From: Ian Lance Taylor Date: Sat, 31 Oct 2015 00:59:47 +0000 (+0000) Subject: runtime: Remove now unnecessary pad field from ParFor. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=af146490bb04205107cb23e301ec7a8ff927b5fc;p=gcc.git runtime: Remove now unnecessary pad field from ParFor. It is not needed due to the removal of the ctx field. Reviewed-on: https://go-review.googlesource.com/16525 From-SVN: r229616 --- diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 5d35b04a15c..c2307e1167e 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -16f69a4007a1903da4055a496882b514e05f45f3 +4b6b496579225cdd897130f6d6fd18ecb100bf99 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/libgo/MERGE b/libgo/MERGE index 260f8cf8e59..af7e452a4d1 100644 --- a/libgo/MERGE +++ b/libgo/MERGE @@ -1,4 +1,4 @@ -883bc6ed0ea815293fe6309d66f967ea60630e87 +bb03defe933c89fee44be675d7aa0fbd893ced30 The first line of this file holds the git revision number of the last merge done from the master library sources. diff --git a/libgo/Makefile.am b/libgo/Makefile.am index ca2280dcecf..91bd3b80bdf 100644 --- a/libgo/Makefile.am +++ b/libgo/Makefile.am @@ -233,12 +233,15 @@ toolexeclibgogodir = $(toolexeclibgodir)/go toolexeclibgogo_DATA = \ go/ast.gox \ go/build.gox \ + go/constant.gox \ go/doc.gox \ go/format.gox \ + go/importer.gox \ go/parser.gox \ go/printer.gox \ go/scanner.gox \ - go/token.gox + go/token.gox \ + go/types.gox toolexeclibgohashdir = $(toolexeclibgodir)/hash @@ -292,7 +295,8 @@ toolexeclibgomath_DATA = \ toolexeclibgomimedir = $(toolexeclibgodir)/mime toolexeclibgomime_DATA = \ - mime/multipart.gox + mime/multipart.gox \ + mime/quotedprintable.gox toolexeclibgonetdir = $(toolexeclibgodir)/net @@ -676,46 +680,74 @@ go_math_files = \ go/math/tanh.go \ go/math/unsafe.go +if LIBGO_IS_OPENBSD +go_mime_type_file = go/mime/type_openbsd.go +else +if LIBGO_IS_FREEBSD +go_mime_type_file = go/mime/type_freebsd.go +else +if LIBGO_IS_DRAGONFLY +go_mime_type_file = go/mime/type_dragonfly.go +else +go_mime_type_file = +endif +endif +endif + go_mime_files = \ + go/mime/encodedword.go \ go/mime/grammar.go \ go/mime/mediatype.go \ go/mime/type.go \ - go/mime/type_unix.go + go/mime/type_unix.go \ + $(go_mime_type_file) if LIBGO_IS_LINUX go_net_cgo_file = go/net/cgo_linux.go go_net_sock_file = go/net/sock_linux.go go_net_sockopt_file = go/net/sockopt_linux.go go_net_sockoptip_file = go/net/sockoptip_linux.go go/net/sockoptip_posix.go +go_net_cgo_sock_file = go/net/cgo_socknew.go +go_net_cgo_res_file = go/net/cgo_resnew.go else if LIBGO_IS_IRIX go_net_cgo_file = go/net/cgo_linux.go go_net_sock_file = go/net/sock_linux.go go_net_sockopt_file = go/net/sockopt_linux.go go_net_sockoptip_file = go/net/sockoptip_linux.go go/net/sockoptip_posix.go +go_net_cgo_sock_file = go/net/cgo_socknew.go +go_net_cgo_res_file = go/net/cgo_resnew.go else if LIBGO_IS_SOLARIS -go_net_cgo_file = go/net/cgo_linux.go +go_net_cgo_file = go/net/cgo_solaris.go go_net_sock_file = go/net/sock_stub.go go_net_sockopt_file = go/net/sockopt_solaris.go go_net_sockoptip_file = go/net/sockoptip_stub.go +go_net_cgo_sock_file = go/net/cgo_socknew.go +go_net_cgo_res_file = go/net/cgo_resnew.go else if LIBGO_IS_FREEBSD go_net_cgo_file = go/net/cgo_bsd.go go_net_sock_file = go/net/sock_bsd.go go_net_sockopt_file = go/net/sockopt_bsd.go go_net_sockoptip_file = go/net/sockoptip_bsd.go go/net/sockoptip_posix.go +go_net_cgo_sock_file = go/net/cgo_sockold.go +go_net_cgo_res_file = go/net/cgo_resold.go else if LIBGO_IS_NETBSD go_net_cgo_file = go/net/cgo_netbsd.go go_net_sock_file = go/net/sock_bsd.go go_net_sockopt_file = go/net/sockopt_bsd.go go_net_sockoptip_file = go/net/sockoptip_bsd.go go/net/sockoptip_posix.go +go_net_cgo_sock_file = go/net/cgo_sockold.go +go_net_cgo_res_file = go/net/cgo_resnew.go else go_net_cgo_file = go/net/cgo_bsd.go go_net_sock_file = go/net/sock_bsd.go go_net_sockopt_file = go/net/sockopt_bsd.go go_net_sockoptip_file = go/net/sockoptip_bsd.go go/net/sockoptip_posix.go +go_net_cgo_sock_file = go/net/cgo_sockold.go +go_net_cgo_res_file = go/net/cgo_resold.go endif endif endif @@ -731,10 +763,14 @@ else if LIBGO_IS_DRAGONFLY go_net_sendfile_file = go/net/sendfile_dragonfly.go else +if LIBGO_IS_SOLARIS +go_net_sendfile_file = go/net/sendfile_solaris.go +else go_net_sendfile_file = go/net/sendfile_stub.go endif endif endif +endif if LIBGO_IS_LINUX go_net_interface_file = go/net/interface_linux.go @@ -775,15 +811,22 @@ endif endif go_net_common_files = \ + go/net/addrselect.go \ $(go_net_cloexec_file) \ + go/net/conf.go \ go/net/dial.go \ go/net/dnsclient.go \ go/net/dnsclient_unix.go \ go/net/dnsconfig_unix.go \ go/net/dnsmsg.go \ go/net/fd_mutex.go \ + go/net/fd_posix.go \ go/net/fd_unix.go \ + go/net/file.go \ go/net/file_unix.go \ + go/net/hook.go \ + go/net/hook_cloexec.go \ + go/net/hook_unix.go \ go/net/hosts.go \ go/net/interface.go \ $(go_net_interface_file) \ @@ -796,6 +839,7 @@ go_net_common_files = \ go/net/lookup_unix.go \ go/net/mac.go \ go/net/net.go \ + go/net/nss.go \ go/net/parse.go \ go/net/pipe.go \ go/net/fd_poll_runtime.go \ @@ -803,7 +847,6 @@ go_net_common_files = \ go/net/port_unix.go \ go/net/race0.go \ $(go_net_sendfile_file) \ - go/net/singleflight.go \ go/net/sock_posix.go \ $(go_net_sock_file) \ go/net/sockopt_posix.go \ @@ -821,6 +864,8 @@ go_net_common_files = \ go_net_files = \ go/net/cgo_unix.go \ $(go_net_cgo_file) \ + $(go_net_cgo_res_file) \ + $(go_net_cgo_sock_file) \ $(go_net_common_files) go_netgo_files = \ @@ -919,6 +964,32 @@ else go_os_pipe_file = go/os/pipe_bsd.go endif +if LIBGO_IS_DARWIN +go_os_sticky_file = go/os/sticky_bsd.go +else +if LIBGO_IS_DRAGONFLY +go_os_sticky_file = go/os/sticky_bsd.go +else +if LIBGO_IS_FREEBSD +go_os_sticky_file = go/os/sticky_bsd.go +else +if LIBGO_IS_NETBSD +go_os_sticky_file = go/os/sticky_bsd.go +else +if LIBGO_IS_OPENBSD +go_os_sticky_file = go/os/sticky_bsd.go +else +if LIBGO_IS_SOLARIS +go_os_sticky_file = go/os/sticky_bsd.go +else +go_os_sticky_file = go/os/sticky_notbsd.go +endif +endif +endif +endif +endif +endif + go_os_files = \ $(go_os_dir_file) \ go/os/dir.go \ @@ -939,6 +1010,7 @@ go_os_files = \ $(go_os_pipe_file) \ go/os/proc.go \ $(go_os_stat_file) \ + $(go_os_sticky_file) \ go/os/str.go \ $(go_os_sys_file) \ $(go_os_cloexec_file) \ @@ -959,6 +1031,7 @@ go_reflect_makefunc_c_file = \ go/reflect/makefunc_ffi_c.c go_regexp_files = \ + go/regexp/backtrack.go \ go/regexp/exec.go \ go/regexp/onepass.go \ go/regexp/regexp.go @@ -974,7 +1047,6 @@ go_runtime_files = \ go/runtime/error.go \ go/runtime/extern.go \ go/runtime/mem.go \ - go/runtime/softfloat64.go \ version.go version.go: s-version; @true @@ -1012,6 +1084,7 @@ go_strconv_files = \ go/strconv/atof.go \ go/strconv/atoi.go \ go/strconv/decimal.go \ + go/strconv/doc.go \ go/strconv/extfloat.go \ go/strconv/ftoa.go \ go/strconv/isprint.go \ @@ -1019,6 +1092,7 @@ go_strconv_files = \ go/strconv/quote.go go_strings_files = \ + go/strings/compare.go \ go/strings/reader.go \ go/strings/replace.go \ go/strings/search.go \ @@ -1048,6 +1122,7 @@ endif endif go_log_syslog_files = \ + go/log/syslog/doc.go \ go/log/syslog/syslog.go \ $(go_syslog_file) go_syslog_c_files = \ @@ -1186,6 +1261,7 @@ crypto_rand_file = endif go_crypto_rand_files = \ + go/crypto/rand/eagain.go \ go/crypto/rand/rand.go \ go/crypto/rand/rand_unix.go \ $(crypto_rand_file) \ @@ -1222,6 +1298,37 @@ go_crypto_tls_files = \ go/crypto/tls/prf.go \ go/crypto/tls/ticket.go \ go/crypto/tls/tls.go + +if LIBGO_IS_LINUX +go_crypto_x509_root_file = go/crypto/x509/root_linux.go +else +if LIBGO_IS_SOLARIS +go_crypto_x509_root_file = go/crypto/x509/root_solaris.go +else +if LIBGO_IS_DRAGONFLY +go_crypto_x509_root_file = go/crypto/x509/root_bsd.go +else +if LIBGO_IS_FREEBSD +go_crypto_x509_root_file = go/crypto/x509/root_bsd.go +else +if LIBGO_IS_NETBSD +go_crypto_x509_root_file = go/crypto/x509/root_bsd.go +else +if LIBGO_IS_OPENBSD +go_crypto_x509_root_file = go/crypto/x509/root_bsd.go +else +if LIBGO_IS_DARWIN +go_crypto_x509_root_file = go/crypto/x509/root_darwin.go +else +go_crypto_x509_root_file = +endif +endif +endif +endif +endif +endif +endif + go_crypto_x509_files = \ go/crypto/x509/cert_pool.go \ go/crypto/x509/pem_decrypt.go \ @@ -1229,6 +1336,7 @@ go_crypto_x509_files = \ go/crypto/x509/pkcs8.go \ go/crypto/x509/root.go \ go/crypto/x509/root_unix.go \ + $(go_crypto_x509_root_file) \ go/crypto/x509/sec1.go \ go/crypto/x509/verify.go \ go/crypto/x509/x509.go @@ -1246,6 +1354,7 @@ go_database_sql_driver_files = \ go_debug_dwarf_files = \ go/debug/dwarf/buf.go \ + go/debug/dwarf/class_string.go \ go/debug/dwarf/const.go \ go/debug/dwarf/entry.go \ go/debug/dwarf/line.go \ @@ -1337,6 +1446,9 @@ go_go_build_files = \ go/go/build/doc.go \ go/go/build/read.go \ go/go/build/syslist.go +go_go_constant_files = \ + go/go/constant/go14.go \ + go/go/constant/value.go go_go_doc_files = \ go/go/doc/comment.go \ go/go/doc/doc.go \ @@ -1347,6 +1459,8 @@ go_go_doc_files = \ go/go/doc/synopsis.go go_go_format_files = \ go/go/format/format.go +go_go_importer_files = \ + go/go/importer/importer.go go_go_parser_files = \ go/go/parser/interface.go \ go/go/parser/parser.go @@ -1360,6 +1474,47 @@ go_go_token_files = \ go/go/token/position.go \ go/go/token/serialize.go \ go/go/token/token.go +go_go_types_files = \ + go/go/types/api.go \ + go/go/types/assignments.go \ + go/go/types/builtins.go \ + go/go/types/call.go \ + go/go/types/check.go \ + go/go/types/conversions.go \ + go/go/types/decl.go \ + go/go/types/errors.go \ + go/go/types/eval.go \ + go/go/types/expr.go \ + go/go/types/exprstring.go \ + go/go/types/go12.go \ + go/go/types/initorder.go \ + go/go/types/labels.go \ + go/go/types/lookup.go \ + go/go/types/methodset.go \ + go/go/types/object.go \ + go/go/types/objset.go \ + go/go/types/operand.go \ + go/go/types/ordering.go \ + go/go/types/package.go \ + go/go/types/predicates.go \ + go/go/types/resolver.go \ + go/go/types/return.go \ + go/go/types/scope.go \ + go/go/types/selection.go \ + go/go/types/stmt.go \ + go/go/types/sizes.go \ + go/go/types/type.go \ + go/go/types/typestring.go \ + go/go/types/typexpr.go \ + go/go/types/universe.go + +go_go_internal_gcimporter_files = \ + go/go/internal/gcimporter/exportdata.go \ + go/go/internal/gcimporter/gcimporter.go +go_go_internal_gccgoimporter_files = \ + go/go/internal/gccgoimporter/gccgoinstallation.go \ + go/go/internal/gccgoimporter/importer.go \ + go/go/internal/gccgoimporter/parser.go go_hash_adler32_files = \ go/hash/adler32/adler32.go @@ -1399,6 +1554,10 @@ go_image_gif_files = \ go/image/gif/reader.go \ go/image/gif/writer.go +go_image_internal_imageutil_files = \ + go/image/internal/imageutil/imageutil.go \ + go/image/internal/imageutil/impl.go + go_image_jpeg_files = \ go/image/jpeg/fdct.go \ go/image/jpeg/huffman.go \ @@ -1416,15 +1575,46 @@ go_index_suffixarray_files = \ go/index/suffixarray/qsufsort.go \ go/index/suffixarray/suffixarray.go +go_internal_format_files = \ + go/internal/format/format.go +go_internal_singleflight_files = \ + go/internal/singleflight/singleflight.go + +if LIBGO_IS_LINUX +internal_syscall_unix_getrandom_file = go/internal/syscall/unix/getrandom_linux.go +else +internal_syscall_unix_getrandom_file = +endif + +go_internal_syscall_unix_files = \ + go/internal/syscall/unix/dummy.go \ + $(internal_syscall_unix_getrandom_file) + +go_internal_testenv_files = \ + go/internal/testenv/testenv.go +go_internal_trace_files = \ + go/internal/trace/goroutines.go \ + go/internal/trace/parser.go + go_io_ioutil_files = \ go/io/ioutil/ioutil.go \ go/io/ioutil/tempfile.go go_math_big_files = \ + go/math/big/accuracy_string.go \ go/math/big/arith.go \ + go/math/big/arith_decl_pure.go \ + go/math/big/decimal.go \ + go/math/big/float.go \ + go/math/big/floatconv.go \ + go/math/big/ftoa.go \ go/math/big/int.go \ + go/math/big/intconv.go \ go/math/big/nat.go \ - go/math/big/rat.go + go/math/big/natconv.go \ + go/math/big/rat.go \ + go/math/big/ratconv.go \ + go/math/big/roundingmode_string.go go_math_cmplx_files = \ go/math/cmplx/abs.go \ go/math/cmplx/asin.go \ @@ -1450,9 +1640,12 @@ go_math_rand_files = \ go_mime_multipart_files = \ go/mime/multipart/formdata.go \ go/mime/multipart/multipart.go \ - go/mime/multipart/quotedprintable.go \ go/mime/multipart/writer.go +go_mime_quotedprintable_files = \ + go/mime/quotedprintable/reader.go \ + go/mime/quotedprintable/writer.go + go_net_http_files = \ go/net/http/client.go \ go/net/http/cookie.go \ @@ -1504,6 +1697,23 @@ go_net_http_httputil_files = \ go_net_http_internal_files = \ go/net/http/internal/chunked.go +if LIBGO_IS_LINUX +go_net_internal_socktest_sys = go/net/internal/socktest/sys_cloexec.go +else +if LIBGO_IS_FREEBSD +go_net_internal_socktest_sys = go/net/internal/socktest/sys_cloexec.go +else +go_net_internal_socktest_sys = +endif +endif + +go_net_internal_socktest_files = \ + go/net/internal/socktest/switch.go \ + go/net/internal/socktest/switch_posix.go \ + go/net/internal/socktest/switch_unix.go \ + go/net/internal/socktest/sys_unix.go \ + $(go_net_internal_socktest_sys) + go_old_regexp_files = \ go/old/regexp/regexp.go go_old_template_files = \ @@ -1514,6 +1724,7 @@ go_old_template_files = \ go_os_exec_files = \ go/os/exec/exec.go \ + go/os/exec/exec_posix.go \ go/os/exec/lp_unix.go go_os_signal_files = \ @@ -1565,6 +1776,7 @@ go_text_template_files = \ go/text/template/exec.go \ go/text/template/funcs.go \ go/text/template/helper.go \ + go/text/template/option.go \ go/text/template/template.go go_text_template_parse_files = \ go/text/template/parse/lex.go \ @@ -1767,6 +1979,12 @@ else syscall_creds_test_file = endif +if LIBGO_IS_LINUX +syscall_exec_test_file = go/syscall/exec_linux_test.go go/syscall/syscall_linux_test.go +else +syscall_exec_test_file = +endif + go_base_syscall_files = \ go/syscall/env_unix.go \ go/syscall/syscall_errno.go \ @@ -1810,21 +2028,14 @@ go_syscall_c_files = \ go_syscall_test_files = \ $(syscall_creds_test_file) \ + $(syscall_exec_test_file) \ + go/syscall/exec_unix_test.go \ go/syscall/export_test.go \ + go/syscall/export_unix_test.go \ go/syscall/mmap_unix_test.go \ go/syscall/syscall_test.go \ go/syscall/syscall_unix_test.go -if LIBGO_IS_LINUX -internal_syscall_getrandom_file = go/internal/syscall/getrandom_linux.go -else -internal_syscall_getrandom_file = -endif - -go_internal_syscall_files = \ - go/internal/syscall/dummy.go \ - $(internal_syscall_getrandom_file) - libcalls.go: s-libcalls; @true s-libcalls: libcalls-list go/syscall/mksyscall.awk $(go_base_syscall_files) rm -f libcalls.go.tmp @@ -1978,12 +2189,17 @@ libgo_go_objs = \ html/template.lo \ go/ast.lo \ go/build.lo \ + go/constant.lo \ go/doc.lo \ go/format.lo \ + go/importer.lo \ + go/internal/gcimporter.lo \ + go/internal/gccgoimporter.lo \ go/parser.lo \ go/printer.lo \ go/scanner.lo \ go/token.lo \ + go/types.lo \ hash/adler32.lo \ hash/crc32.lo \ hash/crc64.lo \ @@ -1999,10 +2215,15 @@ libgo_go_objs = \ image/color/palette.lo \ image/draw.lo \ image/gif.lo \ + image/internal/imageutil.lo \ image/jpeg.lo \ image/png.lo \ index/suffixarray.lo \ - internal/syscall.lo \ + internal/format.lo \ + internal/singleflight.lo \ + internal/syscall/unix.lo \ + internal/testenv.lo \ + internal/trace.lo \ io/ioutil.lo \ log/syslog.lo \ log/syslog/syslog_c.lo \ @@ -2010,7 +2231,9 @@ libgo_go_objs = \ math/cmplx.lo \ math/rand.lo \ mime/multipart.lo \ + mime/quotedprintable.lo \ net/http.lo \ + net/internal/socktest.lo \ net/mail.lo \ net/rpc.lo \ net/smtp.lo \ @@ -2121,11 +2344,11 @@ CHECK = \ $(MKDIR_P) $(@D); \ rm -f $@-testsum $@-testlog; \ if test "$(USE_DEJAGNU)" = "yes"; then \ - $(SHELL) $(srcdir)/testsuite/gotest --dejagnu=yes --basedir=$(srcdir) --srcdir=$(srcdir)/go/$(@D) --pkgpath="$(@D)" --pkgfiles="$(go_$(subst /,_,$(@D))_files)" --testname="$(@D)" --goarch="$(GOARCH)" $(GOTESTFLAGS) $(go_$(subst /,_,$(@D))_test_files); \ + $(SHELL) $(srcdir)/testsuite/gotest --goarch=$(GOARCH) --goos=$(GOOS) --dejagnu=yes --basedir=$(srcdir) --srcdir=$(srcdir)/go/$(@D) --pkgpath="$(@D)" --pkgfiles="$(go_$(subst /,_,$(@D))_files)" --testname="$(@D)" --goarch="$(GOARCH)" $(GOTESTFLAGS) $(go_$(subst /,_,$(@D))_test_files); \ elif test "$(GOBENCH)" != ""; then \ - $(SHELL) $(srcdir)/testsuite/gotest --basedir=$(srcdir) --srcdir=$(srcdir)/go/$(@D) --pkgpath="$(@D)" --pkgfiles="$(go_$(subst /,_,$(@D))_files)" --goarch="$(GOARCH)" --bench="$(GOBENCH)" $(GOTESTFLAGS) $(go_$(subst /,_,$(@D))_test_files); \ + $(SHELL) $(srcdir)/testsuite/gotest --goarch=$(GOARCH) --goos=$(GOOS) --basedir=$(srcdir) --srcdir=$(srcdir)/go/$(@D) --pkgpath="$(@D)" --pkgfiles="$(go_$(subst /,_,$(@D))_files)" --goarch="$(GOARCH)" --bench="$(GOBENCH)" $(GOTESTFLAGS) $(go_$(subst /,_,$(@D))_test_files); \ else \ - if $(SHELL) $(srcdir)/testsuite/gotest --basedir=$(srcdir) --srcdir=$(srcdir)/go/$(@D) --pkgpath="$(@D)" --pkgfiles="$(go_$(subst /,_,$(@D))_files)" --goarch="$(GOARCH)" $(GOTESTFLAGS) $(go_$(subst /,_,$(@D))_test_files) >>$@-testlog 2>&1; then \ + if $(SHELL) $(srcdir)/testsuite/gotest --goarch=$(GOARCH) --goos=$(GOOS) --basedir=$(srcdir) --srcdir=$(srcdir)/go/$(@D) --pkgpath="$(@D)" --pkgfiles="$(go_$(subst /,_,$(@D))_files)" --goarch="$(GOARCH)" $(GOTESTFLAGS) $(go_$(subst /,_,$(@D))_test_files) >>$@-testlog 2>&1; then \ echo "PASS: $(@D)" >> $@-testlog; \ echo "PASS: $(@D)"; \ echo "PASS: $(@D)" > $@-testsum; \ @@ -2910,6 +3133,15 @@ go/build/check: $(CHECK_DEPS) @$(CHECK) .PHONY: go/build/check +@go_include@ go/constant.lo.dep +go/constant.lo.dep: $(go_go_constant_files) + $(BUILDDEPS) +go/constant.lo: $(go_go_constant_files) + $(BUILDPACKAGE) +go/constant/check: $(CHECK_DEPS) + @$(CHECK) +.PHONY: go/constant/check + @go_include@ go/doc.lo.dep go/doc.lo.dep: $(go_go_doc_files) $(BUILDDEPS) @@ -2928,6 +3160,15 @@ go/format/check: $(CHECK_DEPS) @$(CHECK) .PHONY: go/format/check +@go_include@ go/importer.lo.dep +go/importer.lo.dep: $(go_go_importer_files) + $(BUILDDEPS) +go/importer.lo: $(go_go_importer_files) + $(BUILDPACKAGE) +go/importer/check: $(CHECK_DEPS) + @$(CHECK) +.PHONY: go/importer/check + @go_include@ go/parser.lo.dep go/parser.lo.dep: $(go_go_parser_files) $(BUILDDEPS) @@ -2964,6 +3205,33 @@ go/token/check: $(CHECK_DEPS) @$(CHECK) .PHONY: go/token/check +@go_include@ go/types.lo.dep +go/types.lo.dep: $(go_go_types_files) + $(BUILDDEPS) +go/types.lo: $(go_go_types_files) + $(BUILDPACKAGE) +go/types/check: $(CHECK_DEPS) + @$(CHECK) +.PHONY: go/types/check + +@go_include@ go/internal/gcimporter.lo.dep +go/internal/gcimporter.lo.dep: $(go_go_internal_gcimporter_files) + $(BUILDDEPS) +go/internal/gcimporter.lo: $(go_go_internal_gcimporter_files) + $(BUILDPACKAGE) +go/internal/gcimporter/check: $(CHECK_DEPS) + @$(CHECK) +.PHONY: go/internal/gcimporter/check + +@go_include@ go/internal/gccgoimporter.lo.dep +go/internal/gccgoimporter.lo.dep: $(go_go_internal_gccgoimporter_files) + $(BUILDDEPS) +go/internal/gccgoimporter.lo: $(go_go_internal_gccgoimporter_files) + $(BUILDPACKAGE) +go/internal/gccgoimporter/check: $(CHECK_DEPS) + @$(CHECK) +.PHONY: go/internal/gccgoimporter/check + @go_include@ hash/adler32.lo.dep hash/adler32.lo.dep: $(go_hash_adler32_files) $(BUILDDEPS) @@ -3036,6 +3304,15 @@ image/gif/check: $(CHECK_DEPS) @$(CHECK) .PHONY: image/gif/check +@go_include@ image/internal/imageutil.lo.dep +image/internal/imageutil.lo.dep: $(go_image_internal_imageutil_files) + $(BUILDDEPS) +image/internal/imageutil.lo: $(go_image_internal_imageutil_files) + $(BUILDPACKAGE) +image/internal/imageutil/check: $(CHECK_DEPS) + @$(CHECK) +.PHONY: image/internal/imageutil/check + @go_include@ image/jpeg.lo.dep image/jpeg.lo.dep: $(go_image_jpeg_files) $(BUILDDEPS) @@ -3063,6 +3340,51 @@ index/suffixarray/check: $(CHECK_DEPS) @$(CHECK) .PHONY: index/suffixarray/check +@go_include@ internal/format.lo.dep +internal/format.lo.dep: $(go_internal_format_files) + $(BUILDDEPS) +internal/format.lo: $(go_internal_format_files) + $(BUILDPACKAGE) +internal/format/check: $(CHECK_DEPS) + @$(CHECK) +.PHONY: internal/format/check + +@go_include@ internal/singleflight.lo.dep +internal/singleflight.lo.dep: $(go_internal_singleflight_files) + $(BUILDDEPS) +internal/singleflight.lo: $(go_internal_singleflight_files) + $(BUILDPACKAGE) +internal/singleflight/check: $(CHECK_DEPS) + @$(CHECK) +.PHONY: internal/singleflight/check + +@go_include@ internal/syscall/unix.lo.dep +internal/syscall/unix.lo.dep: $(go_internal_syscall_unix_files) + $(BUILDDEPS) +internal/syscall/unix.lo: $(go_internal_syscall_unix_files) + $(BUILDPACKAGE) +internal/syscall/unix/check: $(CHECK_DEPS) + @$(CHECK) +.PHONY: internal/syscall/unix/check + +@go_include@ internal/testenv.lo.dep +internal/testenv.lo.dep: $(go_internal_testenv_files) + $(BUILDDEPS) +internal/testenv.lo: $(go_internal_testenv_files) + $(BUILDPACKAGE) +internal/testenv/check: $(CHECK_DEPS) + @$(CHECK) +.PHONY: internal/testenv/check + +@go_include@ internal/trace.lo.dep +internal/trace.lo.dep: $(go_internal_trace_files) + $(BUILDDEPS) +internal/trace.lo: $(go_internal_trace_files) + $(BUILDPACKAGE) +internal/trace/check: $(CHECK_DEPS) + @$(CHECK) +.PHONY: internal/trace/check + @go_include@ io/ioutil.lo.dep io/ioutil.lo.dep: $(go_io_ioutil_files) $(BUILDDEPS) @@ -3120,6 +3442,15 @@ mime/multipart/check: $(CHECK_DEPS) @$(CHECK) .PHONY: mime/multipart/check +@go_include@ mime/quotedprintable.lo.dep +mime/quotedprintable.lo.dep: $(go_mime_quotedprintable_files) + $(BUILDDEPS) +mime/quotedprintable.lo: $(go_mime_quotedprintable_files) + $(BUILDPACKAGE) +mime/quotedprintable/check: $(CHECK_DEPS) + @$(CHECK) +.PHONY: mime/quotedprintable/check + @go_include@ net/http.lo.dep net/http.lo.dep: $(go_net_http_files) $(BUILDDEPS) @@ -3237,6 +3568,15 @@ net/http/pprof/check: $(CHECK_DEPS) @$(CHECK) .PHONY: net/http/pprof/check +@go_include@ net/internal/socktest.lo.dep +net/internal/socktest.lo.dep: $(go_net_internal_socktest_files) + $(BUILDDEPS) +net/internal/socktest.lo: $(go_net_internal_socktest_files) + $(BUILDPACKAGE) +net/internal/socktest/check: $(CHECK_DEPS) + @$(CHECK) +.PHONY: net/internal/socktest/check + @go_include@ net/rpc/jsonrpc.lo.dep net/rpc/jsonrpc.lo.dep: $(go_net_rpc_jsonrpc_files) $(BUILDDEPS) @@ -3432,15 +3772,6 @@ syscall/check: $(CHECK_DEPS) @$(CHECK) .PHONY: syscall/check -@go_include@ internal/syscall.lo.dep -internal/syscall.lo.dep: $(go_internal_syscall_files) - $(BUILDDEPS) -internal/syscall.lo: $(go_internal_syscall_files) - $(BUILDPACKAGE) -internal/syscall/check: $(CHECK_DEPS) - @$(CHECK) -.PHONY: internal/syscall/check - # How to build a .gox file from a .lo file. BUILDGOX = \ f=`echo $< | sed -e 's/.lo$$/.o/'`; \ @@ -3620,10 +3951,14 @@ go/ast.gox: go/ast.lo $(BUILDGOX) go/build.gox: go/build.lo $(BUILDGOX) +go/constant.gox: go/constant.lo + $(BUILDGOX) go/doc.gox: go/doc.lo $(BUILDGOX) go/format.gox: go/format.lo $(BUILDGOX) +go/importer.gox: go/importer.lo + $(BUILDGOX) go/parser.gox: go/parser.lo $(BUILDGOX) go/printer.gox: go/printer.lo @@ -3632,6 +3967,13 @@ go/scanner.gox: go/scanner.lo $(BUILDGOX) go/token.gox: go/token.lo $(BUILDGOX) +go/types.gox: go/types.lo + $(BUILDGOX) + +go/internal/gcimporter.gox: go/internal/gcimporter.lo + $(BUILDGOX) +go/internal/gccgoimporter.gox: go/internal/gccgoimporter.lo + $(BUILDGOX) hash/adler32.gox: hash/adler32.lo $(BUILDGOX) @@ -3648,6 +3990,8 @@ image/draw.gox: image/draw.lo $(BUILDGOX) image/gif.gox: image/gif.lo $(BUILDGOX) +image/internal/imageutil.gox: image/internal/imageutil.lo + $(BUILDGOX) image/jpeg.gox: image/jpeg.lo $(BUILDGOX) image/png.gox: image/png.lo @@ -3659,6 +4003,17 @@ image/color/palette.gox: image/color/palette.lo index/suffixarray.gox: index/suffixarray.lo $(BUILDGOX) +internal/format.gox: internal/format.lo + $(BUILDGOX) +internal/singleflight.gox: internal/singleflight.lo + $(BUILDGOX) +internal/syscall/unix.gox: internal/syscall/unix.lo + $(BUILDGOX) +internal/testenv.gox: internal/testenv.lo + $(BUILDGOX) +internal/trace.gox: internal/trace.lo + $(BUILDGOX) + io/ioutil.gox: io/ioutil.lo $(BUILDGOX) @@ -3674,6 +4029,8 @@ math/rand.gox: math/rand.lo mime/multipart.gox: mime/multipart.lo $(BUILDGOX) +mime/quotedprintable.gox: mime/quotedprintable.lo + $(BUILDGOX) net/http.gox: net/http.lo $(BUILDGOX) @@ -3704,6 +4061,9 @@ net/http/pprof.gox: net/http/pprof.lo net/http/internal.gox: net/http/internal.lo $(BUILDGOX) +net/internal/socktest.gox: net/internal/socktest.lo + $(BUILDGOX) + net/rpc/jsonrpc.gox: net/rpc/jsonrpc.lo $(BUILDGOX) @@ -3733,9 +4093,6 @@ runtime/pprof.gox: runtime/pprof.lo sync/atomic.gox: sync/atomic.lo $(BUILDGOX) -internal/syscall.gox: internal/syscall.lo - $(BUILDGOX) - text/scanner.gox: text/scanner.lo $(BUILDGOX) text/tabwriter.gox: text/tabwriter.lo @@ -3830,13 +4187,17 @@ TEST_PACKAGES = \ exp/terminal/check \ html/template/check \ go/ast/check \ - $(go_build_check_omitted_since_it_calls_6g) \ + go/build/check \ + go/constant/check \ go/doc/check \ go/format/check \ + go/internal/gcimporter/check \ + go/internal/gccgoimporter/check \ go/parser/check \ go/printer/check \ go/scanner/check \ go/token/check \ + go/types/check \ hash/adler32/check \ hash/crc32/check \ hash/crc64/check \ @@ -3846,12 +4207,15 @@ TEST_PACKAGES = \ image/jpeg/check \ image/png/check \ index/suffixarray/check \ + internal/singleflight/check \ + internal/trace/check \ io/ioutil/check \ log/syslog/check \ math/big/check \ math/cmplx/check \ math/rand/check \ mime/multipart/check \ + mime/quotedprintable/check \ net/http/check \ net/http/cgi/check \ net/http/cookiejar/check \ @@ -3859,6 +4223,7 @@ TEST_PACKAGES = \ net/http/httptest/check \ net/http/httputil/check \ net/http/internal/check \ + net/internal/socktest/check \ net/mail/check \ net/rpc/check \ net/smtp/check \ diff --git a/libgo/Makefile.in b/libgo/Makefile.in index 5d7b8c9b377..9e0e98e5b72 100644 --- a/libgo/Makefile.in +++ b/libgo/Makefile.in @@ -196,16 +196,21 @@ am__DEPENDENCIES_2 = bufio.lo bytes.lo bytes/index.lo crypto.lo \ encoding/binary.lo encoding/csv.lo encoding/gob.lo \ encoding/hex.lo encoding/json.lo encoding/pem.lo \ encoding/xml.lo exp/proxy.lo exp/terminal.lo html/template.lo \ - go/ast.lo go/build.lo go/doc.lo go/format.lo go/parser.lo \ - go/printer.lo go/scanner.lo go/token.lo hash/adler32.lo \ + go/ast.lo go/build.lo go/constant.lo go/doc.lo go/format.lo \ + go/importer.lo go/internal/gcimporter.lo \ + go/internal/gccgoimporter.lo go/parser.lo go/printer.lo \ + go/scanner.lo go/token.lo go/types.lo hash/adler32.lo \ hash/crc32.lo hash/crc64.lo hash/fnv.lo net/http/cgi.lo \ net/http/cookiejar.lo net/http/fcgi.lo net/http/httptest.lo \ net/http/httputil.lo net/http/internal.lo net/http/pprof.lo \ image/color.lo image/color/palette.lo image/draw.lo \ - image/gif.lo image/jpeg.lo image/png.lo index/suffixarray.lo \ - internal/syscall.lo io/ioutil.lo log/syslog.lo \ - log/syslog/syslog_c.lo math/big.lo math/cmplx.lo math/rand.lo \ - mime/multipart.lo net/http.lo net/mail.lo net/rpc.lo \ + image/gif.lo image/internal/imageutil.lo image/jpeg.lo \ + image/png.lo index/suffixarray.lo internal/format.lo \ + internal/singleflight.lo internal/syscall/unix.lo \ + internal/testenv.lo internal/trace.lo io/ioutil.lo \ + log/syslog.lo log/syslog/syslog_c.lo math/big.lo math/cmplx.lo \ + math/rand.lo mime/multipart.lo mime/quotedprintable.lo \ + net/http.lo net/internal/socktest.lo net/mail.lo net/rpc.lo \ net/smtp.lo net/textproto.lo net/url.lo old/regexp.lo \ old/template.lo os/exec.lo $(am__DEPENDENCIES_1) os/signal.lo \ os/user.lo path/filepath.lo regexp/syntax.lo \ @@ -681,12 +686,15 @@ toolexeclibgogodir = $(toolexeclibgodir)/go toolexeclibgogo_DATA = \ go/ast.gox \ go/build.gox \ + go/constant.gox \ go/doc.gox \ go/format.gox \ + go/importer.gox \ go/parser.gox \ go/printer.gox \ go/scanner.gox \ - go/token.gox + go/token.gox \ + go/types.gox toolexeclibgohashdir = $(toolexeclibgodir)/hash toolexeclibgohash_DATA = \ @@ -731,7 +739,8 @@ toolexeclibgomath_DATA = \ toolexeclibgomimedir = $(toolexeclibgodir)/mime toolexeclibgomime_DATA = \ - mime/multipart.gox + mime/multipart.gox \ + mime/quotedprintable.gox toolexeclibgonetdir = $(toolexeclibgodir)/net toolexeclibgonet_DATA = \ @@ -1023,16 +1032,22 @@ go_math_files = \ go/math/tanh.go \ go/math/unsafe.go +@LIBGO_IS_DRAGONFLY_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_OPENBSD_FALSE@go_mime_type_file = +@LIBGO_IS_DRAGONFLY_TRUE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_OPENBSD_FALSE@go_mime_type_file = go/mime/type_dragonfly.go +@LIBGO_IS_FREEBSD_TRUE@@LIBGO_IS_OPENBSD_FALSE@go_mime_type_file = go/mime/type_freebsd.go +@LIBGO_IS_OPENBSD_TRUE@go_mime_type_file = go/mime/type_openbsd.go go_mime_files = \ + go/mime/encodedword.go \ go/mime/grammar.go \ go/mime/mediatype.go \ go/mime/type.go \ - go/mime/type_unix.go + go/mime/type_unix.go \ + $(go_mime_type_file) @LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_cgo_file = go/net/cgo_bsd.go @LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_TRUE@@LIBGO_IS_SOLARIS_FALSE@go_net_cgo_file = go/net/cgo_netbsd.go @LIBGO_IS_FREEBSD_TRUE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_cgo_file = go/net/cgo_bsd.go -@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@go_net_cgo_file = go/net/cgo_linux.go +@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@go_net_cgo_file = go/net/cgo_solaris.go @LIBGO_IS_IRIX_TRUE@@LIBGO_IS_LINUX_FALSE@go_net_cgo_file = go/net/cgo_linux.go @LIBGO_IS_LINUX_TRUE@go_net_cgo_file = go/net/cgo_linux.go @LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_sock_file = go/net/sock_bsd.go @@ -1053,7 +1068,20 @@ go_mime_files = \ @LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@go_net_sockoptip_file = go/net/sockoptip_stub.go @LIBGO_IS_IRIX_TRUE@@LIBGO_IS_LINUX_FALSE@go_net_sockoptip_file = go/net/sockoptip_linux.go go/net/sockoptip_posix.go @LIBGO_IS_LINUX_TRUE@go_net_sockoptip_file = go/net/sockoptip_linux.go go/net/sockoptip_posix.go -@LIBGO_IS_DRAGONFLY_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_LINUX_FALSE@go_net_sendfile_file = go/net/sendfile_stub.go +@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_cgo_sock_file = go/net/cgo_sockold.go +@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_TRUE@@LIBGO_IS_SOLARIS_FALSE@go_net_cgo_sock_file = go/net/cgo_sockold.go +@LIBGO_IS_FREEBSD_TRUE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_cgo_sock_file = go/net/cgo_sockold.go +@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@go_net_cgo_sock_file = go/net/cgo_socknew.go +@LIBGO_IS_IRIX_TRUE@@LIBGO_IS_LINUX_FALSE@go_net_cgo_sock_file = go/net/cgo_socknew.go +@LIBGO_IS_LINUX_TRUE@go_net_cgo_sock_file = go/net/cgo_socknew.go +@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_cgo_res_file = go/net/cgo_resold.go +@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_TRUE@@LIBGO_IS_SOLARIS_FALSE@go_net_cgo_res_file = go/net/cgo_resnew.go +@LIBGO_IS_FREEBSD_TRUE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_cgo_res_file = go/net/cgo_resold.go +@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@go_net_cgo_res_file = go/net/cgo_resnew.go +@LIBGO_IS_IRIX_TRUE@@LIBGO_IS_LINUX_FALSE@go_net_cgo_res_file = go/net/cgo_resnew.go +@LIBGO_IS_LINUX_TRUE@go_net_cgo_res_file = go/net/cgo_resnew.go +@LIBGO_IS_DRAGONFLY_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_net_sendfile_file = go/net/sendfile_stub.go +@LIBGO_IS_DRAGONFLY_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@go_net_sendfile_file = go/net/sendfile_solaris.go @LIBGO_IS_DRAGONFLY_TRUE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_LINUX_FALSE@go_net_sendfile_file = go/net/sendfile_dragonfly.go @LIBGO_IS_FREEBSD_TRUE@@LIBGO_IS_LINUX_FALSE@go_net_sendfile_file = go/net/sendfile_freebsd.go @LIBGO_IS_LINUX_TRUE@go_net_sendfile_file = go/net/sendfile_linux.go @@ -1069,15 +1097,22 @@ go_mime_files = \ @LIBGO_IS_DARWIN_TRUE@@LIBGO_IS_OPENBSD_FALSE@go_net_tcpsockopt_file = go/net/tcpsockopt_darwin.go @LIBGO_IS_OPENBSD_TRUE@go_net_tcpsockopt_file = go/net/tcpsockopt_openbsd.go go_net_common_files = \ + go/net/addrselect.go \ $(go_net_cloexec_file) \ + go/net/conf.go \ go/net/dial.go \ go/net/dnsclient.go \ go/net/dnsclient_unix.go \ go/net/dnsconfig_unix.go \ go/net/dnsmsg.go \ go/net/fd_mutex.go \ + go/net/fd_posix.go \ go/net/fd_unix.go \ + go/net/file.go \ go/net/file_unix.go \ + go/net/hook.go \ + go/net/hook_cloexec.go \ + go/net/hook_unix.go \ go/net/hosts.go \ go/net/interface.go \ $(go_net_interface_file) \ @@ -1090,6 +1125,7 @@ go_net_common_files = \ go/net/lookup_unix.go \ go/net/mac.go \ go/net/net.go \ + go/net/nss.go \ go/net/parse.go \ go/net/pipe.go \ go/net/fd_poll_runtime.go \ @@ -1097,7 +1133,6 @@ go_net_common_files = \ go/net/port_unix.go \ go/net/race0.go \ $(go_net_sendfile_file) \ - go/net/singleflight.go \ go/net/sock_posix.go \ $(go_net_sock_file) \ go/net/sockopt_posix.go \ @@ -1115,6 +1150,8 @@ go_net_common_files = \ go_net_files = \ go/net/cgo_unix.go \ $(go_net_cgo_file) \ + $(go_net_cgo_res_file) \ + $(go_net_cgo_sock_file) \ $(go_net_common_files) go_netgo_files = \ @@ -1147,6 +1184,13 @@ go_netgo_files = \ @LIBGO_IS_LINUX_TRUE@@LIBGO_IS_SOLARIS_FALSE@go_os_stat_file = go/os/stat_atim.go @LIBGO_IS_LINUX_FALSE@go_os_pipe_file = go/os/pipe_bsd.go @LIBGO_IS_LINUX_TRUE@go_os_pipe_file = go/os/pipe_linux.go +@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_DRAGONFLY_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_OPENBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_os_sticky_file = go/os/sticky_notbsd.go +@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_DRAGONFLY_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_OPENBSD_FALSE@@LIBGO_IS_SOLARIS_TRUE@go_os_sticky_file = go/os/sticky_bsd.go +@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_DRAGONFLY_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_OPENBSD_TRUE@go_os_sticky_file = go/os/sticky_bsd.go +@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_DRAGONFLY_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_NETBSD_TRUE@go_os_sticky_file = go/os/sticky_bsd.go +@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_DRAGONFLY_FALSE@@LIBGO_IS_FREEBSD_TRUE@go_os_sticky_file = go/os/sticky_bsd.go +@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_DRAGONFLY_TRUE@go_os_sticky_file = go/os/sticky_bsd.go +@LIBGO_IS_DARWIN_TRUE@go_os_sticky_file = go/os/sticky_bsd.go go_os_files = \ $(go_os_dir_file) \ go/os/dir.go \ @@ -1167,6 +1211,7 @@ go_os_files = \ $(go_os_pipe_file) \ go/os/proc.go \ $(go_os_stat_file) \ + $(go_os_sticky_file) \ go/os/str.go \ $(go_os_sys_file) \ $(go_os_cloexec_file) \ @@ -1188,6 +1233,7 @@ go_reflect_makefunc_c_file = \ go/reflect/makefunc_ffi_c.c go_regexp_files = \ + go/regexp/backtrack.go \ go/regexp/exec.go \ go/regexp/onepass.go \ go/regexp/regexp.go @@ -1203,7 +1249,6 @@ go_runtime_files = \ go/runtime/error.go \ go/runtime/extern.go \ go/runtime/mem.go \ - go/runtime/softfloat64.go \ version.go noinst_DATA = zstdpkglist.go @@ -1216,6 +1261,7 @@ go_strconv_files = \ go/strconv/atof.go \ go/strconv/atoi.go \ go/strconv/decimal.go \ + go/strconv/doc.go \ go/strconv/extfloat.go \ go/strconv/ftoa.go \ go/strconv/isprint.go \ @@ -1223,6 +1269,7 @@ go_strconv_files = \ go/strconv/quote.go go_strings_files = \ + go/strings/compare.go \ go/strings/reader.go \ go/strings/replace.go \ go/strings/search.go \ @@ -1246,6 +1293,7 @@ go_sync_files = \ @LIBGO_IS_IRIX_TRUE@@LIBGO_IS_SOLARIS_FALSE@go_syslog_file = go/log/syslog/syslog_libc.go @LIBGO_IS_SOLARIS_TRUE@go_syslog_file = go/log/syslog/syslog_libc.go go_log_syslog_files = \ + go/log/syslog/doc.go \ go/log/syslog/syslog.go \ $(go_syslog_file) @@ -1375,6 +1423,7 @@ go_crypto_md5_files = \ @LIBGO_IS_LINUX_FALSE@crypto_rand_file = @LIBGO_IS_LINUX_TRUE@crypto_rand_file = go/crypto/rand/rand_linux.go go_crypto_rand_files = \ + go/crypto/rand/eagain.go \ go/crypto/rand/rand.go \ go/crypto/rand/rand_unix.go \ $(crypto_rand_file) \ @@ -1418,6 +1467,14 @@ go_crypto_tls_files = \ go/crypto/tls/ticket.go \ go/crypto/tls/tls.go +@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_DRAGONFLY_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_OPENBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_crypto_x509_root_file = +@LIBGO_IS_DARWIN_TRUE@@LIBGO_IS_DRAGONFLY_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_OPENBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_crypto_x509_root_file = go/crypto/x509/root_darwin.go +@LIBGO_IS_DRAGONFLY_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_OPENBSD_TRUE@@LIBGO_IS_SOLARIS_FALSE@go_crypto_x509_root_file = go/crypto/x509/root_bsd.go +@LIBGO_IS_DRAGONFLY_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_TRUE@@LIBGO_IS_SOLARIS_FALSE@go_crypto_x509_root_file = go/crypto/x509/root_bsd.go +@LIBGO_IS_DRAGONFLY_FALSE@@LIBGO_IS_FREEBSD_TRUE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_crypto_x509_root_file = go/crypto/x509/root_bsd.go +@LIBGO_IS_DRAGONFLY_TRUE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_FALSE@go_crypto_x509_root_file = go/crypto/x509/root_bsd.go +@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_SOLARIS_TRUE@go_crypto_x509_root_file = go/crypto/x509/root_solaris.go +@LIBGO_IS_LINUX_TRUE@go_crypto_x509_root_file = go/crypto/x509/root_linux.go go_crypto_x509_files = \ go/crypto/x509/cert_pool.go \ go/crypto/x509/pem_decrypt.go \ @@ -1425,6 +1482,7 @@ go_crypto_x509_files = \ go/crypto/x509/pkcs8.go \ go/crypto/x509/root.go \ go/crypto/x509/root_unix.go \ + $(go_crypto_x509_root_file) \ go/crypto/x509/sec1.go \ go/crypto/x509/verify.go \ go/crypto/x509/x509.go @@ -1442,6 +1500,7 @@ go_database_sql_driver_files = \ go_debug_dwarf_files = \ go/debug/dwarf/buf.go \ + go/debug/dwarf/class_string.go \ go/debug/dwarf/const.go \ go/debug/dwarf/entry.go \ go/debug/dwarf/line.go \ @@ -1551,6 +1610,10 @@ go_go_build_files = \ go/go/build/read.go \ go/go/build/syslist.go +go_go_constant_files = \ + go/go/constant/go14.go \ + go/go/constant/value.go + go_go_doc_files = \ go/go/doc/comment.go \ go/go/doc/doc.go \ @@ -1563,6 +1626,9 @@ go_go_doc_files = \ go_go_format_files = \ go/go/format/format.go +go_go_importer_files = \ + go/go/importer/importer.go + go_go_parser_files = \ go/go/parser/interface.go \ go/go/parser/parser.go @@ -1580,6 +1646,49 @@ go_go_token_files = \ go/go/token/serialize.go \ go/go/token/token.go +go_go_types_files = \ + go/go/types/api.go \ + go/go/types/assignments.go \ + go/go/types/builtins.go \ + go/go/types/call.go \ + go/go/types/check.go \ + go/go/types/conversions.go \ + go/go/types/decl.go \ + go/go/types/errors.go \ + go/go/types/eval.go \ + go/go/types/expr.go \ + go/go/types/exprstring.go \ + go/go/types/go12.go \ + go/go/types/initorder.go \ + go/go/types/labels.go \ + go/go/types/lookup.go \ + go/go/types/methodset.go \ + go/go/types/object.go \ + go/go/types/objset.go \ + go/go/types/operand.go \ + go/go/types/ordering.go \ + go/go/types/package.go \ + go/go/types/predicates.go \ + go/go/types/resolver.go \ + go/go/types/return.go \ + go/go/types/scope.go \ + go/go/types/selection.go \ + go/go/types/stmt.go \ + go/go/types/sizes.go \ + go/go/types/type.go \ + go/go/types/typestring.go \ + go/go/types/typexpr.go \ + go/go/types/universe.go + +go_go_internal_gcimporter_files = \ + go/go/internal/gcimporter/exportdata.go \ + go/go/internal/gcimporter/gcimporter.go + +go_go_internal_gccgoimporter_files = \ + go/go/internal/gccgoimporter/gccgoinstallation.go \ + go/go/internal/gccgoimporter/importer.go \ + go/go/internal/gccgoimporter/parser.go + go_hash_adler32_files = \ go/hash/adler32/adler32.go @@ -1621,6 +1730,10 @@ go_image_gif_files = \ go/image/gif/reader.go \ go/image/gif/writer.go +go_image_internal_imageutil_files = \ + go/image/internal/imageutil/imageutil.go \ + go/image/internal/imageutil/impl.go + go_image_jpeg_files = \ go/image/jpeg/fdct.go \ go/image/jpeg/huffman.go \ @@ -1638,15 +1751,44 @@ go_index_suffixarray_files = \ go/index/suffixarray/qsufsort.go \ go/index/suffixarray/suffixarray.go +go_internal_format_files = \ + go/internal/format/format.go + +go_internal_singleflight_files = \ + go/internal/singleflight/singleflight.go + +@LIBGO_IS_LINUX_FALSE@internal_syscall_unix_getrandom_file = +@LIBGO_IS_LINUX_TRUE@internal_syscall_unix_getrandom_file = go/internal/syscall/unix/getrandom_linux.go +go_internal_syscall_unix_files = \ + go/internal/syscall/unix/dummy.go \ + $(internal_syscall_unix_getrandom_file) + +go_internal_testenv_files = \ + go/internal/testenv/testenv.go + +go_internal_trace_files = \ + go/internal/trace/goroutines.go \ + go/internal/trace/parser.go + go_io_ioutil_files = \ go/io/ioutil/ioutil.go \ go/io/ioutil/tempfile.go go_math_big_files = \ + go/math/big/accuracy_string.go \ go/math/big/arith.go \ + go/math/big/arith_decl_pure.go \ + go/math/big/decimal.go \ + go/math/big/float.go \ + go/math/big/floatconv.go \ + go/math/big/ftoa.go \ go/math/big/int.go \ + go/math/big/intconv.go \ go/math/big/nat.go \ - go/math/big/rat.go + go/math/big/natconv.go \ + go/math/big/rat.go \ + go/math/big/ratconv.go \ + go/math/big/roundingmode_string.go go_math_cmplx_files = \ go/math/cmplx/abs.go \ @@ -1674,9 +1816,12 @@ go_math_rand_files = \ go_mime_multipart_files = \ go/mime/multipart/formdata.go \ go/mime/multipart/multipart.go \ - go/mime/multipart/quotedprintable.go \ go/mime/multipart/writer.go +go_mime_quotedprintable_files = \ + go/mime/quotedprintable/reader.go \ + go/mime/quotedprintable/writer.go + go_net_http_files = \ go/net/http/client.go \ go/net/http/cookie.go \ @@ -1738,6 +1883,16 @@ go_net_http_httputil_files = \ go_net_http_internal_files = \ go/net/http/internal/chunked.go +@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_LINUX_FALSE@go_net_internal_socktest_sys = +@LIBGO_IS_FREEBSD_TRUE@@LIBGO_IS_LINUX_FALSE@go_net_internal_socktest_sys = go/net/internal/socktest/sys_cloexec.go +@LIBGO_IS_LINUX_TRUE@go_net_internal_socktest_sys = go/net/internal/socktest/sys_cloexec.go +go_net_internal_socktest_files = \ + go/net/internal/socktest/switch.go \ + go/net/internal/socktest/switch_posix.go \ + go/net/internal/socktest/switch_unix.go \ + go/net/internal/socktest/sys_unix.go \ + $(go_net_internal_socktest_sys) + go_old_regexp_files = \ go/old/regexp/regexp.go @@ -1749,6 +1904,7 @@ go_old_template_files = \ go_os_exec_files = \ go/os/exec/exec.go \ + go/os/exec/exec_posix.go \ go/os/exec/lp_unix.go go_os_signal_files = \ @@ -1798,6 +1954,7 @@ go_text_template_files = \ go/text/template/exec.go \ go/text/template/funcs.go \ go/text/template/helper.go \ + go/text/template/option.go \ go/text/template/template.go go_text_template_parse_files = \ @@ -1917,6 +2074,8 @@ go_unicode_utf8_files = \ # Test files. @LIBGO_IS_LINUX_TRUE@syscall_creds_test_file = go/syscall/creds_test.go +@LIBGO_IS_LINUX_FALSE@syscall_exec_test_file = +@LIBGO_IS_LINUX_TRUE@syscall_exec_test_file = go/syscall/exec_linux_test.go go/syscall/syscall_linux_test.go go_base_syscall_files = \ go/syscall/env_unix.go \ go/syscall/syscall_errno.go \ @@ -1961,17 +2120,14 @@ go_syscall_c_files = \ go_syscall_test_files = \ $(syscall_creds_test_file) \ + $(syscall_exec_test_file) \ + go/syscall/exec_unix_test.go \ go/syscall/export_test.go \ + go/syscall/export_unix_test.go \ go/syscall/mmap_unix_test.go \ go/syscall/syscall_test.go \ go/syscall/syscall_unix_test.go -@LIBGO_IS_LINUX_FALSE@internal_syscall_getrandom_file = -@LIBGO_IS_LINUX_TRUE@internal_syscall_getrandom_file = go/internal/syscall/getrandom_linux.go -go_internal_syscall_files = \ - go/internal/syscall/dummy.go \ - $(internal_syscall_getrandom_file) - @LIBGO_IS_LINUX_FALSE@os_lib_inotify_lo = # os_lib_inotify_lo = os/inotify.lo @@ -2064,12 +2220,17 @@ libgo_go_objs = \ html/template.lo \ go/ast.lo \ go/build.lo \ + go/constant.lo \ go/doc.lo \ go/format.lo \ + go/importer.lo \ + go/internal/gcimporter.lo \ + go/internal/gccgoimporter.lo \ go/parser.lo \ go/printer.lo \ go/scanner.lo \ go/token.lo \ + go/types.lo \ hash/adler32.lo \ hash/crc32.lo \ hash/crc64.lo \ @@ -2085,10 +2246,15 @@ libgo_go_objs = \ image/color/palette.lo \ image/draw.lo \ image/gif.lo \ + image/internal/imageutil.lo \ image/jpeg.lo \ image/png.lo \ index/suffixarray.lo \ - internal/syscall.lo \ + internal/format.lo \ + internal/singleflight.lo \ + internal/syscall/unix.lo \ + internal/testenv.lo \ + internal/trace.lo \ io/ioutil.lo \ log/syslog.lo \ log/syslog/syslog_c.lo \ @@ -2096,7 +2262,9 @@ libgo_go_objs = \ math/cmplx.lo \ math/rand.lo \ mime/multipart.lo \ + mime/quotedprintable.lo \ net/http.lo \ + net/internal/socktest.lo \ net/mail.lo \ net/rpc.lo \ net/smtp.lo \ @@ -2203,11 +2371,11 @@ CHECK = \ $(MKDIR_P) $(@D); \ rm -f $@-testsum $@-testlog; \ if test "$(USE_DEJAGNU)" = "yes"; then \ - $(SHELL) $(srcdir)/testsuite/gotest --dejagnu=yes --basedir=$(srcdir) --srcdir=$(srcdir)/go/$(@D) --pkgpath="$(@D)" --pkgfiles="$(go_$(subst /,_,$(@D))_files)" --testname="$(@D)" --goarch="$(GOARCH)" $(GOTESTFLAGS) $(go_$(subst /,_,$(@D))_test_files); \ + $(SHELL) $(srcdir)/testsuite/gotest --goarch=$(GOARCH) --goos=$(GOOS) --dejagnu=yes --basedir=$(srcdir) --srcdir=$(srcdir)/go/$(@D) --pkgpath="$(@D)" --pkgfiles="$(go_$(subst /,_,$(@D))_files)" --testname="$(@D)" --goarch="$(GOARCH)" $(GOTESTFLAGS) $(go_$(subst /,_,$(@D))_test_files); \ elif test "$(GOBENCH)" != ""; then \ - $(SHELL) $(srcdir)/testsuite/gotest --basedir=$(srcdir) --srcdir=$(srcdir)/go/$(@D) --pkgpath="$(@D)" --pkgfiles="$(go_$(subst /,_,$(@D))_files)" --goarch="$(GOARCH)" --bench="$(GOBENCH)" $(GOTESTFLAGS) $(go_$(subst /,_,$(@D))_test_files); \ + $(SHELL) $(srcdir)/testsuite/gotest --goarch=$(GOARCH) --goos=$(GOOS) --basedir=$(srcdir) --srcdir=$(srcdir)/go/$(@D) --pkgpath="$(@D)" --pkgfiles="$(go_$(subst /,_,$(@D))_files)" --goarch="$(GOARCH)" --bench="$(GOBENCH)" $(GOTESTFLAGS) $(go_$(subst /,_,$(@D))_test_files); \ else \ - if $(SHELL) $(srcdir)/testsuite/gotest --basedir=$(srcdir) --srcdir=$(srcdir)/go/$(@D) --pkgpath="$(@D)" --pkgfiles="$(go_$(subst /,_,$(@D))_files)" --goarch="$(GOARCH)" $(GOTESTFLAGS) $(go_$(subst /,_,$(@D))_test_files) >>$@-testlog 2>&1; then \ + if $(SHELL) $(srcdir)/testsuite/gotest --goarch=$(GOARCH) --goos=$(GOOS) --basedir=$(srcdir) --srcdir=$(srcdir)/go/$(@D) --pkgpath="$(@D)" --pkgfiles="$(go_$(subst /,_,$(@D))_files)" --goarch="$(GOARCH)" $(GOTESTFLAGS) $(go_$(subst /,_,$(@D))_test_files) >>$@-testlog 2>&1; then \ echo "PASS: $(@D)" >> $@-testlog; \ echo "PASS: $(@D)"; \ echo "PASS: $(@D)" > $@-testsum; \ @@ -2320,13 +2488,17 @@ TEST_PACKAGES = \ exp/terminal/check \ html/template/check \ go/ast/check \ - $(go_build_check_omitted_since_it_calls_6g) \ + go/build/check \ + go/constant/check \ go/doc/check \ go/format/check \ + go/internal/gcimporter/check \ + go/internal/gccgoimporter/check \ go/parser/check \ go/printer/check \ go/scanner/check \ go/token/check \ + go/types/check \ hash/adler32/check \ hash/crc32/check \ hash/crc64/check \ @@ -2336,12 +2508,15 @@ TEST_PACKAGES = \ image/jpeg/check \ image/png/check \ index/suffixarray/check \ + internal/singleflight/check \ + internal/trace/check \ io/ioutil/check \ log/syslog/check \ math/big/check \ math/cmplx/check \ math/rand/check \ mime/multipart/check \ + mime/quotedprintable/check \ net/http/check \ net/http/cgi/check \ net/http/cookiejar/check \ @@ -2349,6 +2524,7 @@ TEST_PACKAGES = \ net/http/httptest/check \ net/http/httputil/check \ net/http/internal/check \ + net/internal/socktest/check \ net/mail/check \ net/rpc/check \ net/smtp/check \ @@ -5357,6 +5533,15 @@ go/build/check: $(CHECK_DEPS) @$(CHECK) .PHONY: go/build/check +@go_include@ go/constant.lo.dep +go/constant.lo.dep: $(go_go_constant_files) + $(BUILDDEPS) +go/constant.lo: $(go_go_constant_files) + $(BUILDPACKAGE) +go/constant/check: $(CHECK_DEPS) + @$(CHECK) +.PHONY: go/constant/check + @go_include@ go/doc.lo.dep go/doc.lo.dep: $(go_go_doc_files) $(BUILDDEPS) @@ -5375,6 +5560,15 @@ go/format/check: $(CHECK_DEPS) @$(CHECK) .PHONY: go/format/check +@go_include@ go/importer.lo.dep +go/importer.lo.dep: $(go_go_importer_files) + $(BUILDDEPS) +go/importer.lo: $(go_go_importer_files) + $(BUILDPACKAGE) +go/importer/check: $(CHECK_DEPS) + @$(CHECK) +.PHONY: go/importer/check + @go_include@ go/parser.lo.dep go/parser.lo.dep: $(go_go_parser_files) $(BUILDDEPS) @@ -5411,6 +5605,33 @@ go/token/check: $(CHECK_DEPS) @$(CHECK) .PHONY: go/token/check +@go_include@ go/types.lo.dep +go/types.lo.dep: $(go_go_types_files) + $(BUILDDEPS) +go/types.lo: $(go_go_types_files) + $(BUILDPACKAGE) +go/types/check: $(CHECK_DEPS) + @$(CHECK) +.PHONY: go/types/check + +@go_include@ go/internal/gcimporter.lo.dep +go/internal/gcimporter.lo.dep: $(go_go_internal_gcimporter_files) + $(BUILDDEPS) +go/internal/gcimporter.lo: $(go_go_internal_gcimporter_files) + $(BUILDPACKAGE) +go/internal/gcimporter/check: $(CHECK_DEPS) + @$(CHECK) +.PHONY: go/internal/gcimporter/check + +@go_include@ go/internal/gccgoimporter.lo.dep +go/internal/gccgoimporter.lo.dep: $(go_go_internal_gccgoimporter_files) + $(BUILDDEPS) +go/internal/gccgoimporter.lo: $(go_go_internal_gccgoimporter_files) + $(BUILDPACKAGE) +go/internal/gccgoimporter/check: $(CHECK_DEPS) + @$(CHECK) +.PHONY: go/internal/gccgoimporter/check + @go_include@ hash/adler32.lo.dep hash/adler32.lo.dep: $(go_hash_adler32_files) $(BUILDDEPS) @@ -5483,6 +5704,15 @@ image/gif/check: $(CHECK_DEPS) @$(CHECK) .PHONY: image/gif/check +@go_include@ image/internal/imageutil.lo.dep +image/internal/imageutil.lo.dep: $(go_image_internal_imageutil_files) + $(BUILDDEPS) +image/internal/imageutil.lo: $(go_image_internal_imageutil_files) + $(BUILDPACKAGE) +image/internal/imageutil/check: $(CHECK_DEPS) + @$(CHECK) +.PHONY: image/internal/imageutil/check + @go_include@ image/jpeg.lo.dep image/jpeg.lo.dep: $(go_image_jpeg_files) $(BUILDDEPS) @@ -5510,6 +5740,51 @@ index/suffixarray/check: $(CHECK_DEPS) @$(CHECK) .PHONY: index/suffixarray/check +@go_include@ internal/format.lo.dep +internal/format.lo.dep: $(go_internal_format_files) + $(BUILDDEPS) +internal/format.lo: $(go_internal_format_files) + $(BUILDPACKAGE) +internal/format/check: $(CHECK_DEPS) + @$(CHECK) +.PHONY: internal/format/check + +@go_include@ internal/singleflight.lo.dep +internal/singleflight.lo.dep: $(go_internal_singleflight_files) + $(BUILDDEPS) +internal/singleflight.lo: $(go_internal_singleflight_files) + $(BUILDPACKAGE) +internal/singleflight/check: $(CHECK_DEPS) + @$(CHECK) +.PHONY: internal/singleflight/check + +@go_include@ internal/syscall/unix.lo.dep +internal/syscall/unix.lo.dep: $(go_internal_syscall_unix_files) + $(BUILDDEPS) +internal/syscall/unix.lo: $(go_internal_syscall_unix_files) + $(BUILDPACKAGE) +internal/syscall/unix/check: $(CHECK_DEPS) + @$(CHECK) +.PHONY: internal/syscall/unix/check + +@go_include@ internal/testenv.lo.dep +internal/testenv.lo.dep: $(go_internal_testenv_files) + $(BUILDDEPS) +internal/testenv.lo: $(go_internal_testenv_files) + $(BUILDPACKAGE) +internal/testenv/check: $(CHECK_DEPS) + @$(CHECK) +.PHONY: internal/testenv/check + +@go_include@ internal/trace.lo.dep +internal/trace.lo.dep: $(go_internal_trace_files) + $(BUILDDEPS) +internal/trace.lo: $(go_internal_trace_files) + $(BUILDPACKAGE) +internal/trace/check: $(CHECK_DEPS) + @$(CHECK) +.PHONY: internal/trace/check + @go_include@ io/ioutil.lo.dep io/ioutil.lo.dep: $(go_io_ioutil_files) $(BUILDDEPS) @@ -5567,6 +5842,15 @@ mime/multipart/check: $(CHECK_DEPS) @$(CHECK) .PHONY: mime/multipart/check +@go_include@ mime/quotedprintable.lo.dep +mime/quotedprintable.lo.dep: $(go_mime_quotedprintable_files) + $(BUILDDEPS) +mime/quotedprintable.lo: $(go_mime_quotedprintable_files) + $(BUILDPACKAGE) +mime/quotedprintable/check: $(CHECK_DEPS) + @$(CHECK) +.PHONY: mime/quotedprintable/check + @go_include@ net/http.lo.dep net/http.lo.dep: $(go_net_http_files) $(BUILDDEPS) @@ -5684,6 +5968,15 @@ net/http/pprof/check: $(CHECK_DEPS) @$(CHECK) .PHONY: net/http/pprof/check +@go_include@ net/internal/socktest.lo.dep +net/internal/socktest.lo.dep: $(go_net_internal_socktest_files) + $(BUILDDEPS) +net/internal/socktest.lo: $(go_net_internal_socktest_files) + $(BUILDPACKAGE) +net/internal/socktest/check: $(CHECK_DEPS) + @$(CHECK) +.PHONY: net/internal/socktest/check + @go_include@ net/rpc/jsonrpc.lo.dep net/rpc/jsonrpc.lo.dep: $(go_net_rpc_jsonrpc_files) $(BUILDDEPS) @@ -5875,15 +6168,6 @@ syscall/check: $(CHECK_DEPS) @$(CHECK) .PHONY: syscall/check -@go_include@ internal/syscall.lo.dep -internal/syscall.lo.dep: $(go_internal_syscall_files) - $(BUILDDEPS) -internal/syscall.lo: $(go_internal_syscall_files) - $(BUILDPACKAGE) -internal/syscall/check: $(CHECK_DEPS) - @$(CHECK) -.PHONY: internal/syscall/check - bufio.gox: bufio.lo $(BUILDGOX) bytes.gox: bytes.lo @@ -6058,10 +6342,14 @@ go/ast.gox: go/ast.lo $(BUILDGOX) go/build.gox: go/build.lo $(BUILDGOX) +go/constant.gox: go/constant.lo + $(BUILDGOX) go/doc.gox: go/doc.lo $(BUILDGOX) go/format.gox: go/format.lo $(BUILDGOX) +go/importer.gox: go/importer.lo + $(BUILDGOX) go/parser.gox: go/parser.lo $(BUILDGOX) go/printer.gox: go/printer.lo @@ -6070,6 +6358,13 @@ go/scanner.gox: go/scanner.lo $(BUILDGOX) go/token.gox: go/token.lo $(BUILDGOX) +go/types.gox: go/types.lo + $(BUILDGOX) + +go/internal/gcimporter.gox: go/internal/gcimporter.lo + $(BUILDGOX) +go/internal/gccgoimporter.gox: go/internal/gccgoimporter.lo + $(BUILDGOX) hash/adler32.gox: hash/adler32.lo $(BUILDGOX) @@ -6086,6 +6381,8 @@ image/draw.gox: image/draw.lo $(BUILDGOX) image/gif.gox: image/gif.lo $(BUILDGOX) +image/internal/imageutil.gox: image/internal/imageutil.lo + $(BUILDGOX) image/jpeg.gox: image/jpeg.lo $(BUILDGOX) image/png.gox: image/png.lo @@ -6097,6 +6394,17 @@ image/color/palette.gox: image/color/palette.lo index/suffixarray.gox: index/suffixarray.lo $(BUILDGOX) +internal/format.gox: internal/format.lo + $(BUILDGOX) +internal/singleflight.gox: internal/singleflight.lo + $(BUILDGOX) +internal/syscall/unix.gox: internal/syscall/unix.lo + $(BUILDGOX) +internal/testenv.gox: internal/testenv.lo + $(BUILDGOX) +internal/trace.gox: internal/trace.lo + $(BUILDGOX) + io/ioutil.gox: io/ioutil.lo $(BUILDGOX) @@ -6112,6 +6420,8 @@ math/rand.gox: math/rand.lo mime/multipart.gox: mime/multipart.lo $(BUILDGOX) +mime/quotedprintable.gox: mime/quotedprintable.lo + $(BUILDGOX) net/http.gox: net/http.lo $(BUILDGOX) @@ -6142,6 +6452,9 @@ net/http/pprof.gox: net/http/pprof.lo net/http/internal.gox: net/http/internal.lo $(BUILDGOX) +net/internal/socktest.gox: net/internal/socktest.lo + $(BUILDGOX) + net/rpc/jsonrpc.gox: net/rpc/jsonrpc.lo $(BUILDGOX) @@ -6171,9 +6484,6 @@ runtime/pprof.gox: runtime/pprof.lo sync/atomic.gox: sync/atomic.lo $(BUILDGOX) -internal/syscall.gox: internal/syscall.lo - $(BUILDGOX) - text/scanner.gox: text/scanner.lo $(BUILDGOX) text/tabwriter.gox: text/tabwriter.lo diff --git a/libgo/VERSION b/libgo/VERSION index bcab27e8d3e..661b4f92284 100644 --- a/libgo/VERSION +++ b/libgo/VERSION @@ -1 +1 @@ -go1.4.2 \ No newline at end of file +go1.5 \ No newline at end of file diff --git a/libgo/go/archive/tar/common.go b/libgo/go/archive/tar/common.go index e363aa793e0..c31df062f7e 100644 --- a/libgo/go/archive/tar/common.go +++ b/libgo/go/archive/tar/common.go @@ -139,8 +139,8 @@ func (fi headerFileInfo) Mode() (mode os.FileMode) { } switch fi.h.Typeflag { - case TypeLink, TypeSymlink: - // hard link, symbolic link + case TypeSymlink: + // symbolic link mode |= os.ModeSymlink case TypeChar: // character device node @@ -249,6 +249,30 @@ func FileInfoHeader(fi os.FileInfo, link string) (*Header, error) { if fm&os.ModeSticky != 0 { h.Mode |= c_ISVTX } + // If possible, populate additional fields from OS-specific + // FileInfo fields. + if sys, ok := fi.Sys().(*Header); ok { + // This FileInfo came from a Header (not the OS). Use the + // original Header to populate all remaining fields. + h.Uid = sys.Uid + h.Gid = sys.Gid + h.Uname = sys.Uname + h.Gname = sys.Gname + h.AccessTime = sys.AccessTime + h.ChangeTime = sys.ChangeTime + if sys.Xattrs != nil { + h.Xattrs = make(map[string]string) + for k, v := range sys.Xattrs { + h.Xattrs[k] = v + } + } + if sys.Typeflag == TypeLink { + // hard link + h.Typeflag = TypeLink + h.Size = 0 + h.Linkname = sys.Linkname + } + } if sysStat != nil { return h, sysStat(fi, h) } diff --git a/libgo/go/archive/tar/reader.go b/libgo/go/archive/tar/reader.go index a27559d0f04..67daca27a95 100644 --- a/libgo/go/archive/tar/reader.go +++ b/libgo/go/archive/tar/reader.go @@ -85,6 +85,8 @@ const ( func NewReader(r io.Reader) *Reader { return &Reader{r: r} } // Next advances to the next entry in the tar archive. +// +// io.EOF is returned at the end of the input. func (tr *Reader) Next() (*Header, error) { var hdr *Header if tr.err == nil { @@ -108,7 +110,13 @@ func (tr *Reader) Next() (*Header, error) { // We actually read the whole file, // but this skips alignment padding tr.skipUnread() + if tr.err != nil { + return nil, tr.err + } hdr = tr.readHeader() + if hdr == nil { + return nil, tr.err + } mergePAX(hdr, headers) // Check for a PAX format sparse file @@ -331,7 +339,7 @@ func parsePAX(r io.Reader) (map[string]string, error) { } // Parse the first token as a decimal integer. n, err := strconv.ParseInt(string(buf[:sp]), 10, 0) - if err != nil { + if err != nil || n < 5 || int64(len(buf)) < n { return nil, ErrHeader } // Extract everything between the decimal and the n -1 on the @@ -461,6 +469,10 @@ func (tr *Reader) readHeader() *Header { hdr.Uid = int(tr.octal(s.next(8))) hdr.Gid = int(tr.octal(s.next(8))) hdr.Size = tr.octal(s.next(12)) + if hdr.Size < 0 { + tr.err = ErrHeader + return nil + } hdr.ModTime = time.Unix(tr.octal(s.next(12)), 0) s.next(8) // chksum hdr.Typeflag = s.next(1)[0] @@ -785,6 +797,9 @@ func (sfr *sparseFileReader) Read(b []byte) (n int, err error) { // Otherwise, we're at the end of the file return 0, io.EOF } + if sfr.tot < sfr.sp[0].offset { + return 0, io.ErrUnexpectedEOF + } if sfr.pos < sfr.sp[0].offset { // We're in a hole n = sfr.readHole(b, sfr.sp[0].offset) diff --git a/libgo/go/archive/tar/reader_test.go b/libgo/go/archive/tar/reader_test.go index 9601ffe4597..da01f265911 100644 --- a/libgo/go/archive/tar/reader_test.go +++ b/libgo/go/archive/tar/reader_test.go @@ -462,9 +462,14 @@ func TestParsePAXHeader(t *testing.T) { t.Error("Buffer wasn't consumed") } } - badHeader := bytes.NewReader([]byte("3 somelongkey=")) - if _, err := parsePAX(badHeader); err != ErrHeader { - t.Fatal("Unexpected success when parsing bad header") + badHeaderTests := [][]byte{ + []byte("3 somelongkey=\n"), + []byte("50 tooshort=\n"), + } + for _, test := range badHeaderTests { + if _, err := parsePAX(bytes.NewReader(test)); err != ErrHeader { + t.Fatal("Unexpected success when parsing bad header") + } } } @@ -741,3 +746,53 @@ func TestUninitializedRead(t *testing.T) { } } + +// Negative header size should not cause panic. +// Issues 10959 and 10960. +func TestNegativeHdrSize(t *testing.T) { + f, err := os.Open("testdata/neg-size.tar") + if err != nil { + t.Fatal(err) + } + defer f.Close() + r := NewReader(f) + _, err = r.Next() + if err != ErrHeader { + t.Error("want ErrHeader, got", err) + } + io.Copy(ioutil.Discard, r) +} + +// This used to hang in (*sparseFileReader).readHole due to missing +// verification of sparse offsets against file size. +func TestIssue10968(t *testing.T) { + f, err := os.Open("testdata/issue10968.tar") + if err != nil { + t.Fatal(err) + } + defer f.Close() + r := NewReader(f) + _, err = r.Next() + if err != nil { + t.Fatal(err) + } + _, err = io.Copy(ioutil.Discard, r) + if err != io.ErrUnexpectedEOF { + t.Fatalf("expected %q, got %q", io.ErrUnexpectedEOF, err) + } +} + +// Do not panic if there are errors in header blocks after the pax header. +// Issue 11169 +func TestIssue11169(t *testing.T) { + f, err := os.Open("testdata/issue11169.tar") + if err != nil { + t.Fatal(err) + } + defer f.Close() + r := NewReader(f) + _, err = r.Next() + if err == nil { + t.Fatal("Unexpected success") + } +} diff --git a/libgo/go/archive/tar/tar_test.go b/libgo/go/archive/tar/tar_test.go index ed333f3ea4f..d63c072eb9a 100644 --- a/libgo/go/archive/tar/tar_test.go +++ b/libgo/go/archive/tar/tar_test.go @@ -147,17 +147,6 @@ func TestHeaderRoundTrip(t *testing.T) { }, fm: 0644, }, - // hard link. - { - h: &Header{ - Name: "hard.txt", - Mode: 0644 | c_ISLNK, - Size: 0, - ModTime: time.Unix(1360600916, 0), - Typeflag: TypeLink, - }, - fm: 0644 | os.ModeSymlink, - }, // symbolic link. { h: &Header{ @@ -246,6 +235,33 @@ func TestHeaderRoundTrip(t *testing.T) { }, fm: 0600 | os.ModeSticky, }, + // hard link. + { + h: &Header{ + Name: "hard.txt", + Mode: 0644 | c_ISREG, + Size: 0, + Linkname: "file.txt", + ModTime: time.Unix(1360600916, 0), + Typeflag: TypeLink, + }, + fm: 0644, + }, + // More information. + { + h: &Header{ + Name: "info.txt", + Mode: 0600 | c_ISREG, + Size: 0, + Uid: 1000, + Gid: 1000, + ModTime: time.Unix(1360602540, 0), + Uname: "slartibartfast", + Gname: "users", + Typeflag: TypeReg, + }, + fm: 0600, + }, } for i, g := range golden { @@ -268,12 +284,37 @@ func TestHeaderRoundTrip(t *testing.T) { if got, want := h2.Size, g.h.Size; got != want { t.Errorf("i=%d: Size: got %v, want %v", i, got, want) } + if got, want := h2.Uid, g.h.Uid; got != want { + t.Errorf("i=%d: Uid: got %d, want %d", i, got, want) + } + if got, want := h2.Gid, g.h.Gid; got != want { + t.Errorf("i=%d: Gid: got %d, want %d", i, got, want) + } + if got, want := h2.Uname, g.h.Uname; got != want { + t.Errorf("i=%d: Uname: got %q, want %q", i, got, want) + } + if got, want := h2.Gname, g.h.Gname; got != want { + t.Errorf("i=%d: Gname: got %q, want %q", i, got, want) + } + if got, want := h2.Linkname, g.h.Linkname; got != want { + t.Errorf("i=%d: Linkname: got %v, want %v", i, got, want) + } + if got, want := h2.Typeflag, g.h.Typeflag; got != want { + t.Logf("%#v %#v", g.h, fi.Sys()) + t.Errorf("i=%d: Typeflag: got %q, want %q", i, got, want) + } if got, want := h2.Mode, g.h.Mode; got != want { t.Errorf("i=%d: Mode: got %o, want %o", i, got, want) } if got, want := fi.Mode(), g.fm; got != want { t.Errorf("i=%d: fi.Mode: got %o, want %o", i, got, want) } + if got, want := h2.AccessTime, g.h.AccessTime; got != want { + t.Errorf("i=%d: AccessTime: got %v, want %v", i, got, want) + } + if got, want := h2.ChangeTime, g.h.ChangeTime; got != want { + t.Errorf("i=%d: ChangeTime: got %v, want %v", i, got, want) + } if got, want := h2.ModTime, g.h.ModTime; got != want { t.Errorf("i=%d: ModTime: got %v, want %v", i, got, want) } diff --git a/libgo/go/archive/tar/testdata/hardlink.tar b/libgo/go/archive/tar/testdata/hardlink.tar new file mode 100644 index 00000000000..9cd1a26572e Binary files /dev/null and b/libgo/go/archive/tar/testdata/hardlink.tar differ diff --git a/libgo/go/archive/tar/testdata/issue10968.tar b/libgo/go/archive/tar/testdata/issue10968.tar new file mode 100644 index 00000000000..1cc837bcff1 Binary files /dev/null and b/libgo/go/archive/tar/testdata/issue10968.tar differ diff --git a/libgo/go/archive/tar/testdata/issue11169.tar b/libgo/go/archive/tar/testdata/issue11169.tar new file mode 100644 index 00000000000..4d71fa15260 Binary files /dev/null and b/libgo/go/archive/tar/testdata/issue11169.tar differ diff --git a/libgo/go/archive/tar/testdata/neg-size.tar b/libgo/go/archive/tar/testdata/neg-size.tar new file mode 100644 index 00000000000..5deea3d05c4 Binary files /dev/null and b/libgo/go/archive/tar/testdata/neg-size.tar differ diff --git a/libgo/go/archive/tar/writer.go b/libgo/go/archive/tar/writer.go index dafb2cabf37..9dbc01a2ffb 100644 --- a/libgo/go/archive/tar/writer.go +++ b/libgo/go/archive/tar/writer.go @@ -355,7 +355,7 @@ func paxHeader(msg string) string { // hdr.Size bytes are written after WriteHeader. func (tw *Writer) Write(b []byte) (n int, err error) { if tw.closed { - err = ErrWriteTooLong + err = ErrWriteAfterClose return } overwrite := false diff --git a/libgo/go/archive/tar/writer_test.go b/libgo/go/archive/tar/writer_test.go index 5e42e322f9c..fe46a67ce38 100644 --- a/libgo/go/archive/tar/writer_test.go +++ b/libgo/go/archive/tar/writer_test.go @@ -147,6 +147,44 @@ var writerTests = []*writerTest{ }, }, }, + // This file was produced using gnu tar 1.26 + // echo "Slartibartfast" > file.txt + // ln file.txt hard.txt + // tar -b 1 --format=ustar -c -f hardlink.tar file.txt hard.txt + { + file: "testdata/hardlink.tar", + entries: []*writerTestEntry{ + { + header: &Header{ + Name: "file.txt", + Mode: 0644, + Uid: 1000, + Gid: 100, + Size: 15, + ModTime: time.Unix(1425484303, 0), + Typeflag: '0', + Uname: "vbatts", + Gname: "users", + }, + contents: "Slartibartfast\n", + }, + { + header: &Header{ + Name: "hard.txt", + Mode: 0644, + Uid: 1000, + Gid: 100, + Size: 0, + ModTime: time.Unix(1425484303, 0), + Typeflag: '1', + Linkname: "file.txt", + Uname: "vbatts", + Gname: "users", + }, + // no contents + }, + }, + }, } // Render byte array in a two-character hexadecimal string, spaced for easy visual inspection. @@ -489,3 +527,20 @@ func TestValidTypeflagWithPAXHeader(t *testing.T) { } } } + +func TestWriteAfterClose(t *testing.T) { + var buffer bytes.Buffer + tw := NewWriter(&buffer) + + hdr := &Header{ + Name: "small.txt", + Size: 5, + } + if err := tw.WriteHeader(hdr); err != nil { + t.Fatalf("Failed to write header: %s", err) + } + tw.Close() + if _, err := tw.Write([]byte("Kilts")); err != ErrWriteAfterClose { + t.Fatalf("Write: got %v; want ErrWriteAfterClose", err) + } +} diff --git a/libgo/go/archive/zip/reader.go b/libgo/go/archive/zip/reader.go index 8136b840d45..519748bac40 100644 --- a/libgo/go/archive/zip/reader.go +++ b/libgo/go/archive/zip/reader.go @@ -8,6 +8,7 @@ import ( "bufio" "encoding/binary" "errors" + "fmt" "hash" "hash/crc32" "io" @@ -77,6 +78,9 @@ func (z *Reader) init(r io.ReaderAt, size int64) error { if err != nil { return err } + if end.directoryRecords > uint64(size)/fileHeaderLen { + return fmt.Errorf("archive/zip: TOC declares impossible %d files in %d byte zip", end.directoryRecords, size) + } z.r = r z.File = make([]*File, 0, end.directoryRecords) z.Comment = end.comment @@ -146,16 +150,22 @@ func (f *File) Open() (rc io.ReadCloser, err error) { if f.hasDataDescriptor() { desr = io.NewSectionReader(f.zipr, f.headerOffset+bodyOffset+size, dataDescriptorLen) } - rc = &checksumReader{rc, crc32.NewIEEE(), f, desr, nil} + rc = &checksumReader{ + rc: rc, + hash: crc32.NewIEEE(), + f: f, + desr: desr, + } return } type checksumReader struct { - rc io.ReadCloser - hash hash.Hash32 - f *File - desr io.Reader // if non-nil, where to read the data descriptor - err error // sticky error + rc io.ReadCloser + hash hash.Hash32 + nread uint64 // number of bytes read so far + f *File + 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) { @@ -164,13 +174,21 @@ func (r *checksumReader) Read(b []byte) (n int, err error) { } n, err = r.rc.Read(b) r.hash.Write(b[:n]) + r.nread += uint64(n) if err == nil { return } if err == io.EOF { + if r.nread != r.f.UncompressedSize64 { + return 0, io.ErrUnexpectedEOF + } if r.desr != nil { if err1 := readDataDescriptor(r.desr, r.f); err1 != nil { - err = err1 + if err1 == io.EOF { + err = io.ErrUnexpectedEOF + } else { + err = err1 + } } else if r.hash.Sum32() != r.f.CRC32 { err = ErrChecksum } diff --git a/libgo/go/archive/zip/reader_test.go b/libgo/go/archive/zip/reader_test.go index 29d0652dcc1..547dd39048e 100644 --- a/libgo/go/archive/zip/reader_test.go +++ b/libgo/go/archive/zip/reader_test.go @@ -531,3 +531,77 @@ func TestIssue8186(t *testing.T) { } } } + +// Verify we return ErrUnexpectedEOF when length is short. +func TestIssue10957(t *testing.T) { + data := []byte("PK\x03\x040000000PK\x01\x0200000" + + "0000000000000000000\x00" + + "\x00\x00\x00\x00\x00000000000000PK\x01" + + "\x020000000000000000000" + + "00000\v\x00\x00\x00\x00\x00000000000" + + "00000000000000PK\x01\x0200" + + "00000000000000000000" + + "00\v\x00\x00\x00\x00\x00000000000000" + + "00000000000PK\x01\x020000<" + + "0\x00\x0000000000000000\v\x00\v" + + "\x00\x00\x00\x00\x0000000000\x00\x00\x00\x00000" + + "00000000PK\x01\x0200000000" + + "0000000000000000\v\x00\x00\x00" + + "\x00\x0000PK\x05\x06000000\x05\x000000" + + "\v\x00\x00\x00\x00\x00") + z, err := NewReader(bytes.NewReader(data), int64(len(data))) + if err != nil { + t.Fatal(err) + } + for i, f := range z.File { + r, err := f.Open() + if err != nil { + continue + } + if f.UncompressedSize64 < 1e6 { + n, err := io.Copy(ioutil.Discard, r) + if i == 3 && err != io.ErrUnexpectedEOF { + t.Errorf("File[3] error = %v; want io.ErrUnexpectedEOF", err) + } + if err == nil && uint64(n) != f.UncompressedSize64 { + t.Errorf("file %d: bad size: copied=%d; want=%d", i, n, f.UncompressedSize64) + } + } + r.Close() + } +} + +// Verify the number of files is sane. +func TestIssue10956(t *testing.T) { + data := []byte("PK\x06\x06PK\x06\a0000\x00\x00\x00\x00\x00\x00\x00\x00" + + "0000PK\x05\x06000000000000" + + "0000\v\x00000\x00\x00\x00\x00\x00\x00\x000") + _, err := NewReader(bytes.NewReader(data), int64(len(data))) + const want = "TOC declares impossible 3472328296227680304 files in 57 byte" + if err == nil && !strings.Contains(err.Error(), want) { + t.Errorf("error = %v; want %q", err, want) + } +} + +// Verify we return ErrUnexpectedEOF when reading truncated data descriptor. +func TestIssue11146(t *testing.T) { + data := []byte("PK\x03\x040000000000000000" + + "000000\x01\x00\x00\x000\x01\x00\x00\xff\xff0000" + + "0000000000000000PK\x01\x02" + + "0000\b0\b\x00000000000000" + + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x000000PK\x05\x06\x00\x00" + + "\x00\x0000\x01\x0000008\x00\x00\x00\x00\x00") + z, err := NewReader(bytes.NewReader(data), int64(len(data))) + if err != nil { + t.Fatal(err) + } + r, err := z.File[0].Open() + if err != nil { + t.Fatal(err) + } + _, err = ioutil.ReadAll(r) + if err != io.ErrUnexpectedEOF { + t.Errorf("File[0] error = %v; want io.ErrUnexpectedEOF", err) + } + r.Close() +} diff --git a/libgo/go/archive/zip/struct.go b/libgo/go/archive/zip/struct.go index cb28e832423..137d0495fd9 100644 --- a/libgo/go/archive/zip/struct.go +++ b/libgo/go/archive/zip/struct.go @@ -81,8 +81,8 @@ type FileHeader struct { ModifiedTime uint16 // MS-DOS time ModifiedDate uint16 // MS-DOS date CRC32 uint32 - CompressedSize uint32 // deprecated; use CompressedSize64 - UncompressedSize uint32 // deprecated; use UncompressedSize64 + CompressedSize uint32 // Deprecated: Use CompressedSize64 instead. + UncompressedSize uint32 // Deprecated: Use UncompressedSize64 instead. CompressedSize64 uint64 UncompressedSize64 uint64 Extra []byte @@ -233,7 +233,7 @@ func (h *FileHeader) SetMode(mode os.FileMode) { } } -// isZip64 returns true if the file size exceeds the 32 bit limit +// isZip64 reports whether the file size exceeds the 32 bit limit func (fh *FileHeader) isZip64() bool { return fh.CompressedSize64 > uint32max || fh.UncompressedSize64 > uint32max } diff --git a/libgo/go/archive/zip/writer.go b/libgo/go/archive/zip/writer.go index 170beec0eec..3be2b5fdb2f 100644 --- a/libgo/go/archive/zip/writer.go +++ b/libgo/go/archive/zip/writer.go @@ -34,6 +34,17 @@ func NewWriter(w io.Writer) *Writer { return &Writer{cw: &countWriter{w: bufio.NewWriter(w)}} } +// SetOffset sets the offset of the beginning of the zip data within the +// underlying writer. It should be used when the zip data is appended to an +// existing file, such as a binary executable. +// It must be called before any data is written. +func (w *Writer) SetOffset(n int64) { + if w.cw.count != 0 { + panic("zip: SetOffset called after data was written") + } + w.cw.count = n +} + // Flush flushes any buffered data to the underlying writer. // Calling Flush is not normally necessary; calling Close is sufficient. func (w *Writer) Flush() error { @@ -122,15 +133,15 @@ func (w *Writer) Close() error { // zip64 end of central directory record b.uint32(directory64EndSignature) - b.uint64(directory64EndLen) - b.uint16(zipVersion45) // version made by - b.uint16(zipVersion45) // version needed to extract - b.uint32(0) // number of this disk - b.uint32(0) // number of the disk with the start of the central directory - b.uint64(records) // total number of entries in the central directory on this disk - b.uint64(records) // total number of entries in the central directory - b.uint64(size) // size of the central directory - b.uint64(offset) // offset of start of central directory with respect to the starting disk number + b.uint64(directory64EndLen - 12) // length minus signature (uint32) and length fields (uint64) + b.uint16(zipVersion45) // version made by + b.uint16(zipVersion45) // version needed to extract + b.uint32(0) // number of this disk + b.uint32(0) // number of the disk with the start of the central directory + b.uint64(records) // total number of entries in the central directory on this disk + b.uint64(records) // total number of entries in the central directory + b.uint64(size) // size of the central directory + b.uint64(offset) // offset of start of central directory with respect to the starting disk number // zip64 end of central directory locator b.uint32(directory64LocSignature) @@ -184,14 +195,20 @@ func (w *Writer) Create(name string) (io.Writer, error) { // CreateHeader adds a file to the zip file using the provided FileHeader // for the file metadata. // It returns a Writer to which the file contents should be written. +// // The file's contents must be written to the io.Writer before the next -// call to Create, CreateHeader, or Close. +// call to Create, CreateHeader, or Close. The provided FileHeader fh +// must not be modified after a call to CreateHeader. func (w *Writer) CreateHeader(fh *FileHeader) (io.Writer, error) { if w.last != nil && !w.last.closed { if err := w.last.close(); err != nil { return nil, err } } + if len(w.dir) > 0 && w.dir[len(w.dir)-1].FileHeader == fh { + // See https://golang.org/issue/11144 confusion. + return nil, errors.New("archive/zip: invalid duplicate FileHeader") + } fh.Flags |= 0x8 // we will write a data descriptor diff --git a/libgo/go/archive/zip/writer_test.go b/libgo/go/archive/zip/writer_test.go index 184a7d96a7f..01b63f2358d 100644 --- a/libgo/go/archive/zip/writer_test.go +++ b/libgo/go/archive/zip/writer_test.go @@ -87,6 +87,41 @@ func TestWriter(t *testing.T) { } } +func TestWriterOffset(t *testing.T) { + largeData := make([]byte, 1<<17) + for i := range largeData { + largeData[i] = byte(rand.Int()) + } + writeTests[1].Data = largeData + defer func() { + writeTests[1].Data = nil + }() + + // write a zip file + buf := new(bytes.Buffer) + existingData := []byte{1, 2, 3, 1, 2, 3, 1, 2, 3} + n, _ := buf.Write(existingData) + w := NewWriter(buf) + w.SetOffset(int64(n)) + + for _, wt := range writeTests { + testCreate(t, w, &wt) + } + + if err := w.Close(); err != nil { + t.Fatal(err) + } + + // read it back + r, err := NewReader(bytes.NewReader(buf.Bytes()), int64(buf.Len())) + if err != nil { + t.Fatal(err) + } + for i, wt := range writeTests { + testReadFile(t, r.File[i], &wt) + } +} + func TestWriterFlush(t *testing.T) { var buf bytes.Buffer w := NewWriter(struct{ io.Writer }{&buf}) diff --git a/libgo/go/archive/zip/zip_test.go b/libgo/go/archive/zip/zip_test.go index 32a16a79efb..f00ff47d37e 100644 --- a/libgo/go/archive/zip/zip_test.go +++ b/libgo/go/archive/zip/zip_test.go @@ -229,10 +229,11 @@ func TestZip64(t *testing.T) { t.Skip("slow test; skipping") } const size = 1 << 32 // before the "END\n" part - testZip64(t, size) + buf := testZip64(t, size) + testZip64DirectoryRecordLength(buf, t) } -func testZip64(t testing.TB, size int64) { +func testZip64(t testing.TB, size int64) *rleBuffer { const chunkSize = 1024 chunks := int(size / chunkSize) // write 2^32 bytes plus "END\n" to a zip file @@ -302,6 +303,37 @@ func testZip64(t testing.TB, size int64) { if got, want := f0.UncompressedSize64, uint64(size)+uint64(len(end)); got != want { t.Errorf("UncompressedSize64 %d, want %d", got, want) } + + return buf +} + +// Issue 9857 +func testZip64DirectoryRecordLength(buf *rleBuffer, t *testing.T) { + d := make([]byte, 1024) + if _, err := buf.ReadAt(d, buf.Size()-int64(len(d))); err != nil { + t.Fatal("read:", err) + } + + sigOff := findSignatureInBlock(d) + dirOff, err := findDirectory64End(buf, buf.Size()-int64(len(d))+int64(sigOff)) + if err != nil { + t.Fatal("findDirectory64End:", err) + } + + d = make([]byte, directory64EndLen) + if _, err := buf.ReadAt(d, dirOff); err != nil { + t.Fatal("read:", err) + } + + b := readBuf(d) + if sig := b.uint32(); sig != directory64EndSignature { + t.Fatalf("Expected directory64EndSignature (%d), got %d", directory64EndSignature, sig) + } + + size := b.uint64() + if size != directory64EndLen-12 { + t.Fatalf("Expected length of %d, got %d", directory64EndLen-12, size) + } } func testInvalidHeader(h *FileHeader, t *testing.T) { diff --git a/libgo/go/bufio/bufio.go b/libgo/go/bufio/bufio.go index d3c68fe6fe5..3bbb933df35 100644 --- a/libgo/go/bufio/bufio.go +++ b/libgo/go/bufio/bufio.go @@ -144,6 +144,39 @@ func (b *Reader) Peek(n int) ([]byte, error) { return b.buf[b.r : b.r+n], err } +// Discard skips the next n bytes, returning the number of bytes discarded. +// +// If Discard skips fewer than n bytes, it also returns an error. +// If 0 <= n <= b.Buffered(), Discard is guaranteed to succeed without +// reading from the underlying io.Reader. +func (b *Reader) Discard(n int) (discarded int, err error) { + if n < 0 { + return 0, ErrNegativeCount + } + if n == 0 { + return + } + remain := n + for { + skip := b.Buffered() + if skip == 0 { + b.fill() + skip = b.Buffered() + } + if skip > remain { + skip = remain + } + b.r += skip + remain -= skip + if remain == 0 { + return n, nil + } + if b.err != nil { + return n - remain, b.readErr() + } + } +} + // Read reads data into p. // It returns the number of bytes read into p. // It calls Read at most once on the underlying Reader, @@ -367,7 +400,6 @@ func (b *Reader) ReadBytes(delim byte) (line []byte, err error) { // accumulating full buffers. var frag []byte var full [][]byte - err = nil for { var e error diff --git a/libgo/go/bufio/bufio_test.go b/libgo/go/bufio/bufio_test.go index 550dac9173f..666c44e15a9 100644 --- a/libgo/go/bufio/bufio_test.go +++ b/libgo/go/bufio/bufio_test.go @@ -1268,6 +1268,135 @@ func TestWriterReset(t *testing.T) { } } +func TestReaderDiscard(t *testing.T) { + tests := []struct { + name string + r io.Reader + bufSize int // 0 means 16 + peekSize int + + n int // input to Discard + + want int // from Discard + wantErr error // from Discard + + wantBuffered int + }{ + { + name: "normal case", + r: strings.NewReader("abcdefghijklmnopqrstuvwxyz"), + peekSize: 16, + n: 6, + want: 6, + wantBuffered: 10, + }, + { + name: "discard causing read", + r: strings.NewReader("abcdefghijklmnopqrstuvwxyz"), + n: 6, + want: 6, + wantBuffered: 10, + }, + { + name: "discard all without peek", + r: strings.NewReader("abcdefghijklmnopqrstuvwxyz"), + n: 26, + want: 26, + wantBuffered: 0, + }, + { + name: "discard more than end", + r: strings.NewReader("abcdefghijklmnopqrstuvwxyz"), + n: 27, + want: 26, + wantErr: io.EOF, + wantBuffered: 0, + }, + // Any error from filling shouldn't show up until we + // get past the valid bytes. Here we return we return 5 valid bytes at the same time + // as an error, but test that we don't see the error from Discard. + { + name: "fill error, discard less", + r: newScriptedReader(func(p []byte) (n int, err error) { + if len(p) < 5 { + panic("unexpected small read") + } + return 5, errors.New("5-then-error") + }), + n: 4, + want: 4, + wantErr: nil, + wantBuffered: 1, + }, + { + name: "fill error, discard equal", + r: newScriptedReader(func(p []byte) (n int, err error) { + if len(p) < 5 { + panic("unexpected small read") + } + return 5, errors.New("5-then-error") + }), + n: 5, + want: 5, + wantErr: nil, + wantBuffered: 0, + }, + { + name: "fill error, discard more", + r: newScriptedReader(func(p []byte) (n int, err error) { + if len(p) < 5 { + panic("unexpected small read") + } + return 5, errors.New("5-then-error") + }), + n: 6, + want: 5, + wantErr: errors.New("5-then-error"), + wantBuffered: 0, + }, + // Discard of 0 shouldn't cause a read: + { + name: "discard zero", + r: newScriptedReader(), // will panic on Read + n: 0, + want: 0, + wantErr: nil, + wantBuffered: 0, + }, + { + name: "discard negative", + r: newScriptedReader(), // will panic on Read + n: -1, + want: 0, + wantErr: ErrNegativeCount, + wantBuffered: 0, + }, + } + for _, tt := range tests { + br := NewReaderSize(tt.r, tt.bufSize) + if tt.peekSize > 0 { + peekBuf, err := br.Peek(tt.peekSize) + if err != nil { + t.Errorf("%s: Peek(%d): %v", tt.name, tt.peekSize, err) + continue + } + if len(peekBuf) != tt.peekSize { + t.Errorf("%s: len(Peek(%d)) = %v; want %v", tt.name, tt.peekSize, len(peekBuf), tt.peekSize) + continue + } + } + discarded, err := br.Discard(tt.n) + if ge, we := fmt.Sprint(err), fmt.Sprint(tt.wantErr); discarded != tt.want || ge != we { + t.Errorf("%s: Discard(%d) = (%v, %v); want (%v, %v)", tt.name, tt.n, discarded, ge, tt.want, we) + continue + } + if bn := br.Buffered(); bn != tt.wantBuffered { + t.Errorf("%s: after Discard, Buffered = %d; want %d", tt.name, bn, tt.wantBuffered) + } + } + +} + // An onlyReader only implements io.Reader, no matter what other methods the underlying implementation may have. type onlyReader struct { io.Reader @@ -1278,6 +1407,23 @@ type onlyWriter struct { io.Writer } +// A scriptedReader is an io.Reader that executes its steps sequentially. +type scriptedReader []func(p []byte) (n int, err error) + +func (sr *scriptedReader) Read(p []byte) (n int, err error) { + if len(*sr) == 0 { + panic("too many Read calls on scripted Reader. No steps remain.") + } + step := (*sr)[0] + *sr = (*sr)[1:] + return step(p) +} + +func newScriptedReader(steps ...func(p []byte) (n int, err error)) io.Reader { + sr := scriptedReader(steps) + return &sr +} + func BenchmarkReaderCopyOptimal(b *testing.B) { // Optimal case is where the underlying reader implements io.WriterTo srcBuf := bytes.NewBuffer(make([]byte, 8192)) diff --git a/libgo/go/bufio/scan.go b/libgo/go/bufio/scan.go index 364d1596139..7a349fa8fab 100644 --- a/libgo/go/bufio/scan.go +++ b/libgo/go/bufio/scan.go @@ -109,7 +109,7 @@ func (s *Scanner) Text() string { // After Scan returns false, the Err method will return any error that // occurred during scanning, except that if it was io.EOF, Err // will return nil. -// Split panics if the split function returns 100 empty tokens without +// Scan panics if the split function returns 100 empty tokens without // advancing the input. This is a common error mode for scanners. func (s *Scanner) Scan() bool { // Loop until we have a token. diff --git a/libgo/go/builtin/builtin.go b/libgo/go/builtin/builtin.go index 51550a459cb..d63ad22c32d 100644 --- a/libgo/go/builtin/builtin.go +++ b/libgo/go/builtin/builtin.go @@ -236,14 +236,14 @@ func panic(v interface{}) // panicking. func recover() interface{} -// The print built-in function formats its arguments in an implementation- -// specific way and writes the result to standard error. +// The print built-in function formats its arguments in an +// implementation-specific way and writes the result to standard error. // Print is useful for bootstrapping and debugging; it is not guaranteed // to stay in the language. func print(args ...Type) -// The println built-in function formats its arguments in an implementation- -// specific way and writes the result to standard error. +// The println built-in function formats its arguments in an +// implementation-specific way and writes the result to standard error. // Spaces are always added between arguments and a newline is appended. // Println is useful for bootstrapping and debugging; it is not guaranteed // to stay in the language. diff --git a/libgo/go/bytes/buffer.go b/libgo/go/bytes/buffer.go index 46ca1d5ad3f..4db93867d9a 100644 --- a/libgo/go/bytes/buffer.go +++ b/libgo/go/bytes/buffer.go @@ -56,6 +56,10 @@ func (b *Buffer) String() string { // b.Len() == len(b.Bytes()). func (b *Buffer) Len() int { return len(b.buf) - b.off } +// Cap returns the capacity of the buffer's underlying byte slice, that is, the +// total space allocated for the buffer's data. +func (b *Buffer) Cap() int { return cap(b.buf) } + // Truncate discards all but the first n unread bytes from the buffer. // It panics if n is negative or greater than the length of the buffer. func (b *Buffer) Truncate(n int) { diff --git a/libgo/go/bytes/buffer_test.go b/libgo/go/bytes/buffer_test.go index 75145b05e92..7de17ae47e2 100644 --- a/libgo/go/bytes/buffer_test.go +++ b/libgo/go/bytes/buffer_test.go @@ -231,6 +231,23 @@ func TestMixedReadsAndWrites(t *testing.T) { empty(t, "TestMixedReadsAndWrites (2)", &buf, s, make([]byte, buf.Len())) } +func TestCapWithPreallocatedSlice(t *testing.T) { + buf := NewBuffer(make([]byte, 10)) + n := buf.Cap() + if n != 10 { + t.Errorf("expected 10, got %d", n) + } +} + +func TestCapWithSliceAndWrittenData(t *testing.T) { + buf := NewBuffer(make([]byte, 0, 10)) + buf.Write([]byte("test")) + n := buf.Cap() + if n != 10 { + t.Errorf("expected 10, got %d", n) + } +} + func TestNil(t *testing.T) { var b *Buffer if b.String() != "" { diff --git a/libgo/go/bytes/bytes.go b/libgo/go/bytes/bytes.go index 7634707b3cb..b86824087e5 100644 --- a/libgo/go/bytes/bytes.go +++ b/libgo/go/bytes/bytes.go @@ -23,7 +23,7 @@ func equalPortable(a, b []byte) bool { return true } -// explode splits s into a slice of UTF-8 sequences, one per Unicode character (still slices of bytes), +// explode splits s into a slice of UTF-8 sequences, one per Unicode code point (still slices of bytes), // up to a maximum of n byte slices. Invalid UTF-8 sequences are chopped into individual bytes. func explode(s []byte, n int) [][]byte { if n <= 0 { @@ -47,6 +47,7 @@ func explode(s []byte, n int) [][]byte { } // Count counts the number of non-overlapping instances of sep in s. +// If sep is an empty slice, Count returns 1 + the number of Unicode code points in s. func Count(s, sep []byte) int { n := len(sep) if n == 0 { @@ -137,6 +138,16 @@ func LastIndex(s, sep []byte) int { return -1 } +// LastIndexByte returns the index of the last instance of c in s, or -1 if c is not present in s. +func LastIndexByte(s []byte, c byte) int { + for i := len(s) - 1; i >= 0; i-- { + if s[i] == c { + return i + } + } + return -1 +} + // IndexRune interprets s as a sequence of UTF-8-encoded Unicode code points. // It returns the byte index of the first occurrence in s of the given rune. // It returns -1 if rune is not present in s. @@ -442,7 +453,7 @@ func isSeparator(r rune) bool { // Title returns a copy of s with all Unicode letters that begin words // mapped to their title case. // -// BUG: The rule Title uses for word boundaries does not handle Unicode punctuation properly. +// BUG(rsc): The rule Title uses for word boundaries does not handle Unicode punctuation properly. func Title(s []byte) []byte { // Use a closure here to remember state. // Hackish but effective. Depends on Map scanning in order and calling diff --git a/libgo/go/bytes/bytes_decl.go b/libgo/go/bytes/bytes_decl.go index 617d7489a6a..b453f21aa43 100644 --- a/libgo/go/bytes/bytes_decl.go +++ b/libgo/go/bytes/bytes_decl.go @@ -21,4 +21,4 @@ func Equal(a, b []byte) bool // ../runtime/asm_$GOARCH.s // Compare returns an integer comparing two byte slices lexicographically. // The result will be 0 if a==b, -1 if a < b, and +1 if a > b. // A nil argument is equivalent to an empty slice. -func Compare(a, b []byte) int // ../runtime/noasm_arm.goc or ../runtime/asm_{386,amd64}.s +func Compare(a, b []byte) int // ../runtime/noasm.go or ../runtime/asm_{386,amd64}.s diff --git a/libgo/go/bytes/bytes_test.go b/libgo/go/bytes/bytes_test.go index 980c41d754d..6245e481805 100644 --- a/libgo/go/bytes/bytes_test.go +++ b/libgo/go/bytes/bytes_test.go @@ -265,6 +265,23 @@ func TestIndexByte(t *testing.T) { } } +func TestLastIndexByte(t *testing.T) { + testCases := []BinOpTest{ + {"", "q", -1}, + {"abcdef", "q", -1}, + {"abcdefabcdef", "a", len("abcdef")}, // something in the middle + {"abcdefabcdef", "f", len("abcdefabcde")}, // last byte + {"zabcdefabcdef", "z", 0}, // first byte + {"a☺b☻c☹d", "b", len("a☺")}, // non-ascii + } + for _, test := range testCases { + actual := LastIndexByte([]byte(test.a), test.b[0]) + if actual != test.i { + t.Errorf("LastIndexByte(%q,%c) = %v; want %v", test.a, test.b[0], actual, test.i) + } + } +} + // test a larger buffer with different sizes and alignments func TestIndexByteBig(t *testing.T) { var n = 1024 diff --git a/libgo/go/bytes/compare_test.go b/libgo/go/bytes/compare_test.go index 63522374ee0..f2d81d5310c 100644 --- a/libgo/go/bytes/compare_test.go +++ b/libgo/go/bytes/compare_test.go @@ -17,6 +17,8 @@ var compareTests = []struct { {[]byte("a"), []byte(""), 1}, {[]byte(""), []byte("a"), -1}, {[]byte("abc"), []byte("abc"), 0}, + {[]byte("abd"), []byte("abc"), 1}, + {[]byte("abc"), []byte("abd"), -1}, {[]byte("ab"), []byte("abc"), -1}, {[]byte("abc"), []byte("ab"), 1}, {[]byte("x"), []byte("ab"), 1}, @@ -27,6 +29,7 @@ var compareTests = []struct { {[]byte("abcdefgh"), []byte("abcdefgh"), 0}, {[]byte("abcdefghi"), []byte("abcdefghi"), 0}, {[]byte("abcdefghi"), []byte("abcdefghj"), -1}, + {[]byte("abcdefghj"), []byte("abcdefghi"), 1}, // nil tests {nil, nil, 0}, {[]byte(""), nil, 0}, diff --git a/libgo/go/bytes/export_test.go b/libgo/go/bytes/export_test.go index 3b915d5ead8..f61523e60bb 100644 --- a/libgo/go/bytes/export_test.go +++ b/libgo/go/bytes/export_test.go @@ -7,7 +7,3 @@ package bytes // Export func for testing var IndexBytePortable = indexBytePortable var EqualPortable = equalPortable - -func (b *Buffer) Cap() int { - return cap(b.buf) -} diff --git a/libgo/go/bytes/reader.go b/libgo/go/bytes/reader.go index d2d40fa7ca1..b89d1548f1b 100644 --- a/libgo/go/bytes/reader.go +++ b/libgo/go/bytes/reader.go @@ -29,6 +29,12 @@ func (r *Reader) Len() int { return int(int64(len(r.s)) - r.i) } +// Size returns the original length of the underlying byte slice. +// Size is the number of bytes available for reading via ReadAt. +// The returned value is always the same and is not affected by calls +// to any other method. +func (r *Reader) Size() int64 { return int64(len(r.s)) } + func (r *Reader) Read(b []byte) (n int, err error) { if len(b) == 0 { return 0, nil diff --git a/libgo/go/bytes/reader_test.go b/libgo/go/bytes/reader_test.go index d3dce53499e..b929a282609 100644 --- a/libgo/go/bytes/reader_test.go +++ b/libgo/go/bytes/reader_test.go @@ -244,3 +244,15 @@ func TestReaderCopyNothing(t *testing.T) { t.Errorf("behavior differs: with = %#v; without: %#v", with, withOut) } } + +// tests that Len is affected by reads, but Size is not. +func TestReaderLenSize(t *testing.T) { + r := NewReader([]byte("abc")) + io.CopyN(ioutil.Discard, r, 1) + if r.Len() != 2 { + t.Errorf("Len = %d; want 2", r.Len()) + } + if r.Size() != 3 { + t.Errorf("Size = %d; want 3", r.Size()) + } +} diff --git a/libgo/go/cmd/cgo/ast.go b/libgo/go/cmd/cgo/ast.go index 10e2278a1d6..8bbd1cc52e6 100644 --- a/libgo/go/cmd/cgo/ast.go +++ b/libgo/go/cmd/cgo/ast.go @@ -235,9 +235,17 @@ func (f *File) saveExport(x interface{}, context string) { error_(c.Pos(), "export comment has wrong name %q, want %q", name, n.Name.Name) } + doc := "" + for _, c1 := range n.Doc.List { + if c1 != c { + doc += c1.Text + "\n" + } + } + f.ExpFunc = append(f.ExpFunc, &ExpFunc{ Func: n, ExpName: name, + Doc: doc, }) break } diff --git a/libgo/go/cmd/cgo/doc.go b/libgo/go/cmd/cgo/doc.go index 6179c7afd19..b2a5428f3f4 100644 --- a/libgo/go/cmd/cgo/doc.go +++ b/libgo/go/cmd/cgo/doc.go @@ -20,16 +20,23 @@ the C parts of the package. For example: // #include import "C" +The preamble may contain any C code, including function and variable +declarations and definitions. These may then be referred to from Go +code as though they were defined in the package "C". All names +declared in the preamble may be used, even if they start with a +lower-case letter. Exception: static variables in the preamble may +not be referenced from Go code; static functions are permitted. + See $GOROOT/misc/cgo/stdio and $GOROOT/misc/cgo/gmp for examples. See "C? Go? Cgo!" for an introduction to using cgo: -http://golang.org/doc/articles/c_go_cgo.html. +https://golang.org/doc/articles/c_go_cgo.html. CFLAGS, CPPFLAGS, CXXFLAGS and LDFLAGS may be defined with pseudo #cgo directives within these comments to tweak the behavior of the C or C++ compiler. Values defined in multiple directives are concatenated together. The directive can include a list of build constraints limiting its effect to systems satisfying one of the constraints -(see http://golang.org/pkg/go/build/#hdr-Build_Constraints for details about the constraint syntax). +(see https://golang.org/pkg/go/build/#hdr-Build_Constraints for details about the constraint syntax). For example: // #cgo CFLAGS: -DPNG_DEBUG=1 @@ -60,6 +67,18 @@ concatenated and used at link time. All the pkg-config directives are concatenated and sent to pkg-config simultaneously to add to each appropriate set of command-line flags. +When the cgo directives are parsed, any occurrence of the string ${SRCDIR} +will be replaced by the absolute path to the directory containing the source +file. This allows pre-compiled static libraries to be included in the package +directory and linked properly. +For example if package foo is in the directory /go/src/foo: + + // #cgo LDFLAGS: -L${SRCDIR}/libs -lfoo + +Will be expanded to: + + // #cgo LDFLAGS: -L/go/src/foo/libs -lfoo + When the Go tool sees that one or more Go files use the special import "C", it will look for other non-Go files in the directory and compile them as part of the Go package. Any .c, .s, or .S files will be @@ -71,17 +90,19 @@ compilers may be changed by the CC and CXX environment variables, respectively; those environment variables may include command line options. -To enable cgo during cross compiling builds, set the CGO_ENABLED -environment variable to 1 when building the Go tools with make.bash. -Also, set CC_FOR_TARGET to the C cross compiler for the target. CC will -be used for compiling for the host. - -After the Go tools are built, when running the go command, CC_FOR_TARGET is -ignored. The value of CC_FOR_TARGET when running make.bash is the default -compiler. However, you can set the environment variable CC, not CC_FOR_TARGET, -to control the compiler when running the go tool. +The cgo tool is enabled by default for native builds on systems where +it is expected to work. It is disabled by default when +cross-compiling. You can control this by setting the CGO_ENABLED +environment variable when running the go tool: set it to 1 to enable +the use of cgo, and to 0 to disable it. The go tool will set the +build constraint "cgo" if cgo is enabled. -CXX_FOR_TARGET works in a similar way for C++ code. +When cross-compiling, you must specify a C cross-compiler for cgo to +use. You can do this by setting the CC_FOR_TARGET environment +variable when building the toolchain using make.bash, or by setting +the CC environment variable any time you run the go tool. The +CXX_FOR_TARGET and CXX environment variables work in a similar way for +C++ code. Go references to C @@ -195,16 +216,18 @@ Not all Go types can be mapped to C types in a useful way. Using //export in a file places a restriction on the preamble: since it is copied into two different C output files, it must not -contain any definitions, only declarations. Definitions must be -placed in preambles in other files, or in C source files. +contain any definitions, only declarations. If a file contains both +definitions and declarations, then the two output files will produce +duplicate symbols and the linker will fail. To avoid this, definitions +must be placed in preambles in other files, or in C source files. Using cgo directly Usage: - go tool cgo [cgo options] [-- compiler options] file.go + go tool cgo [cgo options] [-- compiler options] gofiles... -Cgo transforms the input file.go into four output files: two Go source -files, a C file for 6c (or 8c or 5c), and a C file for gcc. +Cgo transforms the specified input Go source files into several output +Go and C source files. The compiler options are passed through uninterpreted when invoking the C compiler to compile the C parts of the package. @@ -217,18 +240,23 @@ The following options are available when running cgo directly: build when building a cgo package. -dynout file Write -dynimport output to file. + -dynpackage package + Set Go package for -dynimport output. -dynlinker Write dynamic linker as part of -dynimport output. -godefs Write out input file in Go syntax replacing C package names with real values. Used to generate files in the syscall package when bootstrapping a new target. - -cdefs - Like -godefs, but write file in C syntax. - Used to generate files in the runtime package when - bootstrapping a new target. -objdir directory Put all generated files in directory. + -importpath string + The import path for the Go package. Optional; used for + nicer comments in the generated files. + -exportheader file + If there are any exported functions, write the + generated export declarations to file. + C code can #include this to see the declarations. -gccgo Generate output for the gccgo compiler rather than the gc compiler. @@ -363,9 +391,9 @@ the translation process. Translating Go -[The rest of this comment refers to 6g and 6c, the Go and C compilers -that are part of the amd64 port of the gc Go toolchain. Everything here -applies to another architecture's compilers as well.] +[The rest of this comment refers to 6g, the Go compiler that is part +of the amd64 port of the gc Go toolchain. Everything here applies to +another architecture's compilers as well.] Given the input Go files x.go and y.go, cgo generates these source files: @@ -373,44 +401,41 @@ files: x.cgo1.go # for 6g y.cgo1.go # for 6g _cgo_gotypes.go # for 6g - _cgo_defun.c # for 6c + _cgo_import.go # for 6g (if -dynout _cgo_import.go) x.cgo2.c # for gcc y.cgo2.c # for gcc + _cgo_defun.c # for gcc (if -gccgo) _cgo_export.c # for gcc + _cgo_export.h # for gcc _cgo_main.c # for gcc + _cgo_flags # for alternative build tools The file x.cgo1.go is a copy of x.go with the import "C" removed and references to C.xxx replaced with names like _Cfunc_xxx or _Ctype_xxx. The definitions of those identifiers, written as Go functions, types, or variables, are provided in _cgo_gotypes.go. -Here is a _cgo_gotypes.go containing definitions for C.flush (provided -in the preamble) and C.puts (from stdio): +Here is a _cgo_gotypes.go containing definitions for needed C types: type _Ctype_char int8 type _Ctype_int int32 type _Ctype_void [0]byte - func _Cfunc_CString(string) *_Ctype_char - func _Cfunc_flush() _Ctype_void - func _Cfunc_puts(*_Ctype_char) _Ctype_int - -For functions, cgo only writes an external declaration in the Go -output. The implementation is in a combination of C for 6c (meaning -any gc-toolchain compiler) and C for gcc. - -The 6c file contains the definitions of the functions. They all have -similar bodies that invoke runtime·cgocall to make a switch from the -Go runtime world to the system C (GCC-based) world. +The _cgo_gotypes.go file also contains the definitions of the +functions. They all have similar bodies that invoke runtime·cgocall +to make a switch from the Go runtime world to the system C (GCC-based) +world. For example, here is the definition of _Cfunc_puts: - void _cgo_be59f0f25121_Cfunc_puts(void*); + //go:cgo_import_static _cgo_be59f0f25121_Cfunc_puts + //go:linkname __cgofn__cgo_be59f0f25121_Cfunc_puts _cgo_be59f0f25121_Cfunc_puts + var __cgofn__cgo_be59f0f25121_Cfunc_puts byte + var _cgo_be59f0f25121_Cfunc_puts = unsafe.Pointer(&__cgofn__cgo_be59f0f25121_Cfunc_puts) - void - ·_Cfunc_puts(struct{uint8 x[1];}p) - { - runtime·cgocall(_cgo_be59f0f25121_Cfunc_puts, &p); + func _Cfunc_puts(p0 *_Ctype_char) (r1 _Ctype_int) { + _cgo_runtime_cgocall(_cgo_be59f0f25121_Cfunc_puts, uintptr(unsafe.Pointer(&p0))) + return } The hexadecimal number is a hash of cgo's input, chosen to be @@ -421,6 +446,7 @@ file compiled by gcc, the file x.cgo2.c: void _cgo_be59f0f25121_Cfunc_puts(void *v) { + _cgo_wait_runtime_init_done(); struct { char* p0; int r; @@ -429,7 +455,8 @@ file compiled by gcc, the file x.cgo2.c: a->r = puts((void*)a->p0); } -It extracts the arguments from the pointer to _Cfunc_puts's argument +It waits for Go runtime to be initialized (required for shared libraries), +extracts the arguments from the pointer to _Cfunc_puts's argument frame, invokes the system C function (in this case, puts), stores the result in the frame, and returns. @@ -448,6 +475,7 @@ _cgo_main.c: int main() { return 0; } void crosscall2(void(*fn)(void*, int), void *a, int c) { } + void _cgo_wait_runtime_init_done() { } void _cgo_allocate(void *a, int c) { } void _cgo_panic(void *a, int c) { } @@ -456,23 +484,21 @@ code generated for gcc. The build process links this stub, along with _cgo_export.c and *.cgo2.c, into a dynamic executable and then lets cgo examine the executable. Cgo records the list of shared library references and resolved names and writes them into a new file -_cgo_import.c, which looks like: +_cgo_import.go, which looks like: - #pragma cgo_dynamic_linker "/lib64/ld-linux-x86-64.so.2" - #pragma cgo_import_dynamic puts puts#GLIBC_2.2.5 "libc.so.6" - #pragma cgo_import_dynamic __libc_start_main __libc_start_main#GLIBC_2.2.5 "libc.so.6" - #pragma cgo_import_dynamic stdout stdout#GLIBC_2.2.5 "libc.so.6" - #pragma cgo_import_dynamic fflush fflush#GLIBC_2.2.5 "libc.so.6" - #pragma cgo_import_dynamic _ _ "libpthread.so.0" - #pragma cgo_import_dynamic _ _ "libc.so.6" + //go:cgo_dynamic_linker "/lib64/ld-linux-x86-64.so.2" + //go:cgo_import_dynamic puts puts#GLIBC_2.2.5 "libc.so.6" + //go:cgo_import_dynamic __libc_start_main __libc_start_main#GLIBC_2.2.5 "libc.so.6" + //go:cgo_import_dynamic stdout stdout#GLIBC_2.2.5 "libc.so.6" + //go:cgo_import_dynamic fflush fflush#GLIBC_2.2.5 "libc.so.6" + //go:cgo_import_dynamic _ _ "libpthread.so.0" + //go:cgo_import_dynamic _ _ "libc.so.6" In the end, the compiled Go package, which will eventually be presented to 6l as part of a larger program, contains: - _go_.6 # 6g-compiled object for _cgo_gotypes.go *.cgo1.go - _cgo_defun.6 # 6c-compiled object for _cgo_defun.c + _go_.6 # 6g-compiled object for _cgo_gotypes.go, _cgo_import.go, *.cgo1.go _all.o # gcc-compiled object for _cgo_export.c, *.cgo2.c - _cgo_import.6 # 6c-compiled object for _cgo_import.c The final program will be a dynamic executable, so that 6l can avoid needing to process arbitrary .o files. It only needs to process the .o @@ -496,20 +522,21 @@ Runtime When using cgo, Go must not assume that it owns all details of the process. In particular it needs to coordinate with C in the use of -threads and thread-local storage. The runtime package, in its own -(6c-compiled) C code, declares a few uninitialized (default bss) +threads and thread-local storage. The runtime package declares a few variables: - bool runtime·iscgo; - void (*libcgo_thread_start)(void*); - void (*initcgo)(G*); + var ( + iscgo bool + _cgo_init unsafe.Pointer + _cgo_thread_start unsafe.Pointer + ) Any package using cgo imports "runtime/cgo", which provides -initializations for these variables. It sets iscgo to 1, initcgo to a -gcc-compiled function that can be called early during program startup, -and libcgo_thread_start to a gcc-compiled function that can be used to -create a new thread, in place of the runtime's usual direct system -calls. +initializations for these variables. It sets iscgo to true, _cgo_init +to a gcc-compiled function that can be called early during program +startup, and _cgo_thread_start to a gcc-compiled function that can be +used to create a new thread, in place of the runtime's usual direct +system calls. Internal and External Linking @@ -522,12 +549,12 @@ code can only be used as a dynamic library). On the other hand, when using internal linking, 6l can generate Go binaries by itself. In order to allow linking arbitrary object files without requiring -dynamic libraries, cgo will soon support an "external" linking mode -too. In external linking mode, 6l does not process any host object -files. Instead, it collects all the Go code and writes a single go.o -object file containing it. Then it invokes the host linker (usually -gcc) to combine the go.o object file and any supporting non-Go code -into a final executable. External linking avoids the dynamic library +dynamic libraries, cgo supports an "external" linking mode too. In +external linking mode, 6l does not process any host object files. +Instead, it collects all the Go code and writes a single go.o object +file containing it. Then it invokes the host linker (usually gcc) to +combine the go.o object file and any supporting non-Go code into a +final executable. External linking avoids the dynamic library requirement but introduces a requirement that the host linker be present to create such a binary. @@ -555,13 +582,13 @@ to be made when linking the final binary. Linking Directives In either linking mode, package-specific directives must be passed -through to 6l. These are communicated by writing #pragma directives -in a C source file compiled by 6c. The directives are copied into the .6 object file -and then processed by the linker. +through to 6l. These are communicated by writing //go: directives in a +Go source file compiled by 6g. The directives are copied into the .6 +object file and then processed by the linker. The directives are: -#pragma cgo_import_dynamic [ [""]] +//go:cgo_import_dynamic [ [""]] In internal linking mode, allow an unresolved reference to , assuming it will be resolved by a dynamic library @@ -572,9 +599,9 @@ The directives are: In the , # or @ can be used to introduce a symbol version. Examples: - #pragma cgo_import_dynamic puts - #pragma cgo_import_dynamic puts puts#GLIBC_2.2.5 - #pragma cgo_import_dynamic puts puts#GLIBC_2.2.5 "libc.so.6" + //go:cgo_import_dynamic puts + //go:cgo_import_dynamic puts puts#GLIBC_2.2.5 + //go:cgo_import_dynamic puts puts#GLIBC_2.2.5 "libc.so.6" A side effect of the cgo_import_dynamic directive with a library is to make the final binary depend on that dynamic @@ -582,12 +609,12 @@ The directives are: symbols, use _ for local and remote. Example: - #pragma cgo_import_dynamic _ _ "libc.so.6" + //go:cgo_import_dynamic _ _ "libc.so.6" For compatibility with current versions of SWIG, - #pragma dynimport is an alias for #pragma cgo_import_dynamic. + #pragma dynimport is an alias for //go:cgo_import_dynamic. -#pragma cgo_dynamic_linker "" +//go:cgo_dynamic_linker "" In internal linking mode, use "" as the dynamic linker in the final binary. This directive is only needed from one @@ -595,9 +622,9 @@ The directives are: supplied by runtime/cgo. Example: - #pragma cgo_dynamic_linker "/lib/ld-linux.so.2" + //go:cgo_dynamic_linker "/lib/ld-linux.so.2" -#pragma cgo_export_dynamic +//go:cgo_export_dynamic In internal linking mode, put the Go symbol named into the program's exported symbol table as @@ -606,9 +633,9 @@ The directives are: to share Go's data. For compatibility with current versions of SWIG, - #pragma dynexport is an alias for #pragma cgo_export_dynamic. + #pragma dynexport is an alias for //go:cgo_export_dynamic. -#pragma cgo_import_static +//go:cgo_import_static In external linking mode, allow unresolved references to in the go.o object file prepared for the host linker, @@ -616,9 +643,9 @@ The directives are: other object files that will be linked with go.o. Example: - #pragma cgo_import_static puts_wrapper + //go:cgo_import_static puts_wrapper -#pragma cgo_export_static +//go:cgo_export_static In external linking mode, put the Go symbol named into the program's exported symbol table as @@ -626,15 +653,15 @@ The directives are: mechanism makes it possible for C code to call back into Go or to share Go's data. -#pragma cgo_ldflag "" +//go:cgo_ldflag "" In external linking mode, invoke the host linker (usually gcc) with "" as a command-line argument following the .o files. Note that the arguments are for "gcc", not "ld". Example: - #pragma cgo_ldflag "-lpthread" - #pragma cgo_ldflag "-L/usr/local/sqlite3/lib" + //go:cgo_ldflag "-lpthread" + //go:cgo_ldflag "-L/usr/local/sqlite3/lib" A package compiled with cgo will include directives for both internal and external linking; the linker will select the appropriate @@ -647,22 +674,18 @@ The following code will be generated by cgo: // compiled by 6g - type _Ctype_double float64 - func _Cfunc_sin(_Ctype_double) _Ctype_double - - // compiled by 6c + //go:cgo_ldflag "-lm" - #pragma cgo_import_dynamic sin sin#GLIBC_2.2.5 "libm.so.6" - - #pragma cgo_import_static _cgo_gcc_Cfunc_sin - #pragma cgo_ldflag "-lm" + type _Ctype_double float64 - void _cgo_gcc_Cfunc_sin(void*); + //go:cgo_import_static _cgo_gcc_Cfunc_sin + //go:linkname __cgo_gcc_Cfunc_sin _cgo_gcc_Cfunc_sin + var __cgo_gcc_Cfunc_sin byte + var _cgo_gcc_Cfunc_sin = unsafe.Pointer(&__cgo_gcc_Cfunc_sin) - void - ·_Cfunc_sin(struct{uint8 x[16];}p) - { - runtime·cgocall(_cgo_gcc_Cfunc_sin, &p); + func _Cfunc_sin(p0 _Ctype_double) (r1 _Ctype_double) { + _cgo_runtime_cgocall(_cgo_gcc_Cfunc_sin, uintptr(unsafe.Pointer(&p0))) + return } // compiled by gcc, into foo.cgo2.o @@ -682,8 +705,8 @@ using the internal or external mode. If other packages are compiled in "external only" mode, then the final link will be an external one. Otherwise the link will be an internal one. -The directives in the 6c-compiled file are used according to the kind -of final link used. +The linking directives are used according to the kind of final link +used. In internal mode, 6l itself processes all the host object files, in particular foo.cgo2.o. To do so, it uses the cgo_import_dynamic and @@ -694,10 +717,10 @@ symbol sin with version GLIBC_2.2.5 from the dynamic library runtime dynamic linker. In external mode, 6l does not process any host object files, in -particular foo.cgo2.o. It links together the 6g- and 6c-generated -object files, along with any other Go code, into a go.o file. While -doing that, 6l will discover that there is no definition for -_cgo_gcc_Cfunc_sin, referred to by the 6c-compiled source file. This +particular foo.cgo2.o. It links together the 6g-generated object +files, along with any other Go code, into a go.o file. While doing +that, 6l will discover that there is no definition for +_cgo_gcc_Cfunc_sin, referred to by the 6g-compiled source file. This is okay, because 6l also processes the cgo_import_static directive and knows that _cgo_gcc_Cfunc_sin is expected to be supplied by a host object file, so 6l does not treat the missing symbol as an error when diff --git a/libgo/go/cmd/cgo/gcc.go b/libgo/go/cmd/cgo/gcc.go index abdd369d713..b64849a8d16 100644 --- a/libgo/go/cmd/cgo/gcc.go +++ b/libgo/go/cmd/cgo/gcc.go @@ -154,20 +154,6 @@ func splitQuoted(s string) (r []string, err error) { return args, err } -var safeBytes = []byte(`+-.,/0123456789:=ABCDEFGHIJKLMNOPQRSTUVWXYZ\_abcdefghijklmnopqrstuvwxyz`) - -func safeName(s string) bool { - if s == "" { - return false - } - for i := 0; i < len(s); i++ { - if c := s[i]; c < 0x80 && bytes.IndexByte(safeBytes, c) < 0 { - return false - } - } - return true -} - // Translate rewrites f.AST, the original Go input, to remove // references to the imported package C, replacing them with // references to the equivalent Go types, functions, and variables. @@ -213,6 +199,10 @@ func (p *Package) loadDefines(f *File) { val = strings.TrimSpace(line[tabIndex:]) } + if key == "__clang__" { + p.GccIsClang = true + } + if n := f.Name[key]; n != nil { if *debugDefine { fmt.Fprintf(os.Stderr, "#define %s %s\n", key, val) @@ -582,7 +572,7 @@ func (p *Package) mangleName(n *Name) { // rewriteRef rewrites all the C.xxx references in f.AST to refer to the // Go equivalents, now that we have figured out the meaning of all -// the xxx. In *godefs or *cdefs mode, rewriteRef replaces the names +// the xxx. In *godefs mode, rewriteRef replaces the names // with full definitions instead of mangled names. func (p *Package) rewriteRef(f *File) { // Keep a list of all the functions, to remove the ones @@ -673,6 +663,13 @@ func (p *Package) rewriteRef(f *File) { expr = &ast.StarExpr{Star: (*r.Expr).Pos(), X: expr} } + case "selector": + if r.Name.Kind == "var" { + expr = &ast.StarExpr{Star: (*r.Expr).Pos(), X: expr} + } else { + error_(r.Pos(), "only C variables allowed in selector expression", fixGo(r.Name.Go)) + } + case "type": if r.Name.Kind != "type" { error_(r.Pos(), "expression C.%s used as type", fixGo(r.Name.Go)) @@ -688,7 +685,7 @@ func (p *Package) rewriteRef(f *File) { error_(r.Pos(), "must call C.%s", fixGo(r.Name.Go)) } } - if *godefs || *cdefs { + if *godefs { // Substitute definition for mangled type name. if id, ok := expr.(*ast.Ident); ok { if t := typedef[id.Name]; t != nil { @@ -746,6 +743,10 @@ func (p *Package) gccMachine() []string { return []string{"-m32"} case "arm": return []string{"-marm"} // not thumb + case "s390": + return []string{"-m31"} + case "s390x": + return []string{"-m64"} } return nil } @@ -765,7 +766,7 @@ func (p *Package) gccCmd() []string { "-c", // do not link "-xc", // input language is C ) - if strings.Contains(c[0], "clang") { + if p.GccIsClang { c = append(c, "-ferror-limit=0", // Apple clang version 1.7 (tags/Apple/clang-77) (based on LLVM 2.9svn) @@ -780,7 +781,7 @@ func (p *Package) gccCmd() []string { // incorrectly typed unsigned long. We work around that // by disabling the builtin functions (this is safe as // it won't affect the actual compilation of the C code). - // See: http://golang.org/issue/6506. + // See: https://golang.org/issue/6506. "-fno-builtin", ) } @@ -992,8 +993,8 @@ func (c *typeConv) Init(ptrSize, intSize int64) { c.goVoid = c.Ident("_Ctype_void") // Normally cgo translates void* to unsafe.Pointer, - // but for historical reasons -cdefs and -godefs use *byte instead. - if *cdefs || *godefs { + // but for historical reasons -godefs uses *byte instead. + if *godefs { c.goVoidPtr = &ast.StarExpr{X: c.byte} } else { c.goVoidPtr = c.Ident("unsafe.Pointer") @@ -1045,7 +1046,7 @@ func (tr *TypeRepr) String() string { return fmt.Sprintf(tr.Repr, tr.FormatArgs...) } -// Empty returns true if the result of String would be "". +// Empty reports whether the result of String would be "". func (tr *TypeRepr) Empty() bool { return len(tr.Repr) == 0 } @@ -1334,8 +1335,8 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type { // If sub.Go.Name is "_Ctype_struct_foo" or "_Ctype_union_foo" or "_Ctype_class_foo", // use that as the Go form for this typedef too, so that the typedef will be interchangeable // with the base type. - // In -godefs and -cdefs mode, do this for all typedefs. - if isStructUnionClass(sub.Go) || *godefs || *cdefs { + // In -godefs mode, do this for all typedefs. + if isStructUnionClass(sub.Go) || *godefs { t.Go = sub.Go if isStructUnionClass(sub.Go) { @@ -1397,7 +1398,7 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type { name := c.Ident("_Ctype_" + s) tt := *t typedef[name.Name] = &tt - if !*godefs && !*cdefs { + if !*godefs { t.Go = name } } @@ -1543,14 +1544,16 @@ func (c *typeConv) intExpr(n int64) ast.Expr { } // Add padding of given size to fld. -func (c *typeConv) pad(fld []*ast.Field, size int64) []*ast.Field { +func (c *typeConv) pad(fld []*ast.Field, sizes []int64, size int64) ([]*ast.Field, []int64) { n := len(fld) fld = fld[0 : n+1] fld[n] = &ast.Field{Names: []*ast.Ident{c.Ident("_")}, Type: c.Opaque(size)} - return fld + sizes = sizes[0 : n+1] + sizes[n] = size + return fld, sizes } -// Struct conversion: return Go and (6g) C syntax for type. +// Struct conversion: return Go and (gc) C syntax for type. func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.StructType, csyntax string, align int64) { // Minimum alignment for a struct is 1 byte. align = 1 @@ -1558,6 +1561,7 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct var buf bytes.Buffer buf.WriteString("struct {") fld := make([]*ast.Field, 0, 2*len(dt.Field)+1) // enough for padding around every field + sizes := make([]int64, 0, 2*len(dt.Field)+1) off := int64(0) // Rename struct fields that happen to be named Go keywords into @@ -1573,7 +1577,7 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct used[f.Name] = true } - if !*godefs && !*cdefs { + if !*godefs { for cid, goid := range ident { if token.Lookup(goid).IsKeyword() { // Avoid keyword @@ -1593,19 +1597,19 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct anon := 0 for _, f := range dt.Field { if f.ByteOffset > off { - fld = c.pad(fld, f.ByteOffset-off) + fld, sizes = c.pad(fld, sizes, f.ByteOffset-off) off = f.ByteOffset } name := f.Name ft := f.Type - // In godefs or cdefs mode, if this field is a C11 + // In godefs mode, if this field is a C11 // anonymous union then treat the first field in the // union as the field in the struct. This handles // cases like the glibc file; see // issue 6677. - if *godefs || *cdefs { + if *godefs { if st, ok := f.Type.(*dwarf.StructType); ok && name == "" && st.Kind == "union" && len(st.Field) > 0 && !used[st.Field[0].Name] { name = st.Field[0].Name ident[name] = name @@ -1635,14 +1639,12 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct talign = size } - if talign > 0 && f.ByteOffset%talign != 0 && !*cdefs { + if talign > 0 && f.ByteOffset%talign != 0 { // Drop misaligned fields, the same way we drop integer bit fields. // The goal is to make available what can be made available. // Otherwise one bad and unneeded field in an otherwise okay struct // makes the whole program not compile. Much of the time these // structs are in system headers that cannot be corrected. - // Exception: In -cdefs mode, we use #pragma pack, so misaligned - // fields should still work. continue } n := len(fld) @@ -1653,6 +1655,8 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct ident[name] = name } fld[n] = &ast.Field{Names: []*ast.Ident{c.Ident(ident[name])}, Type: tgo} + sizes = sizes[0 : n+1] + sizes[n] = size off += size buf.WriteString(t.C.String()) buf.WriteString(" ") @@ -1663,16 +1667,29 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct } } if off < dt.ByteSize { - fld = c.pad(fld, dt.ByteSize-off) + fld, sizes = c.pad(fld, sizes, dt.ByteSize-off) off = dt.ByteSize } + + // If the last field in a non-zero-sized struct is zero-sized + // the compiler is going to pad it by one (see issue 9401). + // We can't permit that, because then the size of the Go + // struct will not be the same as the size of the C struct. + // Our only option in such a case is to remove the field, + // which means that it can not be referenced from Go. + for off > 0 && sizes[len(sizes)-1] == 0 { + n := len(sizes) + fld = fld[0 : n-1] + sizes = sizes[0 : n-1] + } + if off != dt.ByteSize { fatalf("%s: struct size calculation error off=%d bytesize=%d", lineno(pos), off, dt.ByteSize) } buf.WriteString("}") csyntax = buf.String() - if *godefs || *cdefs { + if *godefs { godefsFields(fld) } expr = &ast.StructType{Fields: &ast.FieldList{List: fld}} @@ -1707,9 +1724,7 @@ func godefsFields(fld []*ast.Field) { n.Name = "Pad_cgo_" + strconv.Itoa(npad) npad++ } - if !*cdefs { - n.Name = upper(n.Name) - } + n.Name = upper(n.Name) } } } @@ -1721,9 +1736,6 @@ func godefsFields(fld []*ast.Field) { // package syscall's data structures, we drop a common prefix // (so sec, usec, which will get turned into Sec, Usec for exporting). func fieldPrefix(fld []*ast.Field) string { - if *cdefs { - return "" - } prefix := "" for _, f := range fld { for _, n := range f.Names { diff --git a/libgo/go/cmd/cgo/godefs.go b/libgo/go/cmd/cgo/godefs.go index ce5ac2736c5..1b0ece29ef4 100644 --- a/libgo/go/cmd/cgo/godefs.go +++ b/libgo/go/cmd/cgo/godefs.go @@ -114,173 +114,6 @@ func (p *Package) godefs(f *File, srcfile string) string { return buf.String() } -// cdefs returns the output for -cdefs mode. -// The easiest way to do this is to translate the godefs Go to C. -func (p *Package) cdefs(f *File, srcfile string) string { - godefsOutput := p.godefs(f, srcfile) - - lines := strings.Split(godefsOutput, "\n") - lines[0] = "// Created by cgo -cdefs - DO NOT EDIT" - - for i, line := range lines { - lines[i] = strings.TrimSpace(line) - } - - var out bytes.Buffer - printf := func(format string, args ...interface{}) { fmt.Fprintf(&out, format, args...) } - - didTypedef := false - for i := 0; i < len(lines); i++ { - line := lines[i] - - // Delete - // package x - if strings.HasPrefix(line, "package ") { - continue - } - - // Convert - // const ( - // A = 1 - // B = 2 - // ) - // - // to - // - // enum { - // A = 1, - // B = 2, - // }; - if line == "const (" { - printf("enum {\n") - for i++; i < len(lines) && lines[i] != ")"; i++ { - line = lines[i] - if line != "" { - printf("\t%s,", line) - } - printf("\n") - } - printf("};\n") - continue - } - - // Convert - // const A = 1 - // to - // enum { A = 1 }; - if strings.HasPrefix(line, "const ") { - printf("enum { %s };\n", line[len("const "):]) - continue - } - - // On first type definition, typedef all the structs - // in case there are dependencies between them. - if !didTypedef && strings.HasPrefix(line, "type ") { - didTypedef = true - for _, line := range lines { - line = strings.TrimSpace(line) - if strings.HasPrefix(line, "type ") && strings.HasSuffix(line, " struct {") { - s := strings.TrimSuffix(strings.TrimPrefix(line, "type "), " struct {") - printf("typedef struct %s %s;\n", s, s) - } - } - printf("\n") - printf("#pragma pack on\n") - printf("\n") - } - - // Convert - // type T struct { - // X int64 - // Y *int32 - // Z [4]byte - // } - // - // to - // - // struct T { - // int64 X; - // int32 *Y; - // byte Z[4]; - // } - if strings.HasPrefix(line, "type ") && strings.HasSuffix(line, " struct {") { - if len(lines) > i+1 && lines[i+1] == "}" { - // do not output empty struct - i++ - continue - } - s := line[len("type ") : len(line)-len(" struct {")] - printf("struct %s {\n", s) - for i++; i < len(lines) && lines[i] != "}"; i++ { - line := lines[i] - if line != "" { - f := strings.Fields(line) - if len(f) != 2 { - fmt.Fprintf(os.Stderr, "cgo: cannot parse struct field: %s\n", line) - nerrors++ - continue - } - printf("\t%s;", cdecl(f[0], f[1])) - } - printf("\n") - } - printf("};\n") - continue - } - - // Convert - // type T int - // to - // typedef int T; - if strings.HasPrefix(line, "type ") { - f := strings.Fields(line[len("type "):]) - if len(f) != 2 { - fmt.Fprintf(os.Stderr, "cgo: cannot parse type definition: %s\n", line) - nerrors++ - continue - } - printf("typedef\t%s;\n", cdecl(f[0], f[1])) - continue - } - - printf("%s\n", line) - } - - if didTypedef { - printf("\n") - printf("#pragma pack off\n") - } - - return out.String() -} - -// cdecl returns the C declaration for the given Go name and type. -// It only handles the specific cases necessary for converting godefs output. -func cdecl(name, typ string) string { - // X *[0]byte -> X *void - if strings.HasPrefix(typ, "*[0]") { - typ = "*void" - } - // X [4]byte -> X[4] byte - for strings.HasPrefix(typ, "[") { - i := strings.Index(typ, "]") + 1 - name = name + typ[:i] - typ = typ[i:] - } - // X *byte -> *X byte - for strings.HasPrefix(typ, "*") { - name = "*" + name - typ = typ[1:] - } - // X T -> T X - // Handle the special case: 'unsafe.Pointer' is 'void *' - if typ == "unsafe.Pointer" { - typ = "void" - name = "*" + name - } - return typ + "\t" + name -} - var gofmtBuf bytes.Buffer // gofmt returns the gofmt-formatted string for an AST node. diff --git a/libgo/go/cmd/cgo/main.go b/libgo/go/cmd/cgo/main.go index 48257fc6c4d..c8cd1610baf 100644 --- a/libgo/go/cmd/cgo/main.go +++ b/libgo/go/cmd/cgo/main.go @@ -6,7 +6,7 @@ // TODO(rsc): // Emit correct line number annotations. -// Make 6g understand the annotations. +// Make gc understand the annotations. package main @@ -33,6 +33,7 @@ type Package struct { PtrSize int64 IntSize int64 GccOptions []string + GccIsClang bool CgoFlags map[string][]string // #cgo flags (CFLAGS, LDFLAGS) Written map[string]bool Name map[string]*Name // accumulated Name from Files @@ -87,7 +88,7 @@ type Name struct { Const string // constant definition } -// IsVar returns true if Kind is either "var" or "fpvar" +// IsVar reports whether Kind is either "var" or "fpvar" func (n *Name) IsVar() bool { return n.Kind == "var" || n.Kind == "fpvar" } @@ -98,6 +99,7 @@ func (n *Name) IsVar() bool { type ExpFunc struct { Func *ast.FuncDecl ExpName string // name to use from C + Doc string } // A TypeRepr contains the string representation of a type. @@ -174,15 +176,18 @@ var cPrefix string var fset = token.NewFileSet() var dynobj = flag.String("dynimport", "", "if non-empty, print dynamic import data for that file") -var dynout = flag.String("dynout", "", "write -dynobj output to this file") -var dynlinker = flag.Bool("dynlinker", false, "record dynamic linker information in dynimport mode") +var dynout = flag.String("dynout", "", "write -dynimport output to this file") +var dynpackage = flag.String("dynpackage", "main", "set Go package for -dynimport output") +var dynlinker = flag.Bool("dynlinker", false, "record dynamic linker information in -dynimport mode") -// These flags are for bootstrapping a new Go implementation, -// to generate Go and C headers that match the data layout and +// This flag is for bootstrapping a new Go implementation, +// to generate Go types that match the data layout and // constant values used in the host's C libraries and system calls. var godefs = flag.Bool("godefs", false, "for bootstrap: write Go definitions for C file to standard output") -var cdefs = flag.Bool("cdefs", false, "for bootstrap: write C definitions for C file to standard output") + var objDir = flag.String("objdir", "", "object directory") +var importPath = flag.String("importpath", "", "import path of package being built (for comments in generated files)") +var exportHeader = flag.String("exportheader", "", "where to write export header if any exported functions") var gccgo = flag.Bool("gccgo", false, "generate files for use with gccgo") var gccgoprefix = flag.String("gccgoprefix", "", "-fgo-prefix option used with gccgo") @@ -208,12 +213,7 @@ func main() { return } - if *godefs && *cdefs { - fmt.Fprintf(os.Stderr, "cgo: cannot use -cdefs and -godefs together\n") - os.Exit(2) - } - - if *godefs || *cdefs { + if *godefs { // Generating definitions pulled from header files, // to be checked into Go repositories. // Line numbers are just noise. @@ -305,14 +305,12 @@ func main() { p.Record(f) if *godefs { os.Stdout.WriteString(p.godefs(f, input)) - } else if *cdefs { - os.Stdout.WriteString(p.cdefs(f, input)) } else { p.writeOutput(f, input) } } - if !*godefs && !*cdefs { + if !*godefs { p.writeDefs() } if nerrors > 0 { diff --git a/libgo/go/cmd/cgo/out.go b/libgo/go/cmd/cgo/out.go index d92bed9bf01..90a74419622 100644 --- a/libgo/go/cmd/cgo/out.go +++ b/libgo/go/cmd/cgo/out.go @@ -13,6 +13,7 @@ import ( "go/ast" "go/printer" "go/token" + "io" "os" "sort" "strings" @@ -20,11 +21,17 @@ import ( var conf = printer.Config{Mode: printer.SourcePos, Tabwidth: 8} -// writeDefs creates output files to be compiled by 6g, 6c, and gcc. -// (The comments here say 6g and 6c but the code applies to the 8 and 5 tools too.) +// writeDefs creates output files to be compiled by gc and gcc. func (p *Package) writeDefs() { - fgo2 := creat(*objDir + "_cgo_gotypes.go") - fc := creat(*objDir + "_cgo_defun.c") + var fgo2, fc io.Writer + f := creat(*objDir + "_cgo_gotypes.go") + defer f.Close() + fgo2 = f + if *gccgo { + f := creat(*objDir + "_cgo_defun.c") + defer f.Close() + fc = f + } fm := creat(*objDir + "_cgo_main.c") var gccgoInit bytes.Buffer @@ -34,7 +41,7 @@ func (p *Package) writeDefs() { fmt.Fprintf(fflg, "_CGO_%s=%s\n", k, strings.Join(v, " ")) if k == "LDFLAGS" && !*gccgo { for _, arg := range v { - fmt.Fprintf(fc, "#pragma cgo_ldflag %q\n", arg) + fmt.Fprintf(fgo2, "//go:cgo_ldflag %q\n", arg) } } } @@ -44,14 +51,17 @@ func (p *Package) writeDefs() { fmt.Fprintf(fm, "int main() { return 0; }\n") if *importRuntimeCgo { fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int), void *a, int c) { }\n") + fmt.Fprintf(fm, "void _cgo_wait_runtime_init_done() { }\n") fmt.Fprintf(fm, "char* _cgo_topofstack(void) { return (char*)0; }\n") } else { // If we're not importing runtime/cgo, we *are* runtime/cgo, - // which provides crosscall2. We just need a prototype. + // which provides these functions. We just need a prototype. fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int), void *a, int c);\n") + fmt.Fprintf(fm, "void _cgo_wait_runtime_init_done();\n") } fmt.Fprintf(fm, "void _cgo_allocate(void *a, int c) { }\n") fmt.Fprintf(fm, "void _cgo_panic(void *a, int c) { }\n") + fmt.Fprintf(fm, "void _cgo_reginit(void) { }\n") // Write second Go output: definitions of _C_xxx. // In a separate file so that the import of "unsafe" does not @@ -68,6 +78,13 @@ func (p *Package) writeDefs() { } fmt.Fprintf(fgo2, "func _Cgo_ptr(ptr unsafe.Pointer) unsafe.Pointer { return ptr }\n\n") + if !*gccgo { + fmt.Fprintf(fgo2, "//go:linkname _Cgo_always_false runtime.cgoAlwaysFalse\n") + fmt.Fprintf(fgo2, "var _Cgo_always_false bool\n") + fmt.Fprintf(fgo2, "//go:linkname _Cgo_use runtime.cgoUse\n") + fmt.Fprintf(fgo2, "func _Cgo_use(interface{})\n") + } + typedefNames := make([]string, 0, len(typedef)) for name := range typedef { typedefNames = append(typedefNames, name) @@ -88,7 +105,6 @@ func (p *Package) writeDefs() { if *gccgo { fmt.Fprint(fc, p.cPrologGccgo()) } else { - fmt.Fprint(fc, cProlog) fmt.Fprint(fgo2, goProlog) } @@ -102,44 +118,44 @@ func (p *Package) writeDefs() { } if !cVars[n.C] { - fmt.Fprintf(fm, "extern char %s[];\n", n.C) - fmt.Fprintf(fm, "void *_cgohack_%s = %s;\n\n", n.C, n.C) - - if !*gccgo { - fmt.Fprintf(fc, "#pragma cgo_import_static %s\n", n.C) + if *gccgo { + fmt.Fprintf(fc, "extern byte *%s;\n", n.C) + } else { + fmt.Fprintf(fm, "extern char %s[];\n", n.C) + fmt.Fprintf(fm, "void *_cgohack_%s = %s;\n\n", n.C, n.C) + fmt.Fprintf(fgo2, "//go:linkname __cgo_%s %s\n", n.C, n.C) + fmt.Fprintf(fgo2, "//go:cgo_import_static %s\n", n.C) + fmt.Fprintf(fgo2, "var __cgo_%s byte\n", n.C) } - - fmt.Fprintf(fc, "extern byte *%s;\n", n.C) - cVars[n.C] = true } - var amp string + var node ast.Node if n.Kind == "var" { - amp = "&" node = &ast.StarExpr{X: n.Type.Go} } else if n.Kind == "fpvar" { node = n.Type.Go - if *gccgo { - amp = "&" - } } else { panic(fmt.Errorf("invalid var kind %q", n.Kind)) } if *gccgo { fmt.Fprintf(fc, `extern void *%s __asm__("%s.%s");`, n.Mangle, gccgoSymbolPrefix, n.Mangle) - fmt.Fprintf(&gccgoInit, "\t%s = %s%s;\n", n.Mangle, amp, n.C) - } else { - fmt.Fprintf(fc, "#pragma dataflag NOPTR /* C pointer, not heap pointer */ \n") - fmt.Fprintf(fc, "void *·%s = %s%s;\n", n.Mangle, amp, n.C) + fmt.Fprintf(&gccgoInit, "\t%s = &%s;\n", n.Mangle, n.C) + fmt.Fprintf(fc, "\n") } - fmt.Fprintf(fc, "\n") fmt.Fprintf(fgo2, "var %s ", n.Mangle) conf.Fprint(fgo2, fset, node) + if !*gccgo { + fmt.Fprintf(fgo2, " = (") + conf.Fprint(fgo2, fset, node) + fmt.Fprintf(fgo2, ")(unsafe.Pointer(&__cgo_%s))", n.C) + } fmt.Fprintf(fgo2, "\n") } - fmt.Fprintf(fc, "\n") + if *gccgo { + fmt.Fprintf(fc, "\n") + } for _, key := range nameKeys(p.Name) { n := p.Name[key] @@ -152,14 +168,37 @@ func (p *Package) writeDefs() { for _, key := range nameKeys(p.Name) { n := p.Name[key] if n.FuncType != nil { - p.writeDefsFunc(fc, fgo2, n) + p.writeDefsFunc(fgo2, n) } } + fgcc := creat(*objDir + "_cgo_export.c") + fgcch := creat(*objDir + "_cgo_export.h") if *gccgo { - p.writeGccgoExports(fgo2, fc, fm) + p.writeGccgoExports(fgo2, fm, fgcc, fgcch) } else { - p.writeExports(fgo2, fc, fm) + p.writeExports(fgo2, fm, fgcc, fgcch) + } + if err := fgcc.Close(); err != nil { + fatalf("%s", err) + } + if err := fgcch.Close(); err != nil { + fatalf("%s", err) + } + + if *exportHeader != "" && len(p.ExpFunc) > 0 { + fexp := creat(*exportHeader) + fgcch, err := os.Open(*objDir + "_cgo_export.h") + if err != nil { + fatalf("%s", err) + } + _, err = io.Copy(fexp, fgcch) + if err != nil { + fatalf("%s", err) + } + if err = fexp.Close(); err != nil { + fatalf("%s", err) + } } init := gccgoInit.String() @@ -169,9 +208,6 @@ func (p *Package) writeDefs() { fmt.Fprint(fc, init) fmt.Fprintln(fc, "}") } - - fgo2.Close() - fc.Close() } func dynimport(obj string) { @@ -184,13 +220,15 @@ func dynimport(obj string) { stdout = f } + fmt.Fprintf(stdout, "package %s\n", *dynpackage) + if f, err := elf.Open(obj); err == nil { if *dynlinker { // Emit the cgo_dynamic_linker line. if sec := f.Section(".interp"); sec != nil { if data, err := sec.Data(); err == nil && len(data) > 1 { // skip trailing \0 in data - fmt.Fprintf(stdout, "#pragma cgo_dynamic_linker %q\n", string(data[:len(data)-1])) + fmt.Fprintf(stdout, "//go:cgo_dynamic_linker %q\n", string(data[:len(data)-1])) } } } @@ -203,14 +241,14 @@ func dynimport(obj string) { if s.Version != "" { targ += "#" + s.Version } - fmt.Fprintf(stdout, "#pragma cgo_import_dynamic %s %s %q\n", s.Name, targ, s.Library) + fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", s.Name, targ, s.Library) } lib, err := f.ImportedLibraries() if err != nil { fatalf("cannot load imported libraries from ELF file %s: %v", obj, err) } for _, l := range lib { - fmt.Fprintf(stdout, "#pragma cgo_import_dynamic _ _ %q\n", l) + fmt.Fprintf(stdout, "//go:cgo_import_dynamic _ _ %q\n", l) } return } @@ -224,14 +262,14 @@ func dynimport(obj string) { if len(s) > 0 && s[0] == '_' { s = s[1:] } - fmt.Fprintf(stdout, "#pragma cgo_import_dynamic %s %s %q\n", s, s, "") + fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", s, s, "") } lib, err := f.ImportedLibraries() if err != nil { fatalf("cannot load imported libraries from Mach-O file %s: %v", obj, err) } for _, l := range lib { - fmt.Fprintf(stdout, "#pragma cgo_import_dynamic _ _ %q\n", l) + fmt.Fprintf(stdout, "//go:cgo_import_dynamic _ _ %q\n", l) } return } @@ -244,7 +282,7 @@ func dynimport(obj string) { for _, s := range sym { ss := strings.Split(s, ":") name := strings.Split(ss[0], "@")[0] - fmt.Fprintf(stdout, "#pragma cgo_import_dynamic %s %s %q\n", name, ss[0], strings.ToLower(ss[1])) + fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", name, ss[0], strings.ToLower(ss[1])) } return } @@ -252,10 +290,10 @@ func dynimport(obj string) { fatalf("cannot parse %s as ELF, Mach-O or PE", obj) } -// Construct a gcc struct matching the 6c argument frame. +// Construct a gcc struct matching the gc argument frame. // Assumes that in gcc, char is 1 byte, short 2 bytes, int 4 bytes, long long 8 bytes. // These assumptions are checked by the gccProlog. -// Also assumes that 6c convention is to word-align the +// Also assumes that gc convention is to word-align the // input and output parameters. func (p *Package) structType(n *Name) (string, int64) { var buf bytes.Buffer @@ -304,7 +342,7 @@ func (p *Package) structType(n *Name) (string, int64) { return buf.String(), off } -func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) { +func (p *Package) writeDefsFunc(fgo2 io.Writer, n *Name) { name := n.Go gtype := n.FuncType.Go void := gtype.Results == nil || len(gtype.Results.List) == 0 @@ -396,11 +434,11 @@ func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) { return } - // C wrapper calls into gcc, passing a pointer to the argument frame. - fmt.Fprintf(fc, "#pragma cgo_import_static %s\n", cname) - fmt.Fprintf(fc, "void %s(void*);\n", cname) - fmt.Fprintf(fc, "#pragma dataflag NOPTR\n") - fmt.Fprintf(fc, "void *·%s = %s;\n", cname, cname) + // Wrapper calls into gcc, passing a pointer to the argument frame. + fmt.Fprintf(fgo2, "//go:cgo_import_static %s\n", cname) + fmt.Fprintf(fgo2, "//go:linkname __cgofn_%s %s\n", cname, cname) + fmt.Fprintf(fgo2, "var __cgofn_%s byte\n", cname) + fmt.Fprintf(fgo2, "var %s = unsafe.Pointer(&__cgofn_%s)\n", cname, cname) nret := 0 if !void { @@ -412,7 +450,6 @@ func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) { } fmt.Fprint(fgo2, "\n") - fmt.Fprintf(fgo2, "var %s unsafe.Pointer\n", cname) conf.Fprint(fgo2, fset, d) fmt.Fprint(fgo2, " {\n") @@ -428,16 +465,20 @@ func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) { if n.AddError { prefix = "errno := " } - fmt.Fprintf(fgo2, "\t%s_cgo_runtime_cgocall_errno(%s, %s)\n", prefix, cname, arg) + fmt.Fprintf(fgo2, "\t%s_cgo_runtime_cgocall(%s, %s)\n", prefix, cname, arg) if n.AddError { fmt.Fprintf(fgo2, "\tif errno != 0 { r2 = syscall.Errno(errno) }\n") } + fmt.Fprintf(fgo2, "\tif _Cgo_always_false {\n") + for i := range d.Type.Params.List { + fmt.Fprintf(fgo2, "\t\t_Cgo_use(p%d)\n", i) + } + fmt.Fprintf(fgo2, "\t}\n") fmt.Fprintf(fgo2, "\treturn\n") fmt.Fprintf(fgo2, "}\n") } -// writeOutput creates stubs for a specific source file to be compiled by 6g -// (The comments here say 6g and 6c but the code applies to the 8 and 5 tools too.) +// writeOutput creates stubs for a specific source file to be compiled by gc func (p *Package) writeOutput(f *File, srcfile string) { base := srcfile if strings.HasSuffix(base, ".go") { @@ -454,7 +495,7 @@ func (p *Package) writeOutput(f *File, srcfile string) { fmt.Fprintf(fgo1, "// Created by cgo - DO NOT EDIT\n\n") conf.Fprint(fgo1, fset, f.AST) - // While we process the vars and funcs, also write 6c and gcc output. + // While we process the vars and funcs, also write gcc output. // Gcc output starts with the preamble. fmt.Fprintf(fgcc, "%s\n", f.Preamble) fmt.Fprintf(fgcc, "%s\n", gccProlog) @@ -516,7 +557,7 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) { if n.AddError { fmt.Fprintf(fgcc, "\terrno = 0;\n") } - // We're trying to write a gcc struct that matches 6c/8c/5c's layout. + // We're trying to write a gcc struct that matches gc's layout. // Use packed attribute to force no padding in this struct in case // gcc has different packing requirements. fmt.Fprintf(fgcc, "\t%s %v *a = v;\n", ctype, p.packedAttribute()) @@ -612,13 +653,13 @@ func (p *Package) writeGccgoOutputFunc(fgcc *os.File, n *Name) { } // packedAttribute returns host compiler struct attribute that will be -// used to match 6c/8c/5c's struct layout. For example, on 386 Windows, -// gcc wants to 8-align int64s, but 8c does not. +// used to match gc's struct layout. For example, on 386 Windows, +// gcc wants to 8-align int64s, but gc does not. // Use __gcc_struct__ to work around http://gcc.gnu.org/PR52991 on x86, -// and http://golang.org/issue/5603. +// and https://golang.org/issue/5603. func (p *Package) packedAttribute() string { s := "__attribute__((__packed__" - if !strings.Contains(p.gccBaseCmd()[0], "clang") && (goarch == "amd64" || goarch == "386") { + if !p.GccIsClang && (goarch == "amd64" || goarch == "386") { s += ", __gcc_struct__" } return s + "))" @@ -626,23 +667,19 @@ func (p *Package) packedAttribute() string { // Write out the various stubs we need to support functions exported // from Go so that they are callable from C. -func (p *Package) writeExports(fgo2, fc, fm *os.File) { - fgcc := creat(*objDir + "_cgo_export.c") - fgcch := creat(*objDir + "_cgo_export.h") - - fmt.Fprintf(fgcch, "/* Created by cgo - DO NOT EDIT. */\n") - fmt.Fprintf(fgcch, "%s\n", p.Preamble) - fmt.Fprintf(fgcch, "%s\n", p.gccExportHeaderProlog()) +func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) { + p.writeExportHeader(fgcch) fmt.Fprintf(fgcc, "/* Created by cgo - DO NOT EDIT. */\n") - fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n") + fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n\n") - fmt.Fprintf(fgcc, "\nextern void crosscall2(void (*fn)(void *, int), void *, int);\n\n") + fmt.Fprintf(fgcc, "extern void crosscall2(void (*fn)(void *, int), void *, int);\n") + fmt.Fprintf(fgcc, "extern void _cgo_wait_runtime_init_done();\n\n") for _, exp := range p.ExpFunc { fn := exp.Func - // Construct a gcc struct matching the 6c argument and + // Construct a gcc struct matching the gc argument and // result frame. The gcc struct will be compiled with // __attribute__((packed)) so all padding must be accounted // for explicitly. @@ -728,11 +765,16 @@ func (p *Package) writeExports(fgo2, fc, fm *os.File) { s += fmt.Sprintf("%s p%d", p.cgoType(atype).C, i) }) s += ")" + + if len(exp.Doc) > 0 { + fmt.Fprintf(fgcch, "\n%s", exp.Doc) + } fmt.Fprintf(fgcch, "\nextern %s;\n", s) fmt.Fprintf(fgcc, "extern void _cgoexp%s_%s(void *, int);\n", cPrefix, exp.ExpName) fmt.Fprintf(fgcc, "\n%s\n", s) fmt.Fprintf(fgcc, "{\n") + fmt.Fprintf(fgcc, "\t_cgo_wait_runtime_init_done();\n") fmt.Fprintf(fgcc, "\t%s %v a;\n", ctype, p.packedAttribute()) if gccResult != "void" && (len(fntype.Results.List) > 1 || len(fntype.Results.List[0].Names) > 1) { fmt.Fprintf(fgcc, "\t%s r;\n", gccResult) @@ -758,20 +800,21 @@ func (p *Package) writeExports(fgo2, fc, fm *os.File) { } fmt.Fprintf(fgcc, "}\n") - // Build the wrapper function compiled by 6c/8c + // Build the wrapper function compiled by gc. goname := exp.Func.Name.Name if fn.Recv != nil { goname = "_cgoexpwrap" + cPrefix + "_" + fn.Recv.List[0].Names[0].Name + "_" + goname } - fmt.Fprintf(fc, "#pragma cgo_export_dynamic %s\n", goname) - fmt.Fprintf(fc, "extern void ·%s();\n\n", goname) - fmt.Fprintf(fc, "#pragma cgo_export_static _cgoexp%s_%s\n", cPrefix, exp.ExpName) - 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) - fmt.Fprintf(fc, "}\n") + fmt.Fprintf(fgo2, "//go:cgo_export_dynamic %s\n", goname) + fmt.Fprintf(fgo2, "//go:linkname _cgoexp%s_%s _cgoexp%s_%s\n", cPrefix, exp.ExpName, cPrefix, exp.ExpName) + fmt.Fprintf(fgo2, "//go:cgo_export_static _cgoexp%s_%s\n", cPrefix, exp.ExpName) + fmt.Fprintf(fgo2, "//go:nosplit\n") // no split stack, so no use of m or g + fmt.Fprintf(fgo2, "//go:norace\n") // must not have race detector calls inserted + fmt.Fprintf(fgo2, "func _cgoexp%s_%s(a unsafe.Pointer, n int32) {", cPrefix, exp.ExpName) + fmt.Fprintf(fgo2, "\tfn := %s\n", goname) + // The indirect here is converting from a Go function pointer to a C function pointer. + fmt.Fprintf(fgo2, "\t_cgo_runtime_cgocallback(**(**unsafe.Pointer)(unsafe.Pointer(&fn)), a, uintptr(n));\n") + fmt.Fprintf(fgo2, "}\n") fmt.Fprintf(fm, "int _cgoexp%s_%s;\n", cPrefix, exp.ExpName) @@ -814,23 +857,20 @@ func (p *Package) writeExports(fgo2, fc, fm *os.File) { fmt.Fprint(fgo2, "}\n") } } + + fmt.Fprintf(fgcch, "%s", gccExportHeaderEpilog) } // 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") - +func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) { gccgoSymbolPrefix := p.gccgoSymbolPrefix() - fmt.Fprintf(fgcch, "/* Created by cgo - DO NOT EDIT. */\n") - fmt.Fprintf(fgcch, "%s\n", p.Preamble) - fmt.Fprintf(fgcch, "%s\n", p.gccExportHeaderProlog()) + p.writeExportHeader(fgcch) fmt.Fprintf(fgcc, "/* Created by cgo - DO NOT EDIT. */\n") fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n") - fmt.Fprintf(fm, "#include \"_cgo_export.h\"\n") + fmt.Fprintf(fgcc, "%s\n", gccgoExportFileProlog) for _, exp := range p.ExpFunc { fn := exp.Func @@ -851,6 +891,7 @@ func (p *Package) writeGccgoExports(fgo2, fc, fm *os.File) { }) default: // Declare a result struct. + fmt.Fprintf(fgcch, "\n/* Return type for %s */\n", exp.ExpName) fmt.Fprintf(fgcch, "struct %s_result {\n", exp.ExpName) forFieldList(fntype.Results, func(i int, atype ast.Expr) { @@ -880,6 +921,10 @@ func (p *Package) writeGccgoExports(fgo2, fc, fm *os.File) { fmt.Fprintf(cdeclBuf, ")") cParams := cdeclBuf.String() + if len(exp.Doc) > 0 { + fmt.Fprintf(fgcch, "\n%s", exp.Doc) + } + // We need to use a name that will be exported by the // Go code; otherwise gccgo will make it static and we // will not be able to link against it from the C @@ -900,6 +945,8 @@ func (p *Package) writeGccgoExports(fgo2, fc, fm *os.File) { fmt.Fprint(fgcc, "\n") fmt.Fprintf(fgcc, "%s %s %s {\n", cRet, exp.ExpName, cParams) + fmt.Fprintf(fgcc, "\tif(_cgo_wait_runtime_init_done)\n") + fmt.Fprintf(fgcc, "\t\t_cgo_wait_runtime_init_done();\n") fmt.Fprint(fgcc, "\t") if resultCount > 0 { fmt.Fprint(fgcc, "return ") @@ -919,7 +966,8 @@ func (p *Package) writeGccgoExports(fgo2, fc, fm *os.File) { fmt.Fprint(fgcc, "}\n") // Dummy declaration for _cgo_main.c - fmt.Fprintf(fm, "%s %s %s {}\n", cRet, goName, cParams) + fmt.Fprintf(fm, `char %s[1] __asm__("%s.%s");`, goName, gccgoSymbolPrefix, goName) + fmt.Fprint(fm, "\n") // For gccgo we use a wrapper function in Go, in order // to call CgocallBack and CgocallBackDone. @@ -974,6 +1022,24 @@ func (p *Package) writeGccgoExports(fgo2, fc, fm *os.File) { fmt.Fprint(fgo2, ")\n") fmt.Fprint(fgo2, "}\n") } + + fmt.Fprintf(fgcch, "%s", gccExportHeaderEpilog) +} + +// writeExportHeader writes out the start of the _cgo_export.h file. +func (p *Package) writeExportHeader(fgcch io.Writer) { + fmt.Fprintf(fgcch, "/* Created by \"go tool cgo\" - DO NOT EDIT. */\n\n") + pkg := *importPath + if pkg == "" { + pkg = p.PackagePath + } + fmt.Fprintf(fgcch, "/* package %s */\n\n", pkg) + + fmt.Fprintf(fgcch, "/* Start of preamble from import \"C\" comments. */\n\n") + fmt.Fprintf(fgcch, "%s\n", p.Preamble) + fmt.Fprintf(fgcch, "\n/* End of preamble from import \"C\" comments. */\n\n") + + fmt.Fprintf(fgcch, "%s\n", p.gccExportHeaderProlog()) } // Return the package prefix when using gccgo. @@ -1164,60 +1230,39 @@ char *CString(_GoString_); void *_CMalloc(size_t); ` -const cProlog = ` -#include "runtime.h" -#include "cgocall.h" -#include "textflag.h" - -#pragma dataflag NOPTR -static void *cgocall_errno = runtime·cgocall_errno; -#pragma dataflag NOPTR -void *·_cgo_runtime_cgocall_errno = &cgocall_errno; - -#pragma dataflag NOPTR -static void *runtime_gostring = runtime·gostring; -#pragma dataflag NOPTR -void *·_cgo_runtime_gostring = &runtime_gostring; - -#pragma dataflag NOPTR -static void *runtime_gostringn = runtime·gostringn; -#pragma dataflag NOPTR -void *·_cgo_runtime_gostringn = &runtime_gostringn; - -#pragma dataflag NOPTR -static void *runtime_gobytes = runtime·gobytes; -#pragma dataflag NOPTR -void *·_cgo_runtime_gobytes = &runtime_gobytes; - -#pragma dataflag NOPTR -static void *runtime_cmalloc = runtime·cmalloc; -#pragma dataflag NOPTR -void *·_cgo_runtime_cmalloc = &runtime_cmalloc; - -void ·_Cerrno(void*, int32); -` - const goProlog = ` -var _cgo_runtime_cgocall_errno func(unsafe.Pointer, uintptr) int32 -var _cgo_runtime_cmalloc func(uintptr) unsafe.Pointer +//go:linkname _cgo_runtime_cgocall runtime.cgocall +func _cgo_runtime_cgocall(unsafe.Pointer, uintptr) int32 + +//go:linkname _cgo_runtime_cmalloc runtime.cmalloc +func _cgo_runtime_cmalloc(uintptr) unsafe.Pointer + +//go:linkname _cgo_runtime_cgocallback runtime.cgocallback +func _cgo_runtime_cgocallback(unsafe.Pointer, unsafe.Pointer, uintptr) ` const goStringDef = ` -var _cgo_runtime_gostring func(*_Ctype_char) string +//go:linkname _cgo_runtime_gostring runtime.gostring +func _cgo_runtime_gostring(*_Ctype_char) string + func _Cfunc_GoString(p *_Ctype_char) string { return _cgo_runtime_gostring(p) } ` const goStringNDef = ` -var _cgo_runtime_gostringn func(*_Ctype_char, int) string +//go:linkname _cgo_runtime_gostringn runtime.gostringn +func _cgo_runtime_gostringn(*_Ctype_char, int) string + func _Cfunc_GoStringN(p *_Ctype_char, l _Ctype_int) string { return _cgo_runtime_gostringn(p, int(l)) } ` const goBytesDef = ` -var _cgo_runtime_gobytes func(unsafe.Pointer, int) []byte +//go:linkname _cgo_runtime_gobytes runtime.gobytes +func _cgo_runtime_gobytes(unsafe.Pointer, int) []byte + func _Cfunc_GoBytes(p unsafe.Pointer, l _Ctype_int) []byte { return _cgo_runtime_gobytes(p, int(l)) } @@ -1310,6 +1355,11 @@ func (p *Package) gccExportHeaderProlog() string { } const gccExportHeaderProlog = ` +/* Start of boilerplate cgo prologue. */ + +#ifndef GO_CGO_PROLOGUE_H +#define GO_CGO_PROLOGUE_H + typedef signed char GoInt8; typedef unsigned char GoUint8; typedef short GoInt16; @@ -1326,9 +1376,44 @@ typedef double GoFloat64; typedef __complex float GoComplex64; typedef __complex double GoComplex128; +// static assertion to make sure the file is being used on architecture +// at least with matching size of GoInt. +typedef char _check_for_GOINTBITS_bit_pointer_matching_GoInt[sizeof(void*)==GOINTBITS/8 ? 1:-1]; + typedef struct { char *p; GoInt n; } GoString; typedef void *GoMap; typedef void *GoChan; typedef struct { void *t; void *v; } GoInterface; typedef struct { void *data; GoInt len; GoInt cap; } GoSlice; + +#endif + +/* End of boilerplate cgo prologue. */ + +#ifdef __cplusplus +extern "C" { +#endif +` + +// gccExportHeaderEpilog goes at the end of the generated header file. +const gccExportHeaderEpilog = ` +#ifdef __cplusplus +} +#endif +` + +// gccgoExportFileProlog is written to the _cgo_export.c file when +// using gccgo. +// We use weak declarations, and test the addresses, so that this code +// works with older versions of gccgo. +const gccgoExportFileProlog = ` +extern _Bool runtime_iscgo __attribute__ ((weak)); + +static void GoInit(void) __attribute__ ((constructor)); +static void GoInit(void) { + if(&runtime_iscgo) + runtime_iscgo = 1; +} + +extern void _cgo_wait_runtime_init_done() __attribute__ ((weak)); ` diff --git a/libgo/go/cmd/cgo/util.go b/libgo/go/cmd/cgo/util.go index 4e7800d1272..3adb8e87836 100644 --- a/libgo/go/cmd/cgo/util.go +++ b/libgo/go/cmd/cgo/util.go @@ -55,7 +55,7 @@ func error_(pos token.Pos, msg string, args ...interface{}) { fmt.Fprintf(os.Stderr, "\n") } -// isName returns true if s is a valid C identifier +// isName reports whether s is a valid C identifier func isName(s string) bool { for i, v := range s { if v != '_' && (v < 'A' || v > 'Z') && (v < 'a' || v > 'z') && (v < '0' || v > '9') { diff --git a/libgo/go/cmd/go/alldocs.go b/libgo/go/cmd/go/alldocs.go new file mode 100644 index 00000000000..6077d93a436 --- /dev/null +++ b/libgo/go/cmd/go/alldocs.go @@ -0,0 +1,1482 @@ +// 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. + +// DO NOT EDIT THIS FILE. GENERATED BY mkalldocs.sh. +// Edit the documentation in other files and rerun mkalldocs.sh to generate this one. + +/* +Go is a tool for managing Go source code. + +Usage: + + go command [arguments] + +The commands are: + + build compile packages and dependencies + clean remove object files + doc show documentation for package or symbol + env print Go environment information + fix run go tool fix on packages + fmt run gofmt on package sources + generate generate Go files by processing source + get download and install packages and dependencies + install compile and install packages and dependencies + list list packages + run compile and run Go program + test test packages + tool run specified go tool + version print Go version + vet run go tool vet on packages + +Use "go help [command]" for more information about a command. + +Additional help topics: + + c calling between Go and C + buildmode description of build modes + filetype file types + gopath GOPATH environment variable + environment environment variables + importpath import path syntax + packages description of package lists + testflag description of testing flags + testfunc description of testing functions + +Use "go help [topic]" for more information about that topic. + + +Compile packages and dependencies + +Usage: + + go build [-o output] [-i] [build flags] [packages] + +Build compiles the packages named by the import paths, +along with their dependencies, but it does not install the results. + +If the arguments to build are a list of .go files, build treats +them as a list of source files specifying a single package. + +When compiling a single main package, build writes +the resulting executable to an output file named after +the first source file ('go build ed.go rx.go' writes 'ed' or 'ed.exe') +or the source code directory ('go build unix/sam' writes 'sam' or 'sam.exe'). +The '.exe' suffix is added when writing a Windows executable. + +When compiling multiple packages or a single non-main package, +build compiles the packages but discards the resulting object, +serving only as a check that the packages can be built. + +The -o flag, only allowed when compiling a single package, +forces build to write the resulting executable or object +to the named output file, instead of the default behavior described +in the last two paragraphs. + +The -i flag installs the packages that are dependencies of the target. + +The build flags are shared by the build, clean, get, install, list, run, +and test commands: + + -a + force rebuilding of packages that are already up-to-date. + In Go releases, does not apply to the standard library. + -n + print the commands but do not run them. + -p n + the number of builds that can be run in parallel. + The default is the number of CPUs available, except + on darwin/arm which defaults to 1. + -race + enable data race detection. + Supported only on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64. + -v + print the names of packages as they are compiled. + -work + print the name of the temporary work directory and + do not delete it when exiting. + -x + print the commands. + + -asmflags 'flag list' + arguments to pass on each go tool asm invocation. + -buildmode mode + build mode to use. See 'go help buildmode' for more. + -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' + arguments to pass on each go tool compile invocation. + -installsuffix suffix + a suffix to use in the name of the package installation directory, + in order to keep output separate from default builds. + If using the -race flag, the install suffix is automatically set to race + or, if set explicitly, has _race appended to it. Using a -buildmode + option that requires non-default compile flags has a similar effect. + -ldflags 'flag list' + arguments to pass on each go tool link invocation. + -linkshared + link against shared libraries previously created with + -buildmode=shared + -pkgdir dir + install and load all packages from dir instead of the usual locations. + For example, when building with a non-standard configuration, + use -pkgdir to keep generated packages in a separate location. + -tags 'tag list' + a list of build tags to consider satisfied during the build. + For more information about build tags, see the description of + build constraints in the documentation for the go/build package. + -toolexec 'cmd args' + a program to use to invoke toolchain programs like vet and asm. + For example, instead of running asm, the go command will run + 'cmd args /path/to/asm '. + +The list flags accept a space-separated list of strings. To embed spaces +in an element in the list, surround it with either single or double quotes. + +For more about specifying packages, see 'go help packages'. +For more about where packages and binaries are installed, +run 'go help gopath'. +For more about calling between Go and C/C++, run 'go help c'. + +Note: Build adheres to certain conventions such as those described +by 'go help gopath'. Not all projects can follow these conventions, +however. Installations that have their own conventions or that use +a separate software build system may choose to use lower-level +invocations such as 'go tool compile' and 'go tool link' to avoid +some of the overheads and design decisions of the build tool. + +See also: go install, go get, go clean. + + +Remove object files + +Usage: + + go clean [-i] [-r] [-n] [-x] [build flags] [packages] + +Clean removes object files from package source directories. +The go command builds most objects in a temporary directory, +so go clean is mainly concerned with object files left by other +tools or by manual invocations of go build. + +Specifically, clean removes the following files from each of the +source directories corresponding to the import paths: + + _obj/ old object directory, left from Makefiles + _test/ old test directory, left from Makefiles + _testmain.go old gotest file, left from Makefiles + test.out old test log, left from Makefiles + build.out old test log, left from Makefiles + *.[568ao] object files, left from Makefiles + + DIR(.exe) from go build + DIR.test(.exe) from go test -c + MAINFILE(.exe) from go build MAINFILE.go + *.so from SWIG + +In the list, DIR represents the final path element of the +directory, and MAINFILE is the base name of any Go source +file in the directory that is not included when building +the package. + +The -i flag causes clean to remove the corresponding installed +archive or binary (what 'go install' would create). + +The -n flag causes clean to print the remove commands it would execute, +but not run them. + +The -r flag causes clean to be applied recursively to all the +dependencies of the packages named by the import paths. + +The -x flag causes clean to print remove commands as it executes them. + +For more about build flags, see 'go help build'. + +For more about specifying packages, see 'go help packages'. + + +Show documentation for package or symbol + +Usage: + + go doc [-u] [-c] [package|[package.]symbol[.method]] + +Doc prints the documentation comments associated with the item identified by its +arguments (a package, const, func, type, var, or method) followed by a one-line +summary of each of the first-level items "under" that item (package-level +declarations for a package, methods for a type, etc.). + +Doc accepts zero, one, or two arguments. + +Given no arguments, that is, when run as + + go doc + +it prints the package documentation for the package in the current directory. +If the package is a command (package main), the exported symbols of the package +are elided from the presentation unless the -cmd flag is provided. + +When run with one argument, the argument is treated as a Go-syntax-like +representation of the item to be documented. What the argument selects depends +on what is installed in GOROOT and GOPATH, as well as the form of the argument, +which is schematically one of these: + + go doc + go doc [.] + go doc [].[.] + +The first item in this list matched by the argument is the one whose +documentation is printed. (See the examples below.) For packages, the order of +scanning is determined lexically, but the GOROOT tree is always scanned before +GOPATH. + +If there is no package specified or matched, the package in the current +directory is selected, so "go doc Foo" shows the documentation for symbol Foo in +the current package. + +The package path must be either a qualified path or a proper suffix of a +path. The go tool's usual package mechanism does not apply: package path +elements like . and ... are not implemented by go doc. + +When run with two arguments, the first must be a full package path (not just a +suffix), and the second is a symbol or symbol and method; this is similar to the +syntax accepted by godoc: + + go doc [.] + +In all forms, when matching symbols, lower-case letters in the argument match +either case but upper-case letters match exactly. This means that there may be +multiple matches of a lower-case argument in a package if different symbols have +different cases. If this occurs, documentation for all matches is printed. + +Examples: + go doc + Show documentation for current package. + go doc Foo + Show documentation for Foo in the current package. + (Foo starts with a capital letter so it cannot match + a package path.) + go doc encoding/json + Show documentation for the encoding/json package. + go doc json + Shorthand for encoding/json. + go doc json.Number (or go doc json.number) + Show documentation and method summary for json.Number. + go doc json.Number.Int64 (or go doc json.number.int64) + Show documentation for json.Number's Int64 method. + go doc cmd/doc + Show package docs for the doc command. + go doc -cmd cmd/doc + Show package docs and exported symbols within the doc command. + go doc template.new + Show documentation for html/template's New function. + (html/template is lexically before text/template) + go doc text/template.new # One argument + Show documentation for text/template's New function. + go doc text/template new # Two arguments + Show documentation for text/template's New function. + +Flags: + -c + Respect case when matching symbols. + -cmd + Treat a command (package main) like a regular package. + Otherwise package main's exported symbols are hidden + when showing the package's top-level documentation. + -u + Show documentation for unexported as well as exported + symbols and methods. + + +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: + + go fix [packages] + +Fix runs the Go fix command on the packages named by the import paths. + +For more about fix, see 'go doc cmd/fix'. +For more about specifying packages, see 'go help packages'. + +To run fix with specific options, run 'go tool fix'. + +See also: go fmt, go vet. + + +Run gofmt on package sources + +Usage: + + go fmt [-n] [-x] [packages] + +Fmt runs the command 'gofmt -l -w' on the packages named +by the import paths. It prints the names of the files that are modified. + +For more about gofmt, see 'go doc cmd/gofmt'. +For more about specifying packages, see 'go help packages'. + +The -n flag prints commands that would be executed. +The -x flag prints commands as they are executed. + +To run gofmt with specific options, run gofmt itself. + +See also: go fix, go vet. + + +Generate Go files by processing source + +Usage: + + go generate [-run regexp] [file.go... | packages] + +Generate runs commands described by directives within existing +files. Those commands can run any process but the intent is to +create or update Go source files, for instance by running yacc. + +Go generate is never run automatically by go build, go get, go test, +and so on. It must be run explicitly. + +Go generate scans the file for directives, which are lines of +the form, + + //go:generate command argument... + +(note: no leading spaces and no space in "//go") where command +is the generator to be run, corresponding to an executable file +that can be run locally. It must either be in the shell path +(gofmt), a fully qualified path (/usr/you/bin/mytool), or a +command alias, described below. + +Note that go generate does not parse the file, so lines that look +like directives in comments or multiline strings will be treated +as directives. + +The arguments to the directive are space-separated tokens or +double-quoted strings passed to the generator as individual +arguments when it is run. + +Quoted strings use Go syntax and are evaluated before execution; a +quoted string appears as a single argument to the generator. + +Go generate sets several variables when it runs the generator: + + $GOARCH + The execution architecture (arm, amd64, etc.) + $GOOS + The execution operating system (linux, windows, etc.) + $GOFILE + The base name of the file. + $GOLINE + The line number of the directive in the source file. + $GOPACKAGE + The name of the package of the file containing the directive. + $DOLLAR + A dollar sign. + +Other than variable substitution and quoted-string evaluation, no +special processing such as "globbing" is performed on the command +line. + +As a last step before running the command, any invocations of any +environment variables with alphanumeric names, such as $GOFILE or +$HOME, are expanded throughout the command line. The syntax for +variable expansion is $NAME on all operating systems. Due to the +order of evaluation, variables are expanded even inside quoted +strings. If the variable NAME is not set, $NAME expands to the +empty string. + +A directive of the form, + + //go:generate -command xxx args... + +specifies, for the remainder of this source file only, that the +string xxx represents the command identified by the arguments. This +can be used to create aliases or to handle multiword generators. +For example, + + //go:generate -command yacc go tool yacc + +specifies that the command "yacc" represents the generator +"go tool yacc". + +Generate processes packages in the order given on the command line, +one at a time. If the command line lists .go files, they are treated +as a single package. Within a package, generate processes the +source files in a package in file name order, one at a time. Within +a source file, generate runs generators in the order they appear +in the file, one at a time. + +If any generator returns an error exit status, "go generate" skips +all further processing for that package. + +The generator is run in the package's source directory. + +Go generate accepts one specific flag: + + -run="" + if non-empty, specifies a regular expression to select + directives whose full original source text (excluding + any trailing spaces and final newline) matches the + expression. + +It also accepts the standard build flags -v, -n, and -x. +The -v flag prints the names of packages and files as they are +processed. +The -n flag prints commands that would be executed. +The -x flag prints commands as they are executed. + +For more about specifying packages, see 'go help packages'. + + +Download and install packages and dependencies + +Usage: + + go get [-d] [-f] [-fix] [-insecure] [-t] [-u] [build flags] [packages] + +Get downloads and installs the packages named by the import paths, +along with their dependencies. + +The -d flag instructs get to stop after downloading the packages; that is, +it instructs get not to install the packages. + +The -f flag, valid only when -u is set, forces get -u not to verify that +each package has been checked out from the source control repository +implied by its import path. This can be useful if the source is a local fork +of the original. + +The -fix flag instructs get to run the fix tool on the downloaded packages +before resolving dependencies or building the code. + +The -insecure flag permits fetching from repositories and resolving +custom domains using insecure schemes such as HTTP. Use with caution. + +The -t flag instructs get to also download the packages required to build +the tests for the specified packages. + +The -u flag instructs get to use the network to update the named packages +and their dependencies. By default, get uses the network to check out +missing packages but does not use it to look for updates to existing packages. + +Get also accepts build flags to control the installation. See 'go help build'. + +When checking out or updating a package, get looks for a branch or tag +that matches the locally installed version of Go. The most important +rule is that if the local installation is running version "go1", get +searches for a branch or tag named "go1". If no such version exists it +retrieves the most recent version of the package. + +If the vendoring experiment is enabled (see 'go help gopath'), +then when go get checks out or updates a Git repository, +it also updates any git submodules referenced by the repository. + +For more about specifying packages, see 'go help packages'. + +For more about how 'go get' finds source code to +download, see 'go help importpath'. + +See also: go build, go install, go clean. + + +Compile and install packages and dependencies + +Usage: + + go install [build flags] [packages] + +Install compiles and installs the packages named by the import paths, +along with their dependencies. + +For more about the build flags, see 'go help build'. +For more about specifying packages, see 'go help packages'. + +See also: go build, go get, go clean. + + +List packages + +Usage: + + go list [-e] [-f format] [-json] [build flags] [packages] + +List lists the packages named by the import paths, one per line. + +The default output shows the package import path: + + bytes + encoding/json + github.com/gorilla/mux + golang.org/x/net/html + +The -f flag specifies an alternate format for the list, using the +syntax of package template. The default output is equivalent to -f +'{{.ImportPath}}'. The struct being passed to the template is: + + type Package struct { + Dir string // directory containing package sources + ImportPath string // import path of package in dir + ImportComment string // path in import comment on package statement + Name string // package name + Doc string // package documentation string + Target string // install path + Shlib string // the shared library that contains this package (only set when -linkshared) + Goroot bool // is this package in the Go root? + Standard bool // is this package part of the standard Go library? + Stale bool // would 'go install' do anything for this package? + Root string // Go root or Go path dir containing this package + + // Source files + GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles) + CgoFiles []string // .go sources files that import "C" + IgnoredGoFiles []string // .go sources ignored due to build constraints + CFiles []string // .c source files + CXXFiles []string // .cc, .cxx and .cpp source files + MFiles []string // .m source files + HFiles []string // .h, .hh, .hpp and .hxx source files + SFiles []string // .s source files + SwigFiles []string // .swig files + SwigCXXFiles []string // .swigcxx files + SysoFiles []string // .syso object files to add to archive + + // Cgo directives + CgoCFLAGS []string // cgo: flags for C compiler + CgoCPPFLAGS []string // cgo: flags for C preprocessor + CgoCXXFLAGS []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 + 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 template function "join" calls strings.Join. + +The template function "context" returns the build context, defined as: + + type Context struct { + GOARCH string // target architecture + GOOS string // target operating system + GOROOT string // Go root + GOPATH string // Go path + CgoEnabled bool // whether cgo can be used + UseAllFiles bool // use files regardless of +build lines, file names + Compiler string // compiler to assume when computing target paths + BuildTags []string // build constraints to match in +build lines + ReleaseTags []string // releases the current release is compatible with + InstallSuffix string // suffix to use in the name of the install dir + } + +For more information about the meaning of these fields see the documentation +for the go/build package's Context type. + +The -json flag causes the package data to be printed in JSON format +instead of using the template format. + +The -e flag changes the handling of erroneous packages, those that +cannot be found or are malformed. By default, the list command +prints an error to standard error for each erroneous package and +omits the packages from consideration during the usual printing. +With the -e flag, the list command never prints errors to standard +error and instead processes the erroneous packages with the usual +printing. Erroneous packages will have a non-empty ImportPath and +a non-nil Error field; other information may or may not be missing +(zeroed). + +For more about build flags, see 'go help build'. + +For more about specifying packages, see 'go help packages'. + + +Compile and run Go program + +Usage: + + go run [build flags] [-exec xprog] gofiles... [arguments...] + +Run compiles and runs the main package comprising the named Go source files. +A Go source file is defined to be a file ending in a literal ".go" suffix. + +By default, 'go run' runs the compiled binary directly: 'a.out arguments...'. +If the -exec flag is given, 'go run' invokes the binary using xprog: + 'xprog a.out arguments...'. +If the -exec flag is not given, GOOS or GOARCH is different from the system +default, and a program named go_$GOOS_$GOARCH_exec can be found +on the current search path, 'go run' invokes the binary using that program, +for example 'go_nacl_386_exec a.out arguments...'. This allows execution of +cross-compiled programs when a simulator or other execution method is +available. + +For more about build flags, see 'go help build'. + +See also: go build. + + +Test packages + +Usage: + + go test [-c] [-i] [build and test flags] [packages] [flags for test binary] + +'Go test' automates testing the packages named by the import paths. +It prints a summary of the test results in the format: + + ok archive/tar 0.011s + FAIL archive/zip 0.022s + ok compress/gzip 0.033s + ... + +followed by detailed output for each failed package. + +'Go test' recompiles each package along with any files with names matching +the file pattern "*_test.go". +Files whose names begin with "_" (including "_test.go") or "." are ignored. +These additional files can contain test functions, benchmark functions, and +example functions. See 'go help testfunc' for more. +Each listed package causes the execution of a separate test binary. + +Test files that declare a package with the suffix "_test" will be compiled as a +separate package, and then linked and run with the main test binary. + +By default, go test needs no arguments. It compiles and tests the package +with source in the current directory, including tests, and runs the tests. + +The package is built in a temporary directory so it does not interfere with the +non-test installation. + +In addition to the build flags, the flags handled by 'go test' itself are: + + -c + Compile the test binary to pkg.test but do not run it + (where pkg is the last element of the package's import path). + The file name can be changed with the -o flag. + + -exec xprog + Run the test binary using xprog. The behavior is the same as + in 'go run'. See 'go help run' for details. + + -i + Install packages that are dependencies of the test. + Do not run the test. + + -o file + Compile the test binary to the named file. + The test still runs (unless -c or -i is specified). + +The test binary also accepts flags that control execution of the test; these +flags are also accessible by 'go test'. See 'go help testflag' for details. + +If the test binary needs any other flags, they should be presented after the +package names. The go tool treats as a flag the first argument that begins with +a minus sign that it does not recognize itself; that argument and all subsequent +arguments are passed as arguments to the test binary. + +For more about build flags, see 'go help build'. +For more about specifying packages, see 'go help packages'. + +See also: go build, go vet. + + +Run specified go tool + +Usage: + + go tool [-n] command [args...] + +Tool runs the go tool command identified by the arguments. +With no arguments it prints the list of known tools. + +The -n flag causes tool to print the command that would be +executed but not execute it. + +For more about each tool command, see 'go tool command -h'. + + +Print Go version + +Usage: + + go version + +Version prints the Go version, as reported by runtime.Version. + + +Run go tool vet on packages + +Usage: + + go vet [-n] [-x] [build flags] [packages] + +Vet runs the Go vet command on the packages named by the import paths. + +For more about vet, see 'go doc cmd/vet'. +For more about specifying packages, see 'go help packages'. + +To run the vet tool with specific options, run 'go tool vet'. + +The -n flag prints commands that would be executed. +The -x flag prints commands as they are executed. + +For more about build flags, see 'go help build'. + +See also: go fmt, go fix. + + +Calling between Go and C + +There are two different ways to call between Go and C/C++ code. + +The first is the cgo tool, which is part of the Go distribution. For +information on how to use it see the cgo documentation (go doc cmd/cgo). + +The second is the SWIG program, which is a general tool for +interfacing between languages. For information on SWIG see +http://swig.org/. When running go build, any file with a .swig +extension will be passed to SWIG. Any file with a .swigcxx extension +will be passed to SWIG with the -c++ option. + +When either cgo or SWIG is used, go build will pass any .c, .m, .s, +or .S files to the C compiler, and any .cc, .cpp, .cxx files to the C++ +compiler. The CC or CXX environment variables may be set to determine +the C or C++ compiler, respectively, to use. + + +Description of build modes + +The 'go build' and 'go install' commands take a -buildmode argument which +indicates which kind of object file is to be built. Currently supported values +are: + + -buildmode=archive + Build the listed non-main packages into .a files. Packages named + main are ignored. + + -buildmode=c-archive + Build the listed main package, plus all packages it imports, + into a C archive file. The only callable symbols will be those + functions exported using a cgo //export comment. Requires + exactly one main package to be listed. + + -buildmode=c-shared + Build the listed main packages, plus all packages that they + import, into C shared libraries. The only callable symbols will + be those functions exported using a cgo //export comment. + Non-main packages are ignored. + + -buildmode=default + Listed main packages are built into executables and listed + non-main packages are built into .a files (the default + behavior). + + -buildmode=shared + Combine all the listed non-main packages into a single shared + library that will be used when building with the -linkshared + option. Packages named main are ignored. + + -buildmode=exe + Build the listed main packages and everything they import into + executables. Packages not named main are ignored. + + +File types + +The go command examines the contents of a restricted set of files +in each directory. It identifies which files to examine based on +the extension of the file name. These extensions are: + + .go + Go source files. + .c, .h + C source files. + If the package uses cgo or SWIG, these will be compiled with the + OS-native compiler (typically gcc); otherwise they will + trigger an error. + .cc, .cpp, .cxx, .hh, .hpp, .hxx + C++ source files. Only useful with cgo or SWIG, and always + compiled with the OS-native compiler. + .m + Objective-C source files. Only useful with cgo, and always + compiled with the OS-native compiler. + .s, .S + Assembler source files. + If the package uses cgo or SWIG, these will be assembled with the + OS-native assembler (typically gcc (sic)); otherwise they + will be assembled with the Go assembler. + .swig, .swigcxx + SWIG definition files. + .syso + System object files. + +Files of each of these types except .syso may contain build +constraints, but the go command stops scanning for build constraints +at the first item in the file that is not a blank line or //-style +line comment. + + +GOPATH environment variable + +The Go path is used to resolve import statements. +It is implemented by and documented in the go/build package. + +The GOPATH environment variable lists places to look for Go code. +On Unix, the value is a colon-separated string. +On Windows, the value is a semicolon-separated string. +On Plan 9, the value is a list. + +GOPATH must be set to get, build and install packages outside the +standard Go tree. + +Each directory listed in GOPATH must have a prescribed structure: + +The src directory holds source code. The path below src +determines the import path or executable name. + +The pkg directory holds installed package objects. +As in the Go tree, each target operating system and +architecture pair has its own subdirectory of pkg +(pkg/GOOS_GOARCH). + +If DIR is a directory listed in the GOPATH, a package with +source in DIR/src/foo/bar can be imported as "foo/bar" and +has its compiled form installed to "DIR/pkg/GOOS_GOARCH/foo/bar.a". + +The bin directory holds compiled commands. +Each command is named for its source directory, but only +the final element, not the entire path. That is, the +command with source in DIR/src/foo/quux is installed into +DIR/bin/quux, not DIR/bin/foo/quux. The "foo/" prefix is stripped +so that you can add DIR/bin to your PATH to get at the +installed commands. If the GOBIN environment variable is +set, commands are installed to the directory it names instead +of DIR/bin. + +Here's an example directory layout: + + GOPATH=/home/user/gocode + + /home/user/gocode/ + src/ + foo/ + bar/ (go code in package bar) + x.go + quux/ (go code in package main) + y.go + bin/ + quux (installed command) + pkg/ + linux_amd64/ + foo/ + bar.a (installed package object) + +Go searches each directory listed in GOPATH to find source code, +but new packages are always downloaded into the first directory +in the list. + +See https://golang.org/doc/code.html for an example. + +Internal Directories + +Code in or below a directory named "internal" is importable only +by code in the directory tree rooted at the parent of "internal". +Here's an extended version of the directory layout above: + + /home/user/gocode/ + src/ + crash/ + bang/ (go code in package bang) + b.go + foo/ (go code in package foo) + f.go + bar/ (go code in package bar) + x.go + internal/ + baz/ (go code in package baz) + z.go + quux/ (go code in package main) + y.go + + +The code in z.go is imported as "foo/internal/baz", but that +import statement can only appear in source files in the subtree +rooted at foo. The source files foo/f.go, foo/bar/x.go, and +foo/quux/y.go can all import "foo/internal/baz", but the source file +crash/bang/b.go cannot. + +See https://golang.org/s/go14internal for details. + +Vendor Directories + +Go 1.5 includes experimental support for using local copies +of external dependencies to satisfy imports of those dependencies, +often referred to as vendoring. Setting the environment variable +GO15VENDOREXPERIMENT=1 enables that experimental support. + +When the vendor experiment is enabled, +code below a directory named "vendor" is importable only +by code in the directory tree rooted at the parent of "vendor", +and only using an import path that omits the prefix up to and +including the vendor element. + +Here's the example from the previous section, +but with the "internal" directory renamed to "vendor" +and a new foo/vendor/crash/bang directory added: + + /home/user/gocode/ + src/ + crash/ + bang/ (go code in package bang) + b.go + foo/ (go code in package foo) + f.go + bar/ (go code in package bar) + x.go + vendor/ + crash/ + bang/ (go code in package bang) + b.go + baz/ (go code in package baz) + z.go + quux/ (go code in package main) + y.go + +The same visibility rules apply as for internal, but the code +in z.go is imported as "baz", not as "foo/vendor/baz". + +Code in vendor directories deeper in the source tree shadows +code in higher directories. Within the subtree rooted at foo, an import +of "crash/bang" resolves to "foo/vendor/crash/bang", not the +top-level "crash/bang". + +Code in vendor directories is not subject to import path +checking (see 'go help importpath'). + +When the vendor experiment is enabled, 'go get' checks out +submodules when checking out or updating a git repository +(see 'go help get'). + +The vendoring semantics are an experiment, and they may change +in future releases. Once settled, they will be on by default. + +See https://golang.org/s/go15vendor for details. + + +Environment variables + +The go command, and the tools it invokes, examine a few different +environment variables. For many of these, you can see the default +value of on your system by running 'go env NAME', where NAME is the +name of the variable. + +General-purpose environment variables: + + GCCGO + The gccgo command to run for 'go build -compiler=gccgo'. + GOARCH + The architecture, or processor, for which to compile code. + Examples are amd64, 386, arm, ppc64. + GOBIN + The directory where 'go install' will install a command. + GOOS + The operating system for which to compile code. + Examples are linux, darwin, windows, netbsd. + GOPATH + See 'go help gopath'. + GORACE + Options for the race detector. + See https://golang.org/doc/articles/race_detector.html. + GOROOT + The root of the go tree. + +Environment variables for use with cgo: + + CC + The command to use to compile C code. + CGO_ENABLED + Whether the cgo command is supported. Either 0 or 1. + CGO_CFLAGS + Flags that cgo will pass to the compiler when compiling + C code. + CGO_CPPFLAGS + Flags that cgo will pass to the compiler when compiling + C or C++ code. + CGO_CXXFLAGS + Flags that cgo will pass to the compiler when compiling + C++ code. + CGO_LDFLAGS + Flags that cgo will pass to the compiler when linking. + CXX + The command to use to compile C++ code. + +Architecture-specific environment variables: + + GOARM + For GOARCH=arm, the ARM architecture for which to compile. + Valid values are 5, 6, 7. + GO386 + For GOARCH=386, the floating point instruction set. + Valid values are 387, sse2. + +Special-purpose environment variables: + + GOROOT_FINAL + The root of the installed Go tree, when it is + installed in a location other than where it is built. + File names in stack traces are rewritten from GOROOT to + GOROOT_FINAL. + GO15VENDOREXPERIMENT + Set to 1 to enable the Go 1.5 vendoring experiment. + GO_EXTLINK_ENABLED + Whether the linker should use external linking mode + when using -linkmode=auto with code that uses cgo. + Set to 0 to disable external linking mode, 1 to enable it. + + +Import path syntax + +An import path (see 'go help packages') denotes a package +stored in the local file system. In general, an import path denotes +either a standard package (such as "unicode/utf8") or a package +found in one of the work spaces (see 'go help gopath'). + +Relative import paths + +An import path beginning with ./ or ../ is called a relative path. +The toolchain supports relative import paths as a shortcut in two ways. + +First, a relative path can be used as a shorthand on the command line. +If you are working in the directory containing the code imported as +"unicode" and want to run the tests for "unicode/utf8", you can type +"go test ./utf8" instead of needing to specify the full path. +Similarly, in the reverse situation, "go test .." will test "unicode" from +the "unicode/utf8" directory. Relative patterns are also allowed, like +"go test ./..." to test all subdirectories. See 'go help packages' for details +on the pattern syntax. + +Second, if you are compiling a Go program not in a work space, +you can use a relative path in an import statement in that program +to refer to nearby code also not in a work space. +This makes it easy to experiment with small multipackage programs +outside of the usual work spaces, but such programs cannot be +installed with "go install" (there is no work space in which to install them), +so they are rebuilt from scratch each time they are built. +To avoid ambiguity, Go programs cannot use relative import paths +within a work space. + +Remote import paths + +Certain import paths also +describe how to obtain the source code for the package using +a revision control system. + +A few common code hosting sites have special syntax: + + Bitbucket (Git, Mercurial) + + import "bitbucket.org/user/project" + import "bitbucket.org/user/project/sub/directory" + + GitHub (Git) + + import "github.com/user/project" + import "github.com/user/project/sub/directory" + + Google Code Project Hosting (Git, Mercurial, Subversion) + + import "code.google.com/p/project" + import "code.google.com/p/project/sub/directory" + + import "code.google.com/p/project.subrepository" + import "code.google.com/p/project.subrepository/sub/directory" + + Launchpad (Bazaar) + + import "launchpad.net/project" + import "launchpad.net/project/series" + import "launchpad.net/project/series/sub/directory" + + import "launchpad.net/~user/project/branch" + import "launchpad.net/~user/project/branch/sub/directory" + + IBM DevOps Services (Git) + + import "hub.jazz.net/git/user/project" + import "hub.jazz.net/git/user/project/sub/directory" + +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 tag in the HTML. + +To declare the code location, an import path of the form + + repository.vcs/path + +specifies the given repository, with or without the .vcs suffix, +using the named version control system, and then the path inside +that repository. The supported version control systems are: + + Bazaar .bzr + Git .git + Mercurial .hg + Subversion .svn + +For example, + + import "example.org/user/foo.hg" + +denotes the root directory of the Mercurial repository at +example.org/user/foo or foo.hg, and + + import "example.org/repo.git/foo/bar" + +denotes the foo/bar directory of the Git repository at +example.org/repo or repo.git. + +When a version control system supports multiple protocols, +each is tried in turn when downloading. For example, a Git +download tries https://, then git+ssh://. + +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 tag in the document's HTML +. + +The meta tag has the form: + + + +The import-prefix is the import path corresponding 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 tags match. + +The meta tag should appear as early in the file as possible. +In particular, it should appear before any raw JavaScript or CSS, +to avoid confusing the go command's restricted parser. + +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 requests: + + https://example.org/pkg/foo?go-get=1 (preferred) + http://example.org/pkg/foo?go-get=1 (fallback, only with -insecure) + +If that page contains the meta tag + + + +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'). + +The go command attempts to download the version of the +package appropriate for the Go release being used. +Run 'go help get' for more. + +Import path checking + +When the custom import path feature described above redirects to a +known code hosting site, each of the resulting packages has two possible +import paths, using the custom domain or the known hosting site. + +A package statement is said to have an "import comment" if it is immediately +followed (before the next newline) by a comment of one of these two forms: + + package math // import "path" + package math /* import "path" * / + +The go command will refuse to install a package with an import comment +unless it is being referred to by that import path. In this way, import comments +let package authors make sure the custom import path is used and not a +direct path to the underlying code hosting site. + +If the vendoring experiment is enabled (see 'go help gopath'), +then import path checking is disabled for code found within vendor trees. +This makes it possible to copy code into alternate locations in vendor trees +without needing to update import comments. + +See https://golang.org/s/go14customimport for details. + + +Description of package lists + +Many commands apply to a set of packages: + + go action [packages] + +Usually, [packages] is a list of import paths. + +An import path that is a rooted path or that begins with +a . or .. element is interpreted as a file system path and +denotes the package in that directory. + +Otherwise, the import path P denotes the package found in +the directory DIR/src/P for some DIR listed in the GOPATH +environment variable (see 'go help gopath'). + +If no import paths are given, the action applies to the +package in the current directory. + +There are four reserved names for paths that should not be used +for packages to be built with the go tool: + +- "main" denotes the top-level package in a stand-alone executable. + +- "all" expands to all package directories found in all the GOPATH +trees. For example, 'go list all' lists all the packages on the local +system. + +- "std" is like all but expands to just the packages in the standard +Go library. + +- "cmd" expands to the Go repository's commands and their +internal libraries. + +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. 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 importpath' for details. + +Every package in a program must have a unique import path. +By convention, this is arranged by starting each path with a +unique prefix that belongs to you. For example, paths used +internally at Google all begin with 'google', and paths +denoting remote repositories begin with the path to the code, +such as 'github.com/user/repo'. + +As a special case, if the package list is a list of .go files from a +single directory, the command is applied to a single synthesized +package made up of exactly those files, ignoring any build constraints +in those files and ignoring any other files in the directory. + +Directory and file names that begin with "." or "_" are ignored +by the go tool, as are directories named "testdata". + + +Description of testing flags + +The 'go test' command takes both flags that apply to 'go test' itself +and flags that apply to the resulting test binary. + +Several of the flags control profiling and write an execution profile +suitable for "go tool pprof"; run "go tool pprof -h" for more +information. The --alloc_space, --alloc_objects, and --show_bytes +options of pprof control how the information is presented. + +The following flags are recognized by the 'go test' command and +control the execution of any test: + + -bench regexp + Run benchmarks matching the regular expression. + By default, no benchmarks run. To run all benchmarks, + use '-bench .' or '-bench=.'. + + -benchmem + Print memory allocation statistics for benchmarks. + + -benchtime t + Run enough iterations of each benchmark to take t, specified + as a time.Duration (for example, -benchtime 1h30s). + The default is 1 second (1s). + + -blockprofile block.out + Write a goroutine blocking profile to the specified file + when all tests are complete. + Writes test binary as -c would. + + -blockprofilerate n + Control the detail provided in goroutine blocking profiles by + calling runtime.SetBlockProfileRate with n. + See 'go doc runtime.SetBlockProfileRate'. + The profiler aims to sample, on average, one blocking event every + n nanoseconds the program spends blocked. By default, + if -test.blockprofile is set without this flag, all blocking events + are recorded, equivalent to -test.blockprofilerate=1. + + -count n + Run each test and benchmark n times (default 1). + If -cpu is set, run n times for each GOMAXPROCS value. + Examples are always run once. + + -cover + Enable coverage analysis. + + -covermode set,count,atomic + Set the mode for coverage analysis for the package[s] + being tested. The default is "set" unless -race is enabled, + in which case it is "atomic". + The values: + set: bool: does this statement run? + count: int: how many times does this statement run? + atomic: int: count, but correct in multithreaded tests; + significantly more expensive. + Sets -cover. + + -coverpkg pkg1,pkg2,pkg3 + Apply coverage analysis in each test to the given list of packages. + The default is for each test to analyze only the package being tested. + Packages are specified as import paths. + Sets -cover. + + -coverprofile cover.out + Write a coverage profile to the file after all tests have passed. + Sets -cover. + + -cpu 1,2,4 + Specify a list of GOMAXPROCS values for which the tests or + benchmarks should be executed. The default is the current value + of GOMAXPROCS. + + -cpuprofile cpu.out + Write a CPU profile to the specified file before exiting. + Writes test binary as -c would. + + -memprofile mem.out + Write a memory profile to the file after all tests have passed. + Writes test binary as -c would. + + -memprofilerate n + Enable more precise (and expensive) memory profiles by setting + runtime.MemProfileRate. See 'go doc runtime.MemProfileRate'. + To profile all memory allocations, use -test.memprofilerate=1 + and pass --alloc_space flag to the pprof tool. + + -outputdir directory + Place output files from profiling in the specified directory, + by default the directory in which "go test" is running. + + -parallel n + Allow parallel execution of test functions that call t.Parallel. + The value of this flag is the maximum number of tests to run + simultaneously; by default, it is set to the value of GOMAXPROCS. + + -run regexp + Run only those tests and examples matching the regular + expression. + + -short + Tell long-running tests to shorten their run time. + It is off by default but set during all.bash so that installing + the Go tree can run a sanity check but not spend time running + exhaustive tests. + + -timeout t + If a test runs longer than t, panic. + The default is 10 minutes (10m). + + -trace trace.out + Write an execution trace to the specified file before exiting. + Writes test binary as -c would. + + -v + Verbose output: log all tests as they are run. Also print all + text from Log and Logf calls even if the test succeeds. + +The test binary, called pkg.test where pkg is the name of the +directory containing the package sources, can be invoked directly +after building it with 'go test -c'. When invoking the test binary +directly, each of the standard flag names must be prefixed with 'test.', +as in -test.run=TestMyFunc or -test.v. + +When running 'go test', flags not listed above are passed through +unaltered. For instance, the command + + go test -x -v -cpuprofile=prof.out -dir=testdata -update + +will compile the test binary and then run it as + + pkg.test -test.v -test.cpuprofile=prof.out -dir=testdata -update + +The test flags that generate profiles (other than for coverage) also +leave the test binary in pkg.test for use when analyzing the profiles. + +Flags not recognized by 'go test' must be placed after any specified packages. + + +Description of testing functions + +The 'go test' command expects to find test, benchmark, and example functions +in the "*_test.go" files corresponding to the package under test. + +A test function is one named TestXXX (where XXX is any alphanumeric string +not starting with a lower case letter) and should have the signature, + + func TestXXX(t *testing.T) { ... } + +A benchmark function is one named BenchmarkXXX and should have the signature, + + func BenchmarkXXX(b *testing.B) { ... } + +An example function is similar to a test function but, instead of using +*testing.T to report success or failure, prints output to os.Stdout. +That output is compared against the function's "Output:" comment, which +must be the last comment in the function body (see example below). An +example with no such comment, or with no text after "Output:" is compiled +but not executed. + +Godoc displays the body of ExampleXXX to demonstrate the use +of the function, constant, or variable XXX. An example of a method M with +receiver type T or *T is named ExampleT_M. There may be multiple examples +for a given function, constant, or variable, distinguished by a trailing _xxx, +where xxx is a suffix not beginning with an upper case letter. + +Here is an example of an example: + + func ExamplePrintln() { + Println("The output of\nthis example.") + // Output: The output of + // this example. + } + +The entire test file is presented as the example when it contains a single +example function, at least one other function, type, variable, or constant +declaration, and no test or benchmark functions. + +See the documentation of the testing package for more information. + + +*/ +package main diff --git a/libgo/go/cmd/go/bootstrap.go b/libgo/go/cmd/go/bootstrap.go index dc7ed5f4c06..1686df77afd 100644 --- a/libgo/go/cmd/go/bootstrap.go +++ b/libgo/go/cmd/go/bootstrap.go @@ -17,11 +17,19 @@ import ( var errHTTP = errors.New("no http in bootstrap go command") +type httpError struct { + statusCode int +} + +func (e *httpError) Error() string { + panic("unreachable") +} + func httpGET(url string) ([]byte, error) { return nil, errHTTP } -func httpsOrHTTP(importPath string) (string, io.ReadCloser, error) { +func httpsOrHTTP(importPath string, security securityMode) (string, io.ReadCloser, error) { return "", nil, errHTTP } diff --git a/libgo/go/cmd/go/build.go b/libgo/go/cmd/go/build.go index 781a43b5d99..56b15ad90d3 100644 --- a/libgo/go/cmd/go/build.go +++ b/libgo/go/cmd/go/build.go @@ -8,6 +8,7 @@ import ( "bufio" "bytes" "container/heap" + "debug/elf" "errors" "flag" "fmt" @@ -34,21 +35,23 @@ var cmdBuild = &Command{ Build compiles the packages named by the import paths, along with their dependencies, but it does not install the results. -If the arguments are a list of .go files, build treats them as a list -of source files specifying a single package. +If the arguments to build are a list of .go files, build treats +them as a list of source files specifying a single package. -When the command line specifies a single main package, -build writes the resulting executable to output. -Otherwise build compiles the packages but discards the results, +When compiling a single main package, build writes +the resulting executable to an output file named after +the first source file ('go build ed.go rx.go' writes 'ed' or 'ed.exe') +or the source code directory ('go build unix/sam' writes 'sam' or 'sam.exe'). +The '.exe' suffix is added when writing a Windows executable. + +When compiling multiple packages or a single non-main package, +build compiles the packages but discards the resulting object, serving only as a check that the packages can be built. -The -o flag specifies the output file name. If not specified, the -output file name depends on the arguments and derives from the name -of the package, such as p.a for package p, unless p is 'main'. If -the package is main and file names are provided, the file name -derives from the first file name mentioned, such as f1 for 'go build -f1.go f2.go'; with no files provided ('go build'), the output file -name is the base name of the containing directory. +The -o flag, only allowed when compiling a single package, +forces build to write the resulting executable or object +to the named output file, instead of the default behavior described +in the last two paragraphs. The -i flag installs the packages that are dependencies of the target. @@ -62,7 +65,8 @@ and test commands: print the commands but do not run them. -p n the number of builds that can be run in parallel. - The default is the number of CPUs available. + The default is the number of CPUs available, except + on darwin/arm which defaults to 1. -race enable data race detection. Supported only on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64. @@ -74,33 +78,54 @@ and test commands: -x print the commands. - -ccflags 'arg list' - arguments to pass on each 5c, 6c, or 8c compiler invocation. + -asmflags 'flag list' + arguments to pass on each go tool asm invocation. + -buildmode mode + build mode to use. See 'go help buildmode' for more. -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' - arguments to pass on each 5g, 6g, or 8g compiler invocation. + arguments to pass on each go tool compile invocation. -installsuffix suffix a suffix to use in the name of the package installation directory, in order to keep output separate from default builds. If using the -race flag, the install suffix is automatically set to race - or, if set explicitly, has _race appended to it. + or, if set explicitly, has _race appended to it. Using a -buildmode + option that requires non-default compile flags has a similar effect. -ldflags 'flag list' - arguments to pass on each 5l, 6l, or 8l linker invocation. + arguments to pass on each go tool link invocation. + -linkshared + link against shared libraries previously created with + -buildmode=shared + -pkgdir dir + install and load all packages from dir instead of the usual locations. + For example, when building with a non-standard configuration, + use -pkgdir to keep generated packages in a separate location. -tags 'tag list' a list of build tags to consider satisfied during the build. For more information about build tags, see the description of build constraints in the documentation for the go/build package. + -toolexec 'cmd args' + a program to use to invoke toolchain programs like vet and asm. + For example, instead of running asm, the go command will run + 'cmd args /path/to/asm '. The list flags accept a space-separated list of strings. To embed spaces in an element in the list, surround it with either single or double quotes. For more about specifying packages, see 'go help packages'. For more about where packages and binaries are installed, -run 'go help gopath'. For more about calling between Go and C/C++, -run 'go help c'. +run 'go help gopath'. +For more about calling between Go and C/C++, run 'go help c'. + +Note: Build adheres to certain conventions such as those described +by 'go help gopath'. Not all projects can follow these conventions, +however. Installations that have their own conventions or that use +a separate software build system may choose to use lower-level +invocations such as 'go tool compile' and 'go tool link' to avoid +some of the overheads and design decisions of the build tool. See also: go install, go get, go clean. `, @@ -115,6 +140,17 @@ func init() { addBuildFlags(cmdBuild) addBuildFlags(cmdInstall) + + if buildContext.GOOS == "darwin" { + switch buildContext.GOARCH { + case "arm", "arm64": + // darwin/arm cannot run multiple tests simultaneously. + // Parallelism is limited in go_darwin_arm_exec, but + // also needs to be limited here so go test std does not + // timeout tests that waiting to run. + buildP = 1 + } + } } // Flags set by multiple commands. @@ -126,16 +162,21 @@ var buildX bool // -x flag var buildI bool // -i flag var buildO = cmdBuild.Flag.String("o", "", "output file") var buildWork bool // -work flag +var buildAsmflags []string // -asmflags flag var buildGcflags []string // -gcflags flag -var buildCcflags []string // -ccflags flag var buildLdflags []string // -ldflags flag var buildGccgoflags []string // -gccgoflags flag var buildRace bool // -race flag +var buildToolExec []string // -toolexec flag +var buildBuildmode string // -buildmode flag +var buildLinkshared bool // -linkshared flag +var buildPkgdir string // -pkgdir flag // Require the source for go std packages var reqStdPkgSrc bool var buildContext = build.Default var buildToolchain toolchain = noToolchain{} +var ldBuildmode string // buildCompiler implements flag.Var. // It implements Set by updating both @@ -171,21 +212,25 @@ func init() { // addBuildFlags adds the flags common to the build, clean, get, // install, list, run, and test 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, "") - cmd.Flag.StringVar(&buildContext.InstallSuffix, "installsuffix", "", "") cmd.Flag.BoolVar(&buildV, "v", false, "") cmd.Flag.BoolVar(&buildX, "x", false, "") - cmd.Flag.BoolVar(&buildWork, "work", false, "") + + cmd.Flag.Var((*stringsFlag)(&buildAsmflags), "asmflags", "") + cmd.Flag.Var(buildCompiler{}, "compiler", "") + cmd.Flag.StringVar(&buildBuildmode, "buildmode", "default", "") cmd.Flag.Var((*stringsFlag)(&buildGcflags), "gcflags", "") - cmd.Flag.Var((*stringsFlag)(&buildCcflags), "ccflags", "") - cmd.Flag.Var((*stringsFlag)(&buildLdflags), "ldflags", "") cmd.Flag.Var((*stringsFlag)(&buildGccgoflags), "gccgoflags", "") - cmd.Flag.Var((*stringsFlag)(&buildContext.BuildTags), "tags", "") - cmd.Flag.Var(buildCompiler{}, "compiler", "") + cmd.Flag.StringVar(&buildContext.InstallSuffix, "installsuffix", "", "") + cmd.Flag.Var((*stringsFlag)(&buildLdflags), "ldflags", "") + cmd.Flag.BoolVar(&buildLinkshared, "linkshared", false, "") + cmd.Flag.StringVar(&buildPkgdir, "pkgdir", "", "") cmd.Flag.BoolVar(&buildRace, "race", false, "") + cmd.Flag.Var((*stringsFlag)(&buildContext.BuildTags), "tags", "") + cmd.Flag.Var((*stringsFlag)(&buildToolExec), "toolexec", "") + cmd.Flag.BoolVar(&buildWork, "work", false, "") switch build.Default.Compiler { case "gc": reqStdPkgSrc = true @@ -266,8 +311,113 @@ func (v *stringsFlag) String() string { return "" } +func pkgsMain(pkgs []*Package) (res []*Package) { + for _, p := range pkgs { + if p.Name == "main" { + res = append(res, p) + } + } + return res +} + +func pkgsNotMain(pkgs []*Package) (res []*Package) { + for _, p := range pkgs { + if p.Name != "main" { + res = append(res, p) + } + } + return res +} + +var pkgsFilter = func(pkgs []*Package) []*Package { return pkgs } + +func buildModeInit() { + _, gccgo := buildToolchain.(gccgoToolchain) + var codegenArg string + platform := goos + "/" + goarch + switch buildBuildmode { + case "archive": + pkgsFilter = pkgsNotMain + case "c-archive": + pkgsFilter = func(p []*Package) []*Package { + if len(p) != 1 || p[0].Name != "main" { + fatalf("-buildmode=c-archive requires exactly one main package") + } + return p + } + exeSuffix = ".a" + ldBuildmode = "c-archive" + case "c-shared": + pkgsFilter = pkgsMain + if gccgo { + codegenArg = "-fPIC" + } else { + switch platform { + case "linux/amd64": + codegenArg = "-shared" + case "linux/arm": + buildAsmflags = append(buildAsmflags, "-shared") + case "darwin/amd64": + case "android/arm": + default: + fatalf("-buildmode=c-shared not supported on %s\n", platform) + } + } + ldBuildmode = "c-shared" + case "default": + ldBuildmode = "exe" + case "exe": + pkgsFilter = pkgsMain + ldBuildmode = "exe" + case "shared": + pkgsFilter = pkgsNotMain + if gccgo { + codegenArg = "-fPIC" + } else { + switch platform { + case "linux/amd64": + default: + fatalf("-buildmode=shared not supported on %s\n", platform) + } + codegenArg = "-dynlink" + } + if *buildO != "" { + fatalf("-buildmode=shared and -o not supported together") + } + ldBuildmode = "shared" + default: + fatalf("buildmode=%s not supported", buildBuildmode) + } + if buildLinkshared { + if gccgo { + codegenArg = "-fPIC" + } else { + if platform != "linux/amd64" { + fmt.Fprintf(os.Stderr, "go %s: -linkshared is only supported on linux/amd64\n", flag.Args()[0]) + os.Exit(2) + } + codegenArg = "-dynlink" + // TODO(mwhudson): remove -w when that gets fixed in linker. + buildLdflags = append(buildLdflags, "-linkshared", "-w") + } + } + if codegenArg != "" { + if gccgo { + buildGccgoflags = append(buildGccgoflags, codegenArg) + } else { + buildAsmflags = append(buildAsmflags, codegenArg) + buildGcflags = append(buildGcflags, codegenArg) + } + if buildContext.InstallSuffix != "" { + buildContext.InstallSuffix += "_" + } + buildContext.InstallSuffix += codegenArg[1:] + } +} + func runBuild(cmd *Command, args []string) { raceInit() + buildModeInit() var b builder b.init() @@ -305,16 +455,21 @@ func runBuild(cmd *Command, args []string) { fatalf("no packages to build") } p := pkgs[0] - p.target = "" // must build - not up to date + p.target = *buildO + p.Stale = true // must build - not up to date a := b.action(modeInstall, depMode, p) - a.target = *buildO b.do(a) return } - a := &action{} - for _, p := range packages(args) { - a.deps = append(a.deps, b.action(modeBuild, depMode, p)) + var a *action + if buildBuildmode == "shared" { + a = b.libaction(libname(args), pkgsFilter(packages(args)), modeBuild, depMode) + } else { + a = &action{} + for _, p := range pkgsFilter(packages(args)) { + a.deps = append(a.deps, b.action(modeBuild, depMode, p)) + } } b.do(a) } @@ -333,18 +488,47 @@ See also: go build, go get, go clean. `, } +// libname returns the filename to use for the shared library when using +// -buildmode=shared. The rules we use are: +// 1) Drop any trailing "/..."s if present +// 2) Change / to - +// 3) Join arguments with , +// So std -> libstd.so +// a b/... -> liba,b.so +// gopkg.in/tomb.v2 -> libgopkg.in-tomb.v2.so +func libname(args []string) string { + var libname string + for _, arg := range args { + arg = strings.TrimSuffix(arg, "/...") + arg = strings.Replace(arg, "/", "-", -1) + if libname == "" { + libname = arg + } else { + libname += "," + arg + } + } + // TODO(mwhudson): Needs to change for platforms that use different naming + // conventions... + return "lib" + libname + ".so" +} + func runInstall(cmd *Command, args []string) { raceInit() - pkgs := packagesForBuild(args) + buildModeInit() + pkgs := pkgsFilter(packagesForBuild(args)) for _, p := range pkgs { if p.Target == "" && (!p.Standard || p.ImportPath != "unsafe") { - if p.cmdline { + switch { + case p.gobinSubdir: + errorf("go install: cannot install cross-compiled binaries when GOBIN is set") + case p.cmdline: errorf("go install: no install location for .go files listed on command line (GOBIN not set)") - } else if p.ConflictDir != "" { + case p.ConflictDir != "": errorf("go install: no install location for %s: hidden by %s", p.Dir, p.ConflictDir) - } else { - errorf("go install: no install location for directory %s outside GOPATH", p.Dir) + default: + errorf("go install: no install location for directory %s outside GOPATH\n"+ + "\tFor more details see: go help gopath", p.Dir) } } } @@ -352,18 +536,68 @@ func runInstall(cmd *Command, args []string) { var b builder b.init() - a := &action{} - for _, p := range pkgs { - a.deps = append(a.deps, b.action(modeInstall, modeInstall, p)) + var a *action + if buildBuildmode == "shared" { + a = b.libaction(libname(args), pkgs, modeInstall, modeInstall) + } else { + a = &action{} + var tools []*action + for _, p := range pkgs { + // If p is a tool, delay the installation until the end of the build. + // This avoids installing assemblers/compilers that are being executed + // by other steps in the build. + // cmd/cgo is handled specially in b.action, so that we can + // both build and use it in the same 'go install'. + action := b.action(modeInstall, modeInstall, p) + if goTools[p.ImportPath] == toTool && p.ImportPath != "cmd/cgo" { + a.deps = append(a.deps, action.deps...) + action.deps = append(action.deps, a) + tools = append(tools, action) + continue + } + a.deps = append(a.deps, action) + } + if len(tools) > 0 { + a = &action{ + deps: tools, + } + } } b.do(a) + exitIfErrors() + + // Success. If this command is 'go install' with no arguments + // and the current directory (the implicit argument) is a command, + // remove any leftover command binary from a previous 'go build'. + // The binary is installed; it's not needed here anymore. + // And worse it might be a stale copy, which you don't want to find + // instead of the installed one if $PATH contains dot. + // One way to view this behavior is that it is as if 'go install' first + // runs 'go build' and the moves the generated file to the install dir. + // See issue 9645. + if len(args) == 0 && len(pkgs) == 1 && pkgs[0].Name == "main" { + // Compute file 'go build' would have created. + // If it exists and is an executable file, remove it. + _, targ := filepath.Split(pkgs[0].ImportPath) + targ += exeSuffix + if filepath.Join(pkgs[0].Dir, targ) != pkgs[0].Target { // maybe $GOBIN is the current directory + fi, err := os.Stat(targ) + if err == nil { + m := fi.Mode() + if m.IsRegular() { + if m&0111 != 0 || goos == "windows" { // windows never sets executable bit + os.Remove(targ) + } + } + } + } + } } // Global build parameters (used during package load) var ( goarch string goos string - archChar string exeSuffix string ) @@ -373,16 +607,6 @@ func init() { if goos == "windows" { exeSuffix = ".exe" } - var err error - archChar, err = build.ArchChar(goarch) - if err != nil { - if _, isgc := buildToolchain.(gcToolchain); isgc { - fatalf("%s", err) - } - // archChar is only required for gcToolchain, if we're using - // another toolchain leave it blank. - archChar = "" - } } // A builder holds global state about a build. @@ -429,8 +653,9 @@ type action struct { // cacheKey is the key for the action cache. type cacheKey struct { - mode buildMode - p *Package + mode buildMode + p *Package + shlib string } // buildMode specifies the build mode: @@ -505,6 +730,9 @@ func goFilesPackage(gofiles []string) *Package { fatalf("%s is a directory, should be a Go file", file) } dir1, _ := filepath.Split(file) + if dir1 == "" { + dir1 = "./" + } if dir == "" { dir = dir1 } else if dir != dir1 { @@ -541,11 +769,8 @@ func goFilesPackage(gofiles []string) *Package { if gobin != "" { pkg.target = filepath.Join(gobin, exe) } - } else { - if *buildO == "" { - *buildO = pkg.Name + ".a" - } } + pkg.Target = pkg.target pkg.Stale = true @@ -553,24 +778,88 @@ func goFilesPackage(gofiles []string) *Package { return pkg } +// readpkglist returns the list of packages that were built into the shared library +// at shlibpath. For the native toolchain this list is stored, newline separated, in +// an ELF note with name "Go\x00\x00" and type 1. For GCCGO it is extracted from the +// .go_export section. +func readpkglist(shlibpath string) (pkgs []*Package) { + var stk importStack + if _, gccgo := buildToolchain.(gccgoToolchain); gccgo { + f, _ := elf.Open(shlibpath) + sect := f.Section(".go_export") + data, _ := sect.Data() + scanner := bufio.NewScanner(bytes.NewBuffer(data)) + for scanner.Scan() { + t := scanner.Text() + if strings.HasPrefix(t, "pkgpath ") { + t = strings.TrimPrefix(t, "pkgpath ") + t = strings.TrimSuffix(t, ";") + pkgs = append(pkgs, loadPackage(t, &stk)) + } + } + } else { + pkglistbytes, err := readELFNote(shlibpath, "Go\x00\x00", 1) + if err != nil { + fatalf("readELFNote failed: %v", err) + } + scanner := bufio.NewScanner(bytes.NewBuffer(pkglistbytes)) + for scanner.Scan() { + t := scanner.Text() + pkgs = append(pkgs, loadPackage(t, &stk)) + } + } + return +} + // action returns the action for applying the given operation (mode) to the package. // depMode is the action to use when building dependencies. +// action never looks for p in a shared library. func (b *builder) action(mode buildMode, depMode buildMode, p *Package) *action { - key := cacheKey{mode, p} + return b.action1(mode, depMode, p, false) +} + +// action1 returns the action for applying the given operation (mode) to the package. +// depMode is the action to use when building dependencies. +// action1 will look for p in a shared library if lookshared is true. +func (b *builder) action1(mode buildMode, depMode buildMode, p *Package, lookshared bool) *action { + shlib := "" + if lookshared { + shlib = p.Shlib + } + key := cacheKey{mode, p, shlib} + a := b.actionCache[key] if a != nil { return a } + if shlib != "" { + key2 := cacheKey{modeInstall, nil, shlib} + a = b.actionCache[key2] + if a != nil { + b.actionCache[key] = a + return a + } + pkgs := readpkglist(shlib) + a = b.libaction(filepath.Base(shlib), pkgs, modeInstall, depMode) + b.actionCache[key2] = a + b.actionCache[key] = a + return a + } a = &action{p: p, pkgdir: p.build.PkgRoot} if p.pkgdir != "" { // overrides p.t a.pkgdir = p.pkgdir } - b.actionCache[key] = a for _, p1 := range p.imports { - a.deps = append(a.deps, b.action(depMode, depMode, p1)) + ls := buildLinkshared + // If p1 is part of the same shared library as p, we need the action + // that builds p here, not the shared libary or we get action loops. + if p1.Shlib == p.Shlib { + ls = false + } + a.deps = append(a.deps, b.action1(depMode, depMode, p1, ls)) } // If we are not doing a cross-build, then record the binary we'll @@ -578,18 +867,15 @@ func (b *builder) action(mode buildMode, depMode buildMode, p *Package) *action // using cgo, to make sure we do not overwrite the binary while // a package is using it. If this is a cross-build, then the cgo we // are writing is not the cgo we need to use. - - if goos == runtime.GOOS && goarch == runtime.GOARCH && !buildRace { - if reqStdPkgSrc { - if len(p.CgoFiles) > 0 || p.Standard && p.ImportPath == "runtime/cgo" { - var stk importStack - p1 := loadPackage("cmd/cgo", &stk) - if p1.Error != nil { - fatalf("load cmd/cgo: %v", p1.Error) - } - a.cgo = b.action(depMode, depMode, p1) - a.deps = append(a.deps, a.cgo) + if goos == runtime.GOOS && goarch == runtime.GOARCH && !buildRace && reqStdPkgSrc { + if (len(p.CgoFiles) > 0 || p.Standard && p.ImportPath == "runtime/cgo") && !buildLinkshared && buildBuildmode != "shared" { + var stk importStack + p1 := loadPackage("cmd/cgo", &stk) + if p1.Error != nil { + fatalf("load cmd/cgo: %v", p1.Error) } + a.cgo = b.action(depMode, depMode, p1) + a.deps = append(a.deps, a.cgo) } } @@ -629,8 +915,22 @@ func (b *builder) action(mode buildMode, depMode buildMode, p *Package) *action switch mode { case modeInstall: a.f = (*builder).install - a.deps = []*action{b.action(modeBuild, depMode, p)} + a.deps = []*action{b.action1(modeBuild, depMode, p, lookshared)} a.target = a.p.target + + // Install header for cgo in c-archive and c-shared modes. + if p.usesCgo() && (buildBuildmode == "c-archive" || buildBuildmode == "c-shared") { + ah := &action{ + p: a.p, + deps: []*action{a.deps[0]}, + f: (*builder).installHeader, + pkgdir: a.pkgdir, + objdir: a.objdir, + target: a.target[:len(a.target)-len(filepath.Ext(a.target))] + ".h", + } + a.deps = append(a.deps, ah) + } + case modeBuild: a.f = (*builder).build a.target = a.objpkg @@ -645,6 +945,13 @@ func (b *builder) action(mode buildMode, depMode buildMode, p *Package) *action name := "a.out" if p.exeName != "" { name = p.exeName + } else if goos == "darwin" && buildBuildmode == "c-shared" && p.target != "" { + // On OS X, the linker output name gets recorded in the + // shared library's LC_ID_DYLIB load command. + // The code invoking the linker knows to pass only the final + // path element. Arrange that the path element matches what + // we'll install it as; otherwise the library is only loadable as "a.out". + _, name = filepath.Split(p.target) } a.target = a.objdir + filepath.Join("exe", name) + exeSuffix } @@ -653,6 +960,100 @@ func (b *builder) action(mode buildMode, depMode buildMode, p *Package) *action return a } +func (b *builder) libaction(libname string, pkgs []*Package, mode, depMode buildMode) *action { + a := &action{} + if mode == modeBuild { + a.f = (*builder).linkShared + a.target = filepath.Join(b.work, libname) + for _, p := range pkgs { + if p.target == "" { + continue + } + a.deps = append(a.deps, b.action(depMode, depMode, p)) + } + } else if mode == modeInstall { + // Currently build mode shared forces external linking mode, and + // external linking mode forces an import of runtime/cgo. So if it + // was not passed on the command line and it is not present in + // another shared library, add it here. + seencgo := false + _, gccgo := buildToolchain.(gccgoToolchain) + if !gccgo { + for _, p := range pkgs { + seencgo = seencgo || (p.Standard && p.ImportPath == "runtime/cgo") + } + if !seencgo { + var stk importStack + p := loadPackage("runtime/cgo", &stk) + if p.Error != nil { + fatalf("load runtime/cgo: %v", p.Error) + } + computeStale(p) + // If runtime/cgo is in another shared library, then that's + // also the shared library that contains runtime, so + // something will depend on it and so runtime/cgo's staleness + // will be checked when processing that library. + if p.Shlib == "" || p.Shlib == libname { + pkgs = append([]*Package{}, pkgs...) + pkgs = append(pkgs, p) + } + } + } + + // Figure out where the library will go. + var libdir string + for _, p := range pkgs { + plibdir := p.build.PkgTargetRoot + if gccgo { + plibdir = filepath.Join(plibdir, "shlibs") + } + if libdir == "" { + libdir = plibdir + } else if libdir != plibdir { + fatalf("multiple roots %s & %s", libdir, plibdir) + } + } + a.target = filepath.Join(libdir, libname) + + // Now we can check whether we need to rebuild it. + stale := false + var built time.Time + if fi, err := os.Stat(a.target); err == nil { + built = fi.ModTime() + } + for _, p := range pkgs { + if p.target == "" { + continue + } + stale = stale || p.Stale + lstat, err := os.Stat(p.target) + if err != nil || lstat.ModTime().After(built) { + stale = true + } + a.deps = append(a.deps, b.action(depMode, depMode, p)) + } + + if stale { + a.f = (*builder).install + buildAction := b.libaction(libname, pkgs, modeBuild, depMode) + a.deps = []*action{buildAction} + for _, p := range pkgs { + if p.target == "" { + continue + } + shlibnameaction := &action{} + shlibnameaction.f = (*builder).installShlibname + shlibnameaction.target = p.target[:len(p.target)-2] + ".shlibname" + a.deps = append(a.deps, shlibnameaction) + shlibnameaction.deps = append(shlibnameaction.deps, buildAction) + } + } + } else { + fatalf("unregonized mode %v", mode) + } + return a +} + // actionList returns the list of actions in the dag rooted at root // as visited in a depth-first post-order traversal. func actionList(root *action) []*action { @@ -673,6 +1074,31 @@ func actionList(root *action) []*action { return all } +// allArchiveActions returns a list of the archive dependencies of root. +// This is needed because if package p depends on package q that is in libr.so, the +// action graph looks like p->libr.so->q and so just scanning through p's +// dependencies does not find the import dir for q. +func allArchiveActions(root *action) []*action { + seen := map[*action]bool{} + r := []*action{} + var walk func(*action) + walk = func(a *action) { + if seen[a] { + return + } + seen[a] = true + if strings.HasSuffix(a.target, ".so") || a == root { + for _, a1 := range a.deps { + walk(a1) + } + } else if strings.HasSuffix(a.target, ".a") { + r = append(r, a) + } + } + walk(root) + return r +} + // do runs the action graph rooted at root. func (b *builder) do(root *action) { // Build list of all actions, assigning depth-first post-order priority. @@ -793,9 +1219,7 @@ func hasString(strings []string, s string) bool { func (b *builder) build(a *action) (err error) { // Return an error if the package has CXX files but it's not using // cgo nor SWIG, since the CXX files can only be processed by cgo - // and SWIG (it's possible to have packages with C files without - // using cgo, they will get compiled with the plan9 C compiler and - // linked with the rest of the package). + // and SWIG. if len(a.p.CXXFiles) > 0 && !a.p.usesCgo() && !a.p.usesSwig() { return fmt.Errorf("can't build package %s because it contains C++ files (%s) but it's not using cgo nor SWIG", a.p.ImportPath, strings.Join(a.p.CXXFiles, ",")) @@ -824,7 +1248,8 @@ func (b *builder) build(a *action) (err error) { } if a.p.Standard && a.p.ImportPath == "runtime" && buildContext.Compiler == "gc" && - !hasString(a.p.HFiles, "zasm_"+buildContext.GOOS+"_"+buildContext.GOARCH+".h") { + (!hasString(a.p.GoFiles, "zgoos_"+buildContext.GOOS+".go") || + !hasString(a.p.GoFiles, "zgoarch_"+buildContext.GOARCH+".go")) { return fmt.Errorf("%s/%s must be bootstrapped using make%v", buildContext.GOOS, buildContext.GOARCH, defaultSuffix()) } @@ -842,19 +1267,35 @@ func (b *builder) build(a *action) (err error) { } } - var gofiles, cfiles, sfiles, objects, cgoObjects, pcCFLAGS, pcLDFLAGS []string + var gofiles, cgofiles, cfiles, sfiles, cxxfiles, objects, cgoObjects, pcCFLAGS, pcLDFLAGS []string gofiles = append(gofiles, a.p.GoFiles...) + cgofiles = append(cgofiles, a.p.CgoFiles...) cfiles = append(cfiles, a.p.CFiles...) sfiles = append(sfiles, a.p.SFiles...) + cxxfiles = append(cxxfiles, a.p.CXXFiles...) if a.p.usesCgo() || a.p.usesSwig() { if pcCFLAGS, pcLDFLAGS, err = b.getPkgConfigFlags(a.p); err != nil { return } } + + // Run SWIG on each .swig and .swigcxx file. + // Each run will generate two files, a .go file and a .c or .cxx file. + // The .go file will use import "C" and is to be processed by cgo. + if a.p.usesSwig() { + outGo, outC, outCXX, err := b.swig(a.p, obj, pcCFLAGS) + if err != nil { + return err + } + cgofiles = append(cgofiles, outGo...) + cfiles = append(cfiles, outC...) + cxxfiles = append(cxxfiles, outCXX...) + } + // Run cgo. - if a.p.usesCgo() { + if a.p.usesCgo() || a.p.usesSwig() { // In a package using cgo, cgo compiles the C, C++ and assembly files with gcc. // There is one exception: runtime/cgo's job is to bridge the // cgo and non-cgo worlds, so it necessarily has files in both. @@ -883,31 +1324,7 @@ func (b *builder) build(a *action) (err error) { if a.cgo != nil && a.cgo.target != "" { cgoExe = a.cgo.target } - outGo, outObj, err := b.cgo(a.p, cgoExe, obj, pcCFLAGS, pcLDFLAGS, gccfiles, a.p.CXXFiles, a.p.MFiles) - if err != nil { - return err - } - cgoObjects = append(cgoObjects, outObj...) - gofiles = append(gofiles, outGo...) - } - - // Run SWIG. - if a.p.usesSwig() { - // In a package using SWIG, any .c or .s files are - // compiled with gcc. - gccfiles := append(cfiles, sfiles...) - cxxfiles, mfiles := a.p.CXXFiles, a.p.MFiles - cfiles = nil - sfiles = nil - - // Don't build c/c++ files twice if cgo is enabled (mainly for pkg-config). - if a.p.usesCgo() { - cxxfiles = nil - gccfiles = nil - mfiles = nil - } - - outGo, outObj, err := b.swig(a.p, obj, pcCFLAGS, gccfiles, cxxfiles, mfiles) + outGo, outObj, err := b.cgo(a.p, cgoExe, obj, pcCFLAGS, pcLDFLAGS, cgofiles, gccfiles, cxxfiles, a.p.MFiles) if err != nil { return err } @@ -949,10 +1366,10 @@ func (b *builder) build(a *action) (err error) { } // Prepare Go import path list. - inc := b.includeArgs("-I", a.deps) + inc := b.includeArgs("-I", allArchiveActions(a)) // Compile Go. - ofile, out, err := buildToolchain.gc(b, a.p, a.objpkg, obj, inc, gofiles) + ofile, out, err := buildToolchain.gc(b, a.p, a.objpkg, obj, len(sfiles) > 0, inc, gofiles) if len(out) > 0 { b.showOutput(a.p.Dir, a.p.ImportPath, b.processOutput(out)) if err != nil { @@ -977,29 +1394,24 @@ func (b *builder) build(a *action) (err error) { switch { case strings.HasSuffix(name, _goos_goarch): targ := file[:len(name)-len(_goos_goarch)] + "_GOOS_GOARCH." + ext - if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0644); err != nil { + if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0644, true); err != nil { return err } case strings.HasSuffix(name, _goarch): targ := file[:len(name)-len(_goarch)] + "_GOARCH." + ext - if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0644); err != nil { + if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0644, true); err != nil { return err } case strings.HasSuffix(name, _goos): targ := file[:len(name)-len(_goos)] + "_GOOS." + ext - if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0644); err != nil { + if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0644, true); err != nil { return err } } } - objExt := archChar - if _, ok := buildToolchain.(gccgoToolchain); ok { - objExt = "o" - } - for _, file := range cfiles { - out := file[:len(file)-len(".c")] + "." + objExt + out := file[:len(file)-len(".c")] + ".o" if err := buildToolchain.cc(b, a.p, obj, obj+out, file); err != nil { return err } @@ -1008,7 +1420,7 @@ func (b *builder) build(a *action) (err error) { // Assemble .s files. for _, file := range sfiles { - out := file[:len(file)-len(".s")] + "." + objExt + out := file[:len(file)-len(".s")] + ".o" if err := buildToolchain.asm(b, a.p, obj, obj+out, file); err != nil { return err } @@ -1018,7 +1430,7 @@ func (b *builder) build(a *action) (err error) { // NOTE(rsc): On Windows, it is critically important that the // gcc-compiled objects (cgoObjects) be listed after the ordinary // objects in the archive. I do not know why this is. - // http://golang.org/issue/2601 + // https://golang.org/issue/2601 objects = append(objects, cgoObjects...) // Add system object files. @@ -1043,7 +1455,7 @@ func (b *builder) build(a *action) (err error) { // linker needs the whole dependency tree. all := actionList(a) all = all[:len(all)-1] // drop a - if err := buildToolchain.ld(b, a.p, a.target, all, a.objpkg, objects); err != nil { + if err := buildToolchain.ld(b, a, a.target, all, a.objpkg, objects); err != nil { return err } } @@ -1079,6 +1491,24 @@ func (b *builder) getPkgConfigFlags(p *Package) (cflags, ldflags []string, err e return } +func (b *builder) installShlibname(a *action) error { + a1 := a.deps[0] + err := ioutil.WriteFile(a.target, []byte(filepath.Base(a1.target)+"\n"), 0644) + if err != nil { + return err + } + if buildX { + b.showcmd("", "echo '%s' > %s # internal", filepath.Base(a1.target), a.target) + } + return nil +} + +func (b *builder) linkShared(a *action) (err error) { + allactions := actionList(a) + allactions = allactions[:len(allactions)-1] + return buildToolchain.ldShared(b, a.deps, a.target, allactions) +} + // install is the action for installing a single package or executable. func (b *builder) install(a *action) (err error) { defer func() { @@ -1089,7 +1519,11 @@ func (b *builder) install(a *action) (err error) { a1 := a.deps[0] perm := os.FileMode(0644) if a1.link { - perm = 0755 + switch buildBuildmode { + case "c-archive", "c-shared": + default: + perm = 0755 + } } // make target directory @@ -1109,7 +1543,7 @@ func (b *builder) install(a *action) (err error) { defer os.Remove(a1.target) } - return b.moveOrCopyFile(a, a.target, a1.target, perm) + return b.moveOrCopyFile(a, a.target, a1.target, perm, false) } // includeArgs returns the -I or -L directory list for access @@ -1126,6 +1560,9 @@ func (b *builder) includeArgs(flag string, all []*action) []string { // This is the $WORK/my/package/_test directory for the // package being built, so there are few of these. for _, a1 := range all { + if a1.p == nil { + continue + } if dir := a1.pkgdir; dir != a1.p.build.PkgRoot && !incMap[dir] { incMap[dir] = true inc = append(inc, flag, dir) @@ -1138,17 +1575,12 @@ func (b *builder) includeArgs(flag string, all []*action) []string { // Finally, look in the installed package directories for each action. for _, a1 := range all { + if a1.p == nil { + continue + } if dir := a1.pkgdir; dir == a1.p.build.PkgRoot && !incMap[dir] { incMap[dir] = true - if _, ok := buildToolchain.(gccgoToolchain); ok { - dir = filepath.Join(dir, "gccgo_"+goos+"_"+goarch) - } else { - dir = filepath.Join(dir, goos+"_"+goarch) - if buildContext.InstallSuffix != "" { - dir += "_" + buildContext.InstallSuffix - } - } - inc = append(inc, flag, dir) + inc = append(inc, flag, a1.p.build.PkgTargetRoot) } } @@ -1156,7 +1588,7 @@ func (b *builder) includeArgs(flag string, all []*action) []string { } // moveOrCopyFile is like 'mv src dst' or 'cp src dst'. -func (b *builder) moveOrCopyFile(a *action, dst, src string, perm os.FileMode) error { +func (b *builder) moveOrCopyFile(a *action, dst, src string, perm os.FileMode, force bool) error { if buildN { b.showcmd("", "mv %s %s", src, dst) return nil @@ -1173,11 +1605,11 @@ func (b *builder) moveOrCopyFile(a *action, dst, src string, perm os.FileMode) e } } - return b.copyFile(a, dst, src, perm) + return b.copyFile(a, dst, src, perm, force) } // copyFile is like 'cp src dst'. -func (b *builder) copyFile(a *action, dst, src string, perm os.FileMode) error { +func (b *builder) copyFile(a *action, dst, src string, perm os.FileMode, force bool) error { if buildN || buildX { b.showcmd("", "cp %s %s", src, dst) if buildN { @@ -1198,7 +1630,7 @@ func (b *builder) copyFile(a *action, dst, src string, perm os.FileMode) error { if fi.IsDir() { return fmt.Errorf("build output %q already exists and is a directory", dst) } - if !isObject(dst) { + if !force && !isObject(dst) { return fmt.Errorf("build output %q already exists and is not an object file", dst) } } @@ -1235,10 +1667,30 @@ func (b *builder) copyFile(a *action, dst, src string, perm os.FileMode) error { return nil } +// Install the cgo export header file, if there is one. +func (b *builder) installHeader(a *action) error { + src := a.objdir + "_cgo_install.h" + if _, err := os.Stat(src); os.IsNotExist(err) { + // If the file does not exist, there are no exported + // functions, and we do not install anything. + return nil + } + + dir, _ := filepath.Split(a.target) + if dir != "" { + if err := b.mkdir(dir); err != nil { + return err + } + } + + return b.moveOrCopyFile(a, a.target, src, 0644, true) +} + // cover runs, in effect, // go tool cover -mode=b.coverMode -var="varName" -o dst.go src.go func (b *builder) cover(a *action, dst, src string, perm os.FileMode, varName string) error { return b.run(a.objdir, "cover "+a.p.ImportPath, nil, + buildToolExec, tool("cover"), "-mode", a.p.coverMode, "-var", varName, @@ -1247,15 +1699,15 @@ func (b *builder) cover(a *action, dst, src string, perm os.FileMode, varName st } var objectMagic = [][]byte{ - {'!', '<', 'a', 'r', 'c', 'h', '>', '\n'}, // Package archive - {'\x7F', 'E', 'L', 'F'}, // ELF - {0xFE, 0xED, 0xFA, 0xCE}, // Mach-O big-endian 32-bit - {0xFE, 0xED, 0xFA, 0xCF}, // Mach-O big-endian 64-bit - {0xCE, 0xFA, 0xED, 0xFE}, // Mach-O little-endian 32-bit - {0xCF, 0xFA, 0xED, 0xFE}, // Mach-O little-endian 64-bit - {0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x04, 0x00}, // PE (Windows) as generated by 6l/8l - {0x00, 0x00, 0x01, 0xEB}, // Plan 9 i386 - {0x00, 0x00, 0x8a, 0x97}, // Plan 9 amd64 + {'!', '<', 'a', 'r', 'c', 'h', '>', '\n'}, // Package archive + {'\x7F', 'E', 'L', 'F'}, // ELF + {0xFE, 0xED, 0xFA, 0xCE}, // Mach-O big-endian 32-bit + {0xFE, 0xED, 0xFA, 0xCF}, // Mach-O big-endian 64-bit + {0xCE, 0xFA, 0xED, 0xFE}, // Mach-O little-endian 32-bit + {0xCF, 0xFA, 0xED, 0xFE}, // Mach-O little-endian 64-bit + {0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00}, // PE (Windows) as generated by 6l/8l and gcc + {0x00, 0x00, 0x01, 0xEB}, // Plan 9 i386 + {0x00, 0x00, 0x8a, 0x97}, // Plan 9 amd64 } func isObject(s string) bool { @@ -1436,7 +1888,7 @@ func (b *builder) runOut(dir string, desc string, env []string, cmdargs ...inter cmd.Stdout = &buf cmd.Stderr = &buf cmd.Dir = dir - cmd.Env = mergeEnvLists(env, envForDir(cmd.Dir)) + cmd.Env = mergeEnvLists(env, envForDir(cmd.Dir, os.Environ())) err := cmd.Run() // cmd.Run will fail on Unix if some other process has the binary @@ -1478,7 +1930,7 @@ func (b *builder) runOut(dir string, desc string, env []string, cmdargs ...inter // Sleeping when we observe the race seems to be the most reliable // option we have. // - // http://golang.org/issue/3001 + // https://golang.org/issue/3001 // if err != nil && nbusy < 3 && strings.Contains(err.Error(), "text file busy") { time.Sleep(100 * time.Millisecond << uint(nbusy)) @@ -1561,7 +2013,7 @@ type toolchain interface { // gc runs the compiler in a specific directory on a set of files // and returns the name of the generated output file. // The compiler runs in the directory dir. - gc(b *builder, p *Package, archive, obj string, importArgs []string, gofiles []string) (ofile string, out []byte, err error) + gc(b *builder, p *Package, archive, obj string, asmhdr bool, importArgs []string, gofiles []string) (ofile string, out []byte, err error) // cc runs the toolchain's C compiler in a directory on a C file // to produce an output file. cc(b *builder, p *Package, objdir, ofile, cfile string) error @@ -1574,8 +2026,10 @@ type toolchain interface { // an archive from a set of object files. // typically it is run in the object directory. pack(b *builder, p *Package, objDir, afile string, ofiles []string) error - // ld runs the linker to create a package starting at mainpkg. - ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error + // ld runs the linker to create an executable starting at mainpkg. + ld(b *builder, root *action, out string, allactions []*action, mainpkg string, ofiles []string) error + // ldShared runs the linker to create a shared library containing the pkgs built by toplevelactions + ldShared(b *builder, toplevelactions []*action, out string, allactions []*action) error compiler() string linker() string @@ -1598,7 +2052,7 @@ func (noToolchain) linker() string { return "" } -func (noToolchain) gc(b *builder, p *Package, archive, obj string, importArgs []string, gofiles []string) (ofile string, out []byte, err error) { +func (noToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool, importArgs []string, gofiles []string) (ofile string, out []byte, err error) { return "", nil, noCompiler() } @@ -1615,7 +2069,11 @@ func (noToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles []s return noCompiler() } -func (noToolchain) ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error { +func (noToolchain) ld(b *builder, root *action, out string, allactions []*action, mainpkg string, ofiles []string) error { + return noCompiler() +} + +func (noToolchain) ldShared(b *builder, toplevelactions []*action, out string, allactions []*action) error { return noCompiler() } @@ -1627,24 +2085,27 @@ func (noToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error type gcToolchain struct{} func (gcToolchain) compiler() string { - return tool(archChar + "g") + return tool("compile") } func (gcToolchain) linker() string { - return tool(archChar + "l") + return tool("link") } -func (gcToolchain) gc(b *builder, p *Package, archive, obj string, importArgs []string, gofiles []string) (ofile string, output []byte, err error) { +func (gcToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool, importArgs []string, gofiles []string) (ofile string, output []byte, err error) { if archive != "" { ofile = archive } else { - out := "_go_." + archChar + out := "_go_.o" ofile = obj + out } gcargs := []string{"-p", p.ImportPath} + if p.Name == "main" { + gcargs[1] = "main" + } if p.Standard && p.ImportPath == "runtime" { - // runtime compiles with a special 6g flag to emit + // runtime compiles with a special gc flag to emit // additional reflect type data. gcargs = append(gcargs, "-+") } @@ -1666,24 +2127,76 @@ func (gcToolchain) gc(b *builder, p *Package, archive, obj string, importArgs [] if buildContext.InstallSuffix != "" { gcargs = append(gcargs, "-installsuffix", buildContext.InstallSuffix) } + if p.buildID != "" { + gcargs = append(gcargs, "-buildid", p.buildID) + } + + for _, path := range p.Imports { + if i := strings.LastIndex(path, "/vendor/"); i >= 0 { + gcargs = append(gcargs, "-importmap", path[i+len("/vendor/"):]+"="+path) + } else if strings.HasPrefix(path, "vendor/") { + gcargs = append(gcargs, "-importmap", path[len("vendor/"):]+"="+path) + } + } + + for _, path := range p.Imports { + if i := strings.LastIndex(path, "/vendor/"); i >= 0 { + gcargs = append(gcargs, "-importmap", path[i+len("/vendor/"):]+"="+path) + } else if strings.HasPrefix(path, "vendor/") { + gcargs = append(gcargs, "-importmap", path[len("vendor/"):]+"="+path) + } + } - args := stringList(tool(archChar+"g"), "-o", ofile, "-trimpath", b.work, buildGcflags, gcargs, "-D", p.localPrefix, importArgs) + args := []interface{}{buildToolExec, tool("compile"), "-o", ofile, "-trimpath", b.work, buildGcflags, gcargs, "-D", p.localPrefix, importArgs} if ofile == archive { args = append(args, "-pack") } + if asmhdr { + args = append(args, "-asmhdr", obj+"go_asm.h") + } for _, f := range gofiles { args = append(args, mkAbs(p.Dir, f)) } - output, err = b.runOut(p.Dir, p.ImportPath, nil, args) + output, err = b.runOut(p.Dir, p.ImportPath, nil, args...) return ofile, output, err } func (gcToolchain) asm(b *builder, p *Package, obj, ofile, sfile string) error { // Add -I pkg/GOOS_GOARCH so #include "textflag.h" works in .s files. - inc := filepath.Join(goroot, "pkg", fmt.Sprintf("%s_%s", goos, goarch)) + inc := filepath.Join(goroot, "pkg", "include") sfile = mkAbs(p.Dir, sfile) - return b.run(p.Dir, p.ImportPath, nil, tool(archChar+"a"), "-trimpath", b.work, "-I", obj, "-I", inc, "-o", ofile, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, sfile) + args := []interface{}{buildToolExec, tool("asm"), "-o", ofile, "-trimpath", b.work, "-I", obj, "-I", inc, "-D", "GOOS_" + goos, "-D", "GOARCH_" + goarch, buildAsmflags, sfile} + if err := b.run(p.Dir, p.ImportPath, nil, args...); err != nil { + return err + } + return nil +} + +// toolVerify checks that the command line args writes the same output file +// if run using newTool instead. +// Unused now but kept around for future use. +func toolVerify(b *builder, p *Package, newTool string, ofile string, args []interface{}) error { + newArgs := make([]interface{}, len(args)) + copy(newArgs, args) + newArgs[1] = tool(newTool) + newArgs[3] = ofile + ".new" // x.6 becomes x.6.new + if err := b.run(p.Dir, p.ImportPath, nil, newArgs...); err != nil { + return err + } + data1, err := ioutil.ReadFile(ofile) + if err != nil { + return err + } + data2, err := ioutil.ReadFile(ofile + ".new") + if err != nil { + return err + } + if !bytes.Equal(data1, data2) { + return fmt.Errorf("%s and %s produced different output files:\n%s\n%s", filepath.Base(args[1].(string)), newTool, strings.Join(stringList(args...), " "), strings.Join(stringList(newArgs...), " ")) + } + os.Remove(ofile + ".new") + return nil } func (gcToolchain) pkgpath(basedir string, p *Package) string { @@ -1722,7 +2235,7 @@ func (gcToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles []s // Need actual pack. cmdline[0] = tool("pack") - return b.run(p.Dir, p.ImportPath, nil, cmdline) + return b.run(p.Dir, p.ImportPath, nil, buildToolExec, cmdline) } func packInternal(b *builder, afile string, ofiles []string) error { @@ -1775,21 +2288,49 @@ func packInternal(b *builder, afile string, ofiles []string) error { return dst.Close() } -func (gcToolchain) ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error { +// setextld sets the appropriate linker flags for the specified compiler. +func setextld(ldflags []string, compiler []string) []string { + for _, f := range ldflags { + if f == "-extld" || strings.HasPrefix(f, "-extld=") { + // don't override -extld if supplied + return ldflags + } + } + ldflags = append(ldflags, "-extld="+compiler[0]) + if len(compiler) > 1 { + extldflags := false + add := strings.Join(compiler[1:], " ") + for i, f := range ldflags { + if f == "-extldflags" && i+1 < len(ldflags) { + ldflags[i+1] = add + " " + ldflags[i+1] + extldflags = true + break + } else if strings.HasPrefix(f, "-extldflags=") { + ldflags[i] = "-extldflags=" + add + " " + ldflags[i][len("-extldflags="):] + extldflags = true + break + } + } + if !extldflags { + ldflags = append(ldflags, "-extldflags="+add) + } + } + return ldflags +} + +func (gcToolchain) ld(b *builder, root *action, out string, allactions []*action, mainpkg string, ofiles []string) error { importArgs := b.includeArgs("-L", allactions) - cxx := len(p.CXXFiles) > 0 + cxx := len(root.p.CXXFiles) > 0 || len(root.p.SwigCXXFiles) > 0 for _, a := range allactions { - if a.p != nil && len(a.p.CXXFiles) > 0 { + if a.p != nil && (len(a.p.CXXFiles) > 0 || len(a.p.SwigCXXFiles) > 0) { cxx = true } } - ldflags := buildLdflags - // Limit slice capacity so that concurrent appends do not race on the shared array. - ldflags = ldflags[:len(ldflags):len(ldflags)] + var ldflags []string if buildContext.InstallSuffix != "" { ldflags = append(ldflags, "-installsuffix", buildContext.InstallSuffix) } - if p.omitDWARF { + if root.p.omitDWARF { ldflags = append(ldflags, "-w") } @@ -1797,56 +2338,67 @@ func (gcToolchain) ld(b *builder, p *Package, out string, allactions []*action, // appropriate linker. In case of C++ code, use the compiler named // by the CXX environment variable or defaultCXX if CXX is not set. // Else, use the CC environment variable and defaultCC as fallback. - extld := false - for _, f := range ldflags { - if f == "-extld" || strings.HasPrefix(f, "-extld=") { - extld = true - break + var compiler []string + if cxx { + compiler = envList("CXX", defaultCXX) + } else { + compiler = envList("CC", defaultCC) + } + ldflags = setextld(ldflags, compiler) + ldflags = append(ldflags, "-buildmode="+ldBuildmode) + if root.p.buildID != "" { + ldflags = append(ldflags, "-buildid="+root.p.buildID) + } + ldflags = append(ldflags, buildLdflags...) + + // On OS X when using external linking to build a shared library, + // the argument passed here to -o ends up recorded in the final + // shared library in the LC_ID_DYLIB load command. + // To avoid putting the temporary output directory name there + // (and making the resulting shared library useless), + // run the link in the output directory so that -o can name + // just the final path element. + dir := "." + if goos == "darwin" && buildBuildmode == "c-shared" { + dir, out = filepath.Split(out) + } + + return b.run(dir, root.p.ImportPath, nil, buildToolExec, tool("link"), "-o", out, importArgs, ldflags, mainpkg) +} + +func (gcToolchain) ldShared(b *builder, toplevelactions []*action, out string, allactions []*action) error { + importArgs := b.includeArgs("-L", allactions) + ldflags := []string{"-installsuffix", buildContext.InstallSuffix} + ldflags = append(ldflags, "-buildmode=shared") + ldflags = append(ldflags, buildLdflags...) + cxx := false + for _, a := range allactions { + if a.p != nil && (len(a.p.CXXFiles) > 0 || len(a.p.SwigCXXFiles) > 0) { + cxx = true } } - if !extld { - var compiler []string - if cxx { - compiler = envList("CXX", defaultCXX) - } else { - compiler = envList("CC", defaultCC) - } - ldflags = append(ldflags, "-extld="+compiler[0]) - if len(compiler) > 1 { - extldflags := false - add := strings.Join(compiler[1:], " ") - for i, f := range ldflags { - if f == "-extldflags" && i+1 < len(ldflags) { - ldflags[i+1] = add + " " + ldflags[i+1] - extldflags = true - break - } else if strings.HasPrefix(f, "-extldflags=") { - ldflags[i] = "-extldflags=" + add + " " + ldflags[i][len("-extldflags="):] - extldflags = true - break - } - } - if !extldflags { - ldflags = append(ldflags, "-extldflags="+add) - } + // If the user has not specified the -extld option, then specify the + // appropriate linker. In case of C++ code, use the compiler named + // by the CXX environment variable or defaultCXX if CXX is not set. + // Else, use the CC environment variable and defaultCC as fallback. + var compiler []string + if cxx { + compiler = envList("CXX", defaultCXX) + } else { + compiler = envList("CC", defaultCC) + } + ldflags = setextld(ldflags, compiler) + for _, d := range toplevelactions { + if !strings.HasSuffix(d.target, ".a") { // omit unsafe etc and actions for other shared libraries + continue } + ldflags = append(ldflags, d.p.ImportPath+"="+d.target) } - return b.run(".", p.ImportPath, nil, tool(archChar+"l"), "-o", out, importArgs, ldflags, mainpkg) + return b.run(".", out, nil, buildToolExec, tool("link"), "-o", out, importArgs, ldflags) } 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) - warn := []string{"-w"} - if p.usesSwig() { - // When using SWIG, this compiler is only used to - // compile the C files generated by SWIG. - // We don't want warnings. - // See issue 9065 for details. - warn = nil - } - args := stringList(tool(archChar+"c"), "-F", "-V", warn, "-trimpath", b.work, "-I", objdir, "-I", inc, "-o", ofile, buildCcflags, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, cfile) - return b.run(p.Dir, p.ImportPath, nil, args) + return fmt.Errorf("%s: C source files not supported without cgo", mkAbs(p.Dir, cfile)) } // The Gccgo toolchain. @@ -1870,7 +2422,7 @@ func (gccgoToolchain) linker() string { return gccgoBin } -func (tools gccgoToolchain) gc(b *builder, p *Package, archive, obj string, importArgs []string, gofiles []string) (ofile string, output []byte, err error) { +func (tools gccgoToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool, importArgs []string, gofiles []string) (ofile string, output []byte, err error) { out := "_go_.o" ofile = obj + out gcargs := []string{"-g"} @@ -1896,8 +2448,8 @@ func (tools gccgoToolchain) asm(b *builder, p *Package, obj, ofile, sfile string if pkgpath := gccgoCleanPkgpath(p); pkgpath != "" { defs = append(defs, `-D`, `GOPKGPATH="`+pkgpath+`"`) } + defs = tools.maybePIC(defs) defs = append(defs, b.gccArchArgs()...) - return b.run(p.Dir, p.ImportPath, nil, tools.compiler(), "-c", "-I", obj, "-o", ofile, defs, sfile) } @@ -1916,30 +2468,46 @@ func (gccgoToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles return b.run(p.Dir, p.ImportPath, nil, "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 gccgoToolchain) ld(b *builder, root *action, out string, allactions []*action, mainpkg string, ofiles []string) error { // gccgo needs explicit linking with all package dependencies, // and all LDFLAGS from cgo dependencies. apackagesSeen := make(map[*Package]bool) afiles := []string{} + shlibs := []string{} xfiles := []string{} ldflags := b.gccArchArgs() cgoldflags := []string{} usesCgo := false - cxx := len(p.CXXFiles) > 0 - objc := len(p.MFiles) > 0 - - // Prefer the output of an install action to the output of a build action, - // because the install action will delete the output of the build action. - // Iterate over the list backward (reverse dependency order) so that we - // always see the install before the build. - for i := len(allactions) - 1; i >= 0; i-- { - a := allactions[i] - if !a.p.Standard { - if a.p != nil && !apackagesSeen[a.p] { + cxx := len(root.p.CXXFiles) > 0 || len(root.p.SwigCXXFiles) > 0 + objc := len(root.p.MFiles) > 0 + + actionsSeen := make(map[*action]bool) + // Make a pre-order depth-first traversal of the action graph, taking note of + // whether a shared library action has been seen on the way to an action (the + // construction of the graph means that if any path to a node passes through + // a shared library action, they all do). + var walk func(a *action, seenShlib bool) + walk = func(a *action, seenShlib bool) { + if actionsSeen[a] { + return + } + actionsSeen[a] = true + if a.p != nil && !seenShlib { + if a.p.Standard { + return + } + // We record the target of the first time we see a .a file + // for a package to make sure that we prefer the 'install' + // rather than the 'build' location (which may not exist any + // more). We still need to traverse the dependencies of the + // build action though so saying + // if apackagesSeen[a.p] { return } + // doesn't work. + if !apackagesSeen[a.p] { apackagesSeen[a.p] = true if a.p.fake && a.p.external { // external _tests, if present must come before - // internal _tests. Store these on a seperate list + // internal _tests. Store these on a separate list // and place them at the head after this loop. xfiles = append(xfiles, a.target) } else if a.p.fake { @@ -1950,54 +2518,182 @@ func (tools gccgoToolchain) ld(b *builder, p *Package, out string, allactions [] } } } + if strings.HasSuffix(a.target, ".so") { + shlibs = append(shlibs, a.target) + seenShlib = true + } + for _, a1 := range a.deps { + walk(a1, seenShlib) + } + } + for _, a1 := range root.deps { + walk(a1, false) } afiles = append(xfiles, afiles...) for _, a := range allactions { - if a.p != nil { + // Gather CgoLDFLAGS, but not from standard packages. + // The go tool can dig up runtime/cgo from GOROOT and + // think that it should use its CgoLDFLAGS, but gccgo + // doesn't use runtime/cgo. + if a.p == nil { + continue + } + if !a.p.Standard { cgoldflags = append(cgoldflags, a.p.CgoLDFLAGS...) - if len(a.p.CgoFiles) > 0 { - usesCgo = true - } - if a.p.usesSwig() { - usesCgo = true - } - if len(a.p.CXXFiles) > 0 { - cxx = true - } - if len(a.p.MFiles) > 0 { - objc = true - } + } + if len(a.p.CgoFiles) > 0 { + usesCgo = true + } + if a.p.usesSwig() { + usesCgo = true + } + if len(a.p.CXXFiles) > 0 || len(a.p.SwigCXXFiles) > 0 { + cxx = true + } + if len(a.p.MFiles) > 0 { + objc = true } } + + switch ldBuildmode { + case "c-archive", "c-shared": + ldflags = append(ldflags, "-Wl,--whole-archive") + } + ldflags = append(ldflags, afiles...) + + switch ldBuildmode { + case "c-archive", "c-shared": + ldflags = append(ldflags, "-Wl,--no-whole-archive") + } + ldflags = append(ldflags, cgoldflags...) ldflags = append(ldflags, envList("CGO_LDFLAGS", "")...) - ldflags = append(ldflags, p.CgoLDFLAGS...) - if usesCgo && goos == "linux" { - ldflags = append(ldflags, "-Wl,-E") + ldflags = append(ldflags, root.p.CgoLDFLAGS...) + + ldflags = stringList("-Wl,-(", ldflags, "-Wl,-)") + + for _, shlib := range shlibs { + ldflags = append( + ldflags, + "-L"+filepath.Dir(shlib), + "-Wl,-rpath="+filepath.Dir(shlib), + "-l"+strings.TrimSuffix( + strings.TrimPrefix(filepath.Base(shlib), "lib"), + ".so")) } - if cxx { - ldflags = append(ldflags, "-lstdc++") + + var realOut string + switch ldBuildmode { + case "exe": + if usesCgo && goos == "linux" { + ldflags = append(ldflags, "-Wl,-E") + } + + case "c-archive": + // Link the Go files into a single .o, and also link + // in -lgolibbegin. + // + // We need to use --whole-archive with -lgolibbegin + // because it doesn't define any symbols that will + // cause the contents to be pulled in; it's just + // initialization code. + // + // The user remains responsible for linking against + // -lgo -lpthread -lm in the final link. We can't use + // -r to pick them up because we can't combine + // split-stack and non-split-stack code in a single -r + // link, and libgo picks up non-split-stack code from + // libffi. + ldflags = append(ldflags, "-Wl,-r", "-nostdlib", "-Wl,--whole-archive", "-lgolibbegin", "-Wl,--no-whole-archive") + + // We are creating an object file, so we don't want a build ID. + ldflags = b.disableBuildID(ldflags) + + realOut = out + out = out + ".o" + + case "c-shared": + ldflags = append(ldflags, "-shared", "-nostdlib", "-Wl,--whole-archive", "-lgolibbegin", "-Wl,--no-whole-archive", "-lgo", "-lgcc_s", "-lgcc") + + default: + fatalf("-buildmode=%s not supported for gccgo", ldBuildmode) + } + + switch ldBuildmode { + case "exe", "c-shared": + if cxx { + ldflags = append(ldflags, "-lstdc++") + } + if objc { + ldflags = append(ldflags, "-lobjc") + } } - if objc { - ldflags = append(ldflags, "-lobjc") + + if err := b.run(".", root.p.ImportPath, nil, tools.linker(), "-o", out, ofiles, ldflags, buildGccgoflags); err != nil { + return err + } + + switch ldBuildmode { + case "c-archive": + if err := b.run(".", root.p.ImportPath, nil, "ar", "rc", realOut, out); err != nil { + return err + } } - return b.run(".", p.ImportPath, nil, tools.linker(), "-o", out, ofiles, "-Wl,-(", ldflags, "-Wl,-)", buildGccgoflags) + return nil } -func (gccgoToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error { - inc := filepath.Join(goroot, "pkg", fmt.Sprintf("%s_%s", goos, goarch)) +func (tools gccgoToolchain) ldShared(b *builder, toplevelactions []*action, out string, allactions []*action) error { + args := []string{"-o", out, "-shared", "-nostdlib", "-zdefs", "-Wl,--whole-archive"} + for _, a := range toplevelactions { + args = append(args, a.target) + } + args = append(args, "-Wl,--no-whole-archive", "-shared", "-nostdlib", "-lgo", "-lgcc_s", "-lgcc", "-lc") + shlibs := []string{} + for _, a := range allactions { + if strings.HasSuffix(a.target, ".so") { + shlibs = append(shlibs, a.target) + } + } + for _, shlib := range shlibs { + args = append( + args, + "-L"+filepath.Dir(shlib), + "-Wl,-rpath="+filepath.Dir(shlib), + "-l"+strings.TrimSuffix( + strings.TrimPrefix(filepath.Base(shlib), "lib"), + ".so")) + } + return b.run(".", out, nil, tools.linker(), args, buildGccgoflags) +} + +func (tools gccgoToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error { + inc := filepath.Join(goroot, "pkg", "include") cfile = mkAbs(p.Dir, cfile) defs := []string{"-D", "GOOS_" + goos, "-D", "GOARCH_" + goarch} defs = append(defs, b.gccArchArgs()...) if pkgpath := gccgoCleanPkgpath(p); pkgpath != "" { defs = append(defs, `-D`, `GOPKGPATH="`+pkgpath+`"`) } + switch goarch { + case "386", "amd64": + defs = append(defs, "-fsplit-stack") + } + defs = tools.maybePIC(defs) return b.run(p.Dir, p.ImportPath, nil, envList("CC", defaultCC), "-Wall", "-g", "-I", objdir, "-I", inc, "-o", ofile, defs, "-c", cfile) } +// maybePIC adds -fPIC to the list of arguments if needed. +func (tools gccgoToolchain) maybePIC(args []string) []string { + switch buildBuildmode { + case "c-shared", "shared": + args = append(args, "-fPIC") + } + return args +} + func gccgoPkgpath(p *Package) string { if p.build.IsCommand() && !p.forceLibrary { return "" @@ -2073,7 +2769,7 @@ func (b *builder) ccompile(p *Package, out string, flags []string, file string, // gccld runs the gcc linker to create an executable from a set of object files. func (b *builder) gccld(p *Package, out string, flags []string, obj []string) error { var cmd []string - if len(p.CXXFiles) > 0 { + if len(p.CXXFiles) > 0 || len(p.SwigCXXFiles) > 0 { cmd = b.gxxCmd(p.Dir) } else { cmd = b.gccCmd(p.Dir) @@ -2132,7 +2828,7 @@ func (b *builder) ccompilerCmd(envvar, defcmd, objdir string) []string { // 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. + // See https://golang.org/issue/3253. if goos == "darwin" { a = append(a, "-fno-common") } @@ -2142,12 +2838,12 @@ func (b *builder) ccompilerCmd(envvar, defcmd, objdir string) []string { // gccArchArgs returns arguments to pass to gcc based on the architecture. func (b *builder) gccArchArgs() []string { - switch archChar { - case "8": + switch goarch { + case "386": return []string{"-m32"} - case "6": + case "amd64", "amd64p32": return []string{"-m64"} - case "5": + case "arm": return []string{"-marm"} // not thumb } return nil @@ -2185,7 +2881,7 @@ var ( cgoLibGccFileOnce sync.Once ) -func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, gccfiles, gxxfiles, mfiles []string) (outGo, outObj []string, err error) { +func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, cgofiles, gccfiles, gxxfiles, mfiles []string) (outGo, outObj []string, err error) { cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, cgoLDFLAGS := b.cflags(p, true) _, cgoexeCFLAGS, _, _ := b.cflags(p, false) cgoCPPFLAGS = append(cgoCPPFLAGS, pcCFLAGS...) @@ -2202,7 +2898,7 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, gccfi // TODO: CGOPKGPATH, CGO_FLAGS? gofiles := []string{obj + "_cgo_gotypes.go"} cfiles := []string{"_cgo_main.c", "_cgo_export.c"} - for _, fn := range p.CgoFiles { + for _, fn := range cgofiles { f := cgoRe.ReplaceAllString(fn[:len(fn)-2], "_") gofiles = append(gofiles, obj+f+"cgo1.go") cfiles = append(cfiles, f+"cgo2.c") @@ -2212,8 +2908,6 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, gccfi 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") } @@ -2232,23 +2926,38 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, gccfi } if _, ok := buildToolchain.(gccgoToolchain); ok { + switch goarch { + case "386", "amd64": + cgoCFLAGS = append(cgoCFLAGS, "-fsplit-stack") + } cgoflags = append(cgoflags, "-gccgo") if pkgpath := gccgoPkgpath(p); pkgpath != "" { cgoflags = append(cgoflags, "-gccgopkgpath="+pkgpath) } - objExt = "o" } - if err := b.run(p.Dir, p.ImportPath, cgoenv, cgoExe, "-objdir", obj, cgoflags, "--", cgoCPPFLAGS, cgoexeCFLAGS, p.CgoFiles); err != nil { + + switch buildBuildmode { + case "c-archive", "c-shared": + // Tell cgo that if there are any exported functions + // it should generate a header file that C code can + // #include. + cgoflags = append(cgoflags, "-exportheader="+obj+"_cgo_install.h") + } + + if err := b.run(p.Dir, p.ImportPath, cgoenv, buildToolExec, cgoExe, "-objdir", obj, "-importpath", p.ImportPath, cgoflags, "--", cgoCPPFLAGS, cgoexeCFLAGS, cgofiles); err != nil { return nil, nil, err } outGo = append(outGo, gofiles...) // cc _cgo_defun.c - defunObj := obj + "_cgo_defun." + objExt - if err := buildToolchain.cc(b, p, obj, defunObj, defunC); err != nil { - return nil, nil, err + _, gccgo := buildToolchain.(gccgoToolchain) + if gccgo { + defunObj := obj + "_cgo_defun.o" + if err := buildToolchain.cc(b, p, obj, defunObj, defunC); err != nil { + return nil, nil, err + } + outObj = append(outObj, defunObj) } - outObj = append(outObj, defunObj) // gcc var linkobj []string @@ -2362,20 +3071,15 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, gccfi } // cgo -dynimport - importC := obj + "_cgo_import.c" + importGo := obj + "_cgo_import.go" cgoflags = []string{} if p.Standard && p.ImportPath == "runtime/cgo" { cgoflags = append(cgoflags, "-dynlinker") // record path to dynamic linker } - if err := b.run(p.Dir, p.ImportPath, nil, cgoExe, "-objdir", obj, "-dynimport", dynobj, "-dynout", importC, cgoflags); err != nil { - return nil, nil, err - } - - // cc _cgo_import.ARCH - importObj := obj + "_cgo_import." + objExt - if err := buildToolchain.cc(b, p, obj, importObj, importC); err != nil { + if err := b.run(p.Dir, p.ImportPath, nil, buildToolExec, cgoExe, "-objdir", obj, "-dynpackage", p.Name, "-dynimport", dynobj, "-dynout", importGo, cgoflags); err != nil { return nil, nil, err } + outGo = append(outGo, importGo) ofile := obj + "_all.o" var gccObjs, nonGccObjs []string @@ -2388,19 +3092,8 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, gccfi } ldflags := stringList(bareLDFLAGS, "-Wl,-r", "-nostdlib", staticLibs) - // Some systems, such as Ubuntu, always add --build-id to - // every link, but we don't want a build ID since we are - // producing an object file. On some of those system a plain - // -r (not -Wl,-r) will turn off --build-id, but clang 3.0 - // doesn't support a plain -r. I don't know how to turn off - // --build-id when using clang other than passing a trailing - // --build-id=none. So that is what we do, but only on - // systems likely to support it, which is to say, systems that - // normally use gold or the GNU linker. - switch goos { - case "android", "dragonfly", "linux", "netbsd": - ldflags = append(ldflags, "-Wl,--build-id=none") - } + // We are creating an object file, so we don't want a build ID. + ldflags = b.disableBuildID(ldflags) if err := b.gccld(p, ofile, ldflags, gccObjs); err != nil { return nil, nil, err @@ -2408,8 +3101,8 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, gccfi // NOTE(rsc): The importObj is a 5c/6c/8c object and on Windows // must be processed before the gcc-generated objects. - // Put it first. http://golang.org/issue/2601 - outObj = stringList(importObj, nonGccObjs, ofile) + // Put it first. https://golang.org/issue/2601 + outObj = stringList(nonGccObjs, ofile) return outGo, outObj, nil } @@ -2417,77 +3110,41 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, gccfi // Run SWIG on all SWIG input files. // TODO: Don't build a shared library, once SWIG emits the necessary // pragmas for external linking. -func (b *builder) swig(p *Package, obj string, pcCFLAGS, gccfiles, gxxfiles, mfiles []string) (outGo, outObj []string, err error) { - cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _ := b.cflags(p, true) - cflags := stringList(cgoCPPFLAGS, cgoCFLAGS) - cxxflags := stringList(cgoCPPFLAGS, cgoCXXFLAGS) - - for _, file := range gccfiles { - ofile := obj + cgoRe.ReplaceAllString(file[:len(file)-1], "_") + "o" - if err := b.gcc(p, ofile, cflags, file); err != nil { - return nil, nil, err - } - outObj = append(outObj, ofile) - } - - for _, file := range gxxfiles { - // Append .o to the file, just in case the pkg has file.c and file.cpp - ofile := obj + cgoRe.ReplaceAllString(file, "_") + ".o" - if err := b.gxx(p, ofile, cxxflags, file); err != nil { - return nil, nil, err - } - outObj = append(outObj, ofile) - } - - for _, file := range mfiles { - // Append .o to the file, just in case the pkg has file.c and file.cpp - ofile := obj + cgoRe.ReplaceAllString(file, "_") + ".o" - if err := b.gcc(p, ofile, cflags, file); err != nil { - return nil, nil, err - } - outObj = append(outObj, ofile) - } - +func (b *builder) swig(p *Package, obj string, pcCFLAGS []string) (outGo, outC, outCXX []string, err error) { if err := b.swigVersionCheck(); err != nil { - return nil, nil, err + return nil, nil, nil, err } intgosize, err := b.swigIntSize(obj) if err != nil { - return nil, nil, err + return nil, nil, nil, err } for _, f := range p.SwigFiles { - goFile, objFile, gccObjFile, err := b.swigOne(p, f, obj, pcCFLAGS, false, intgosize) + goFile, cFile, err := b.swigOne(p, f, obj, pcCFLAGS, false, intgosize) if err != nil { - return nil, nil, err + return nil, nil, nil, err } if goFile != "" { outGo = append(outGo, goFile) } - if objFile != "" { - outObj = append(outObj, objFile) - } - if gccObjFile != "" { - outObj = append(outObj, gccObjFile) + if cFile != "" { + outC = append(outC, cFile) } } for _, f := range p.SwigCXXFiles { - goFile, objFile, gccObjFile, err := b.swigOne(p, f, obj, pcCFLAGS, true, intgosize) + goFile, cxxFile, err := b.swigOne(p, f, obj, pcCFLAGS, true, intgosize) if err != nil { - return nil, nil, err + return nil, nil, nil, err } if goFile != "" { outGo = append(outGo, goFile) } - if objFile != "" { - outObj = append(outObj, objFile) - } - if gccObjFile != "" { - outObj = append(outObj, gccObjFile) + if cxxFile != "" { + outCXX = append(outCXX, cxxFile) } } - return outGo, outObj, nil + return outGo, outC, outCXX, nil } // Make sure SWIG is new enough. @@ -2501,20 +3158,51 @@ func (b *builder) swigDoVersionCheck() error { if err != nil { return err } - re := regexp.MustCompile(`[vV]ersion +([\d])`) + re := regexp.MustCompile(`[vV]ersion +([\d]+)([.][\d]+)?([.][\d]+)?`) matches := re.FindSubmatch(out) if matches == nil { // Can't find version number; hope for the best. return nil } + major, err := strconv.Atoi(string(matches[1])) if err != nil { // Can't find version number; hope for the best. return nil } + const errmsg = "must have SWIG version >= 3.0.6" if major < 3 { - return errors.New("must have SWIG version >= 3.0") + return errors.New(errmsg) + } + if major > 3 { + // 4.0 or later + return nil + } + + // We have SWIG version 3.x. + if len(matches[2]) > 0 { + minor, err := strconv.Atoi(string(matches[2][1:])) + if err != nil { + return nil + } + if minor > 0 { + // 3.1 or later + return nil + } } + + // We have SWIG version 3.0.x. + if len(matches[3]) > 0 { + patch, err := strconv.Atoi(string(matches[3][1:])) + if err != nil { + return nil + } + if patch < 6 { + // Before 3.0.6. + return errors.New(errmsg) + } + } + return nil } @@ -2545,14 +3233,14 @@ func (b *builder) swigIntSize(obj string) (intsize string, err error) { p := goFilesPackage(srcs) - if _, _, e := buildToolchain.gc(b, p, "", obj, nil, srcs); e != nil { + if _, _, e := buildToolchain.gc(b, p, "", obj, false, nil, srcs); e != nil { return "32", nil } return "64", nil } // Run SWIG on one SWIG input file. -func (b *builder) swigOne(p *Package, file, obj string, pcCFLAGS []string, cxx bool, intgosize string) (outGo, outObj, objGccObj string, err error) { +func (b *builder) swigOne(p *Package, file, obj string, pcCFLAGS []string, cxx bool, intgosize string) (outGo, outC string, err error) { cgoCPPFLAGS, cgoCFLAGS, cgoCXXFLAGS, _ := b.cflags(p, true) var cflags []string if cxx { @@ -2567,7 +3255,6 @@ func (b *builder) swigOne(p *Package, file, obj string, pcCFLAGS []string, cxx b } base := file[:len(file)-n] goFile := base + ".go" - cBase := base + "_gc." gccBase := base + "_wrap." gccExt := "c" if cxx { @@ -2579,6 +3266,7 @@ func (b *builder) swigOne(p *Package, file, obj string, pcCFLAGS []string, cxx b // swig args := []string{ "-go", + "-cgo", "-intgosize", intgosize, "-module", base, "-o", obj + gccBase + gccExt, @@ -2601,39 +3289,40 @@ func (b *builder) swigOne(p *Package, file, obj string, pcCFLAGS []string, cxx b args = append(args, "-c++") } - if out, err := b.runOut(p.Dir, p.ImportPath, nil, "swig", args, file); err != nil { + out, err := b.runOut(p.Dir, p.ImportPath, nil, "swig", args, file) + if err != nil { if len(out) > 0 { - if bytes.Contains(out, []byte("Unrecognized option -intgosize")) { - return "", "", "", errors.New("must have SWIG version >= 3.0") + if bytes.Contains(out, []byte("-intgosize")) || bytes.Contains(out, []byte("-cgo")) { + return "", "", errors.New("must have SWIG version >= 3.0.6") } - b.showOutput(p.Dir, p.ImportPath, b.processOutput(out)) - return "", "", "", errPrintedOutput + b.showOutput(p.Dir, p.ImportPath, b.processOutput(out)) // swig error + return "", "", errPrintedOutput } - return "", "", "", err + return "", "", err } - - var cObj string - if !gccgo { - // cc - cObj = obj + cBase + archChar - if err := buildToolchain.cc(b, p, obj, cObj, obj+cBase+"c"); err != nil { - return "", "", "", err - } + if len(out) > 0 { + b.showOutput(p.Dir, p.ImportPath, b.processOutput(out)) // swig warning } - // gcc - gccObj := obj + gccBase + "o" - if !cxx { - if err := b.gcc(p, gccObj, cflags, obj+gccBase+gccExt); err != nil { - return "", "", "", err - } - } else { - if err := b.gxx(p, gccObj, cflags, obj+gccBase+gccExt); err != nil { - return "", "", "", err - } - } + return obj + goFile, obj + gccBase + gccExt, nil +} - return obj + goFile, cObj, gccObj, nil +// disableBuildID adjusts a linker command line to avoid creating a +// build ID when creating an object file rather than an executable or +// shared library. Some systems, such as Ubuntu, always add +// --build-id to every link, but we don't want a build ID when we are +// producing an object file. On some of those system a plain -r (not +// -Wl,-r) will turn off --build-id, but clang 3.0 doesn't support a +// plain -r. I don't know how to turn off --build-id when using clang +// other than passing a trailing --build-id=none. So that is what we +// do, but only on systems likely to support it, which is to say, +// systems that normally use gold or the GNU linker. +func (b *builder) disableBuildID(ldflags []string) []string { + switch goos { + case "android", "dragonfly", "linux", "netbsd": + ldflags = append(ldflags, "-Wl,--build-id=none") + } + return ldflags } // An actionQueue is a priority queue of actions. @@ -2669,7 +3358,6 @@ func raceInit() { } buildGcflags = append(buildGcflags, "-race") buildLdflags = append(buildLdflags, "-race") - buildCcflags = append(buildCcflags, "-D", "RACE") if buildContext.InstallSuffix != "" { buildContext.InstallSuffix += "_" } diff --git a/libgo/go/cmd/go/doc.go b/libgo/go/cmd/go/doc.go index 7191ee0f3a9..4a07dfe11f4 100644 --- a/libgo/go/cmd/go/doc.go +++ b/libgo/go/cmd/go/doc.go @@ -1,1131 +1,103 @@ -// Copyright 2011 The Go Authors. All rights reserved. +// Copyright 2015 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. -// DO NOT EDIT THIS FILE. GENERATED BY mkdoc.sh. -// Edit the documentation in other files and rerun mkdoc.sh to generate this one. - -/* -Go is a tool for managing Go source code. - -Usage: - - go command [arguments] - -The commands are: - - build compile packages and dependencies - clean remove object files - env print Go environment information - fix run go tool fix on packages - fmt run gofmt on package sources - generate generate Go files by processing source - get download and install packages and dependencies - install compile and install packages and dependencies - list list packages - run compile and run Go program - test test packages - tool run specified go tool - version print Go version - vet run go tool vet on packages - -Use "go help [command]" for more information about a command. - -Additional help topics: - - c calling between Go and C - filetype file types - gopath GOPATH environment variable - importpath import path syntax - packages description of package lists - testflag description of testing flags - testfunc description of testing functions - -Use "go help [topic]" for more information about that topic. - - -Compile packages and dependencies - -Usage: - - go build [-o output] [-i] [build flags] [packages] - -Build compiles the packages named by the import paths, -along with their dependencies, but it does not install the results. - -If the arguments are a list of .go files, build treats them as a list -of source files specifying a single package. - -When the command line specifies a single main package, -build writes the resulting executable to output. -Otherwise build compiles the packages but discards the results, -serving only as a check that the packages can be built. - -The -o flag specifies the output file name. If not specified, the -output file name depends on the arguments and derives from the name -of the package, such as p.a for package p, unless p is 'main'. If -the package is main and file names are provided, the file name -derives from the first file name mentioned, such as f1 for 'go build -f1.go f2.go'; with no files provided ('go build'), the output file -name is the base name of the containing directory. - -The -i flag installs the packages that are dependencies of the target. - -The build flags are shared by the build, clean, get, install, list, run, -and test commands: - - -a - force rebuilding of packages that are already up-to-date. - In Go releases, does not apply to the standard library. - -n - print the commands but do not run them. - -p n - the number of builds that can be run in parallel. - The default is the number of CPUs available. - -race - enable data race detection. - Supported only on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64. - -v - print the names of packages as they are compiled. - -work - print the name of the temporary work directory and - do not delete it when exiting. - -x - print the commands. - - -ccflags 'arg list' - arguments to pass on each 5c, 6c, or 8c compiler invocation. - -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' - arguments to pass on each 5g, 6g, or 8g compiler invocation. - -installsuffix suffix - a suffix to use in the name of the package installation directory, - in order to keep output separate from default builds. - If using the -race flag, the install suffix is automatically set to race - or, if set explicitly, has _race appended to it. - -ldflags 'flag list' - arguments to pass on each 5l, 6l, or 8l linker invocation. - -tags 'tag list' - a list of build tags to consider satisfied during the build. - For more information about build tags, see the description of - build constraints in the documentation for the go/build package. - -The list flags accept a space-separated list of strings. To embed spaces -in an element in the list, surround it with either single or double quotes. - -For more about specifying packages, see 'go help packages'. -For more about where packages and binaries are installed, -run 'go help gopath'. For more about calling between Go and C/C++, -run 'go help c'. - -See also: go install, go get, go clean. - - -Remove object files - -Usage: - - go clean [-i] [-r] [-n] [-x] [build flags] [packages] - -Clean removes object files from package source directories. -The go command builds most objects in a temporary directory, -so go clean is mainly concerned with object files left by other -tools or by manual invocations of go build. - -Specifically, clean removes the following files from each of the -source directories corresponding to the import paths: - - _obj/ old object directory, left from Makefiles - _test/ old test directory, left from Makefiles - _testmain.go old gotest file, left from Makefiles - test.out old test log, left from Makefiles - build.out old test log, left from Makefiles - *.[568ao] object files, left from Makefiles - - DIR(.exe) from go build - DIR.test(.exe) from go test -c - MAINFILE(.exe) from go build MAINFILE.go - *.so from SWIG - -In the list, DIR represents the final path element of the -directory, and MAINFILE is the base name of any Go source -file in the directory that is not included when building -the package. - -The -i flag causes clean to remove the corresponding installed -archive or binary (what 'go install' would create). - -The -n flag causes clean to print the remove commands it would execute, -but not run them. - -The -r flag causes clean to be applied recursively to all the -dependencies of the packages named by the import paths. - -The -x flag causes clean to print remove commands as it executes them. - -For more about build flags, see 'go help build'. - -For more about specifying packages, see 'go help packages'. - - -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: - - go fix [packages] - -Fix runs the Go fix command on the packages named by the import paths. - -For more about fix, see 'godoc fix'. -For more about specifying packages, see 'go help packages'. - -To run fix with specific options, run 'go tool fix'. - -See also: go fmt, go vet. - - -Run gofmt on package sources - -Usage: - - go fmt [-n] [-x] [packages] - -Fmt runs the command 'gofmt -l -w' on the packages named -by the import paths. It prints the names of the files that are modified. - -For more about gofmt, see 'godoc gofmt'. -For more about specifying packages, see 'go help packages'. - -The -n flag prints commands that would be executed. -The -x flag prints commands as they are executed. - -To run gofmt with specific options, run gofmt itself. - -See also: go fix, go vet. - - -Generate Go files by processing source - -Usage: - - go generate [-run regexp] [file.go... | packages] - -Generate runs commands described by directives within existing -files. Those commands can run any process but the intent is to -create or update Go source files, for instance by running yacc. - -Go generate is never run automatically by go build, go get, go test, -and so on. It must be run explicitly. - -Go generate scans the file for directives, which are lines of -the form, - - //go:generate command argument... - -(note: no leading spaces and no space in "//go") where command -is the generator to be run, corresponding to an executable file -that can be run locally. It must either be in the shell path -(gofmt), a fully qualified path (/usr/you/bin/mytool), or a -command alias, described below. - -Note that go generate does not parse the file, so lines that look -like directives in comments or multiline strings will be treated -as directives. - -The arguments to the directive are space-separated tokens or -double-quoted strings passed to the generator as individual -arguments when it is run. - -Quoted strings use Go syntax and are evaluated before execution; a -quoted string appears as a single argument to the generator. - -Go generate sets several variables when it runs the generator: - - $GOARCH - The execution architecture (arm, amd64, etc.) - $GOOS - The execution operating system (linux, windows, etc.) - $GOFILE - The base name of the file. - $GOPACKAGE - The name of the package of the file containing the directive. - -Other than variable substitution and quoted-string evaluation, no -special processing such as "globbing" is performed on the command -line. - -As a last step before running the command, any invocations of any -environment variables with alphanumeric names, such as $GOFILE or -$HOME, are expanded throughout the command line. The syntax for -variable expansion is $NAME on all operating systems. Due to the -order of evaluation, variables are expanded even inside quoted -strings. If the variable NAME is not set, $NAME expands to the -empty string. - -A directive of the form, - - //go:generate -command xxx args... - -specifies, for the remainder of this source file only, that the -string xxx represents the command identified by the arguments. This -can be used to create aliases or to handle multiword generators. -For example, - - //go:generate -command yacc go tool yacc - -specifies that the command "yacc" represents the generator -"go tool yacc". - -Generate processes packages in the order given on the command line, -one at a time. If the command line lists .go files, they are treated -as a single package. Within a package, generate processes the -source files in a package in file name order, one at a time. Within -a source file, generate runs generators in the order they appear -in the file, one at a time. - -If any generator returns an error exit status, "go generate" skips -all further processing for that package. - -The generator is run in the package's source directory. - -Go generate accepts one specific flag: - - -run="" - TODO: This flag is unimplemented. - if non-empty, specifies a regular expression to - select directives whose command matches the expression. - -It also accepts the standard build flags -v, -n, and -x. -The -v flag prints the names of packages and files as they are -processed. -The -n flag prints commands that would be executed. -The -x flag prints commands as they are executed. - -For more about specifying packages, see 'go help packages'. - - -Download and install packages and dependencies - -Usage: - - go get [-d] [-f] [-fix] [-t] [-u] [build flags] [packages] - -Get downloads and installs the packages named by the import paths, -along with their dependencies. - -The -d flag instructs get to stop after downloading the packages; that is, -it instructs get not to install the packages. - -The -f flag, valid only when -u is set, forces get -u not to verify that -each package has been checked out from the source control repository -implied by its import path. This can be useful if the source is a local fork -of the original. - -The -fix flag instructs get to run the fix tool on the downloaded packages -before resolving dependencies or building the code. - -The -t flag instructs get to also download the packages required to build -the tests for the specified packages. - -The -u flag instructs get to use the network to update the named packages -and their dependencies. By default, get uses the network to check out -missing packages but does not use it to look for updates to existing packages. - -Get also accepts build flags to control the installation. See 'go help build'. - -When checking out or updating a package, get looks for a branch or tag -that matches the locally installed version of Go. The most important -rule is that if the local installation is running version "go1", get -searches for a branch or tag named "go1". If no such version exists it -retrieves the most recent version of the package. - -For more about specifying packages, see 'go help packages'. - -For more about how 'go get' finds source code to -download, see 'go help importpath'. - -See also: go build, go install, go clean. - - -Compile and install packages and dependencies - -Usage: - - go install [build flags] [packages] - -Install compiles and installs the packages named by the import paths, -along with their dependencies. - -For more about the build flags, see 'go help build'. -For more about specifying packages, see 'go help packages'. - -See also: go build, go get, go clean. - - -List packages - -Usage: - - go list [-e] [-f format] [-json] [build flags] [packages] - -List lists the packages named by the import paths, one per line. - -The default output shows the package import path: - - code.google.com/p/google-api-go-client/books/v1 - code.google.com/p/goauth2/oauth - code.google.com/p/sqlite - -The -f flag specifies an alternate format for the list, using the -syntax of package template. The default output is equivalent to -f -'{{.ImportPath}}'. The struct being passed to the template is: - - type Package struct { - Dir string // directory containing package sources - ImportPath string // import path of package in dir - ImportComment string // path in import comment on package statement - Name string // package name - Doc string // package documentation string - Target string // install path - Goroot bool // is this package in the Go root? - Standard bool // is this package part of the standard Go library? - Stale bool // would 'go install' do anything for this package? - Root string // Go root or Go path dir containing this package - - // Source files - GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles) - CgoFiles []string // .go sources files that import "C" - IgnoredGoFiles []string // .go sources ignored due to build constraints - CFiles []string // .c source files - CXXFiles []string // .cc, .cxx and .cpp source files - MFiles []string // .m source files - HFiles []string // .h, .hh, .hpp and .hxx source files - SFiles []string // .s source files - SwigFiles []string // .swig files - SwigCXXFiles []string // .swigcxx files - SysoFiles []string // .syso object files to add to archive - - // Cgo directives - CgoCFLAGS []string // cgo: flags for C compiler - CgoCPPFLAGS []string // cgo: flags for C preprocessor - CgoCXXFLAGS []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 - 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 template function "join" calls strings.Join. - -The template function "context" returns the build context, defined as: - - type Context struct { - GOARCH string // target architecture - GOOS string // target operating system - GOROOT string // Go root - GOPATH string // Go path - CgoEnabled bool // whether cgo can be used - UseAllFiles bool // use files regardless of +build lines, file names - Compiler string // compiler to assume when computing target paths - BuildTags []string // build constraints to match in +build lines - ReleaseTags []string // releases the current release is compatible with - InstallSuffix string // suffix to use in the name of the install dir - } - -For more information about the meaning of these fields see the documentation -for the go/build package's Context type. - -The -json flag causes the package data to be printed in JSON format -instead of using the template format. - -The -e flag changes the handling of erroneous packages, those that -cannot be found or are malformed. By default, the list command -prints an error to standard error for each erroneous package and -omits the packages from consideration during the usual printing. -With the -e flag, the list command never prints errors to standard -error and instead processes the erroneous packages with the usual -printing. Erroneous packages will have a non-empty ImportPath and -a non-nil Error field; other information may or may not be missing -(zeroed). - -For more about build flags, see 'go help build'. - -For more about specifying packages, see 'go help packages'. - - -Compile and run Go program - -Usage: - - go run [build flags] [-exec xprog] gofiles... [arguments...] - -Run compiles and runs the main package comprising the named Go source files. -A Go source file is defined to be a file ending in a literal ".go" suffix. - -By default, 'go run' runs the compiled binary directly: 'a.out arguments...'. -If the -exec flag is given, 'go run' invokes the binary using xprog: 'xprog a.out arguments...'. -If the -exec flag is not given, GOOS or GOARCH is different from the system -default, and a program named go_$GOOS_$GOARCH_exec can be found -on the current search path, 'go run' invokes the binary using that program, -for example 'go_nacl_386_exec a.out arguments...'. This allows execution of -cross-compiled programs when a simulator or other execution method is -available. - -For more about build flags, see 'go help build'. - -See also: go build. - - -Test packages - -Usage: - - go test [-c] [-i] [build and test flags] [packages] [flags for test binary] - -'Go test' automates testing the packages named by the import paths. -It prints a summary of the test results in the format: - - ok archive/tar 0.011s - FAIL archive/zip 0.022s - ok compress/gzip 0.033s - ... - -followed by detailed output for each failed package. - -'Go test' recompiles each package along with any files with names matching -the file pattern "*_test.go". -Files whose names begin with "_" (including "_test.go") or "." are ignored. -These additional files can contain test functions, benchmark functions, and -example functions. See 'go help testfunc' for more. -Each listed package causes the execution of a separate test binary. - -Test files that declare a package with the suffix "_test" will be compiled as a -separate package, and then linked and run with the main test binary. - -By default, go test needs no arguments. It compiles and tests the package -with source in the current directory, including tests, and runs the tests. - -The package is built in a temporary directory so it does not interfere with the -non-test installation. - -In addition to the build flags, the flags handled by 'go test' itself are: +package main +var cmdDoc = &Command{ + Run: runDoc, + UsageLine: "doc [-u] [-c] [package|[package.]symbol[.method]]", + CustomFlags: true, + Short: "show documentation for package or symbol", + Long: ` +Doc prints the documentation comments associated with the item identified by its +arguments (a package, const, func, type, var, or method) followed by a one-line +summary of each of the first-level items "under" that item (package-level +declarations for a package, methods for a type, etc.). + +Doc accepts zero, one, or two arguments. + +Given no arguments, that is, when run as + + go doc + +it prints the package documentation for the package in the current directory. +If the package is a command (package main), the exported symbols of the package +are elided from the presentation unless the -cmd flag is provided. + +When run with one argument, the argument is treated as a Go-syntax-like +representation of the item to be documented. What the argument selects depends +on what is installed in GOROOT and GOPATH, as well as the form of the argument, +which is schematically one of these: + + go doc + go doc [.] + go doc [].[.] + +The first item in this list matched by the argument is the one whose +documentation is printed. (See the examples below.) For packages, the order of +scanning is determined lexically, but the GOROOT tree is always scanned before +GOPATH. + +If there is no package specified or matched, the package in the current +directory is selected, so "go doc Foo" shows the documentation for symbol Foo in +the current package. + +The package path must be either a qualified path or a proper suffix of a +path. The go tool's usual package mechanism does not apply: package path +elements like . and ... are not implemented by go doc. + +When run with two arguments, the first must be a full package path (not just a +suffix), and the second is a symbol or symbol and method; this is similar to the +syntax accepted by godoc: + + go doc [.] + +In all forms, when matching symbols, lower-case letters in the argument match +either case but upper-case letters match exactly. This means that there may be +multiple matches of a lower-case argument in a package if different symbols have +different cases. If this occurs, documentation for all matches is printed. + +Examples: + go doc + Show documentation for current package. + go doc Foo + Show documentation for Foo in the current package. + (Foo starts with a capital letter so it cannot match + a package path.) + go doc encoding/json + Show documentation for the encoding/json package. + go doc json + Shorthand for encoding/json. + go doc json.Number (or go doc json.number) + Show documentation and method summary for json.Number. + go doc json.Number.Int64 (or go doc json.number.int64) + Show documentation for json.Number's Int64 method. + go doc cmd/doc + Show package docs for the doc command. + go doc -cmd cmd/doc + Show package docs and exported symbols within the doc command. + go doc template.new + Show documentation for html/template's New function. + (html/template is lexically before text/template) + go doc text/template.new # One argument + Show documentation for text/template's New function. + go doc text/template new # Two arguments + Show documentation for text/template's New function. + +Flags: -c - Compile the test binary to pkg.test but do not run it - (where pkg is the last element of the package's import path). - The file name can be changed with the -o flag. - - -exec xprog - Run the test binary using xprog. The behavior is the same as - in 'go run'. See 'go help run' for details. - - -i - Install packages that are dependencies of the test. - Do not run the test. - - -o file - Compile the test binary to the named file. - The test still runs (unless -c or -i is specified). - - -The test binary also accepts flags that control execution of the test; these -flags are also accessible by 'go test'. See 'go help testflag' for details. - -If the test binary needs any other flags, they should be presented after the -package names. The go tool treats as a flag the first argument that begins with -a minus sign that it does not recognize itself; that argument and all subsequent -arguments are passed as arguments to the test binary. - -For more about build flags, see 'go help build'. -For more about specifying packages, see 'go help packages'. - -See also: go build, go vet. - - -Run specified go tool - -Usage: - - go tool [-n] command [args...] - -Tool runs the go tool command identified by the arguments. -With no arguments it prints the list of known tools. - -The -n flag causes tool to print the command that would be -executed but not execute it. - -For more about each tool command, see 'go tool command -h'. - - -Print Go version - -Usage: - - go version - -Version prints the Go version, as reported by runtime.Version. - - -Run go tool vet on packages - -Usage: - - go vet [-n] [-x] [packages] - -Vet runs the Go vet command on the packages named by the import paths. - -For more about vet, see 'godoc golang.org/x/tools/cmd/vet'. -For more about specifying packages, see 'go help packages'. - -To run the vet tool with specific options, run 'go tool vet'. - -The -n flag prints commands that would be executed. -The -x flag prints commands as they are executed. - -See also: go fmt, go fix. - - -Calling between Go and C - -There are two different ways to call between Go and C/C++ code. - -The first is the cgo tool, which is part of the Go distribution. For -information on how to use it see the cgo documentation (godoc cmd/cgo). - -The second is the SWIG program, which is a general tool for -interfacing between languages. For information on SWIG see -http://swig.org/. When running go build, any file with a .swig -extension will be passed to SWIG. Any file with a .swigcxx extension -will be passed to SWIG with the -c++ option. - -When either cgo or SWIG is used, go build will pass any .c, .m, .s, -or .S files to the C compiler, and any .cc, .cpp, .cxx files to the C++ -compiler. The CC or CXX environment variables may be set to determine -the C or C++ compiler, respectively, to use. - - -File types - -The go command examines the contents of a restricted set of files -in each directory. It identifies which files to examine based on -the extension of the file name. These extensions are: - - .go - Go source files. - .c, .h - C source files. - If the package uses cgo, these will be compiled with the - OS-native compiler (typically gcc); otherwise they will be - compiled with the Go-specific support compiler, - 5c, 6c, or 8c, etc. as appropriate. - .cc, .cpp, .cxx, .hh, .hpp, .hxx - C++ source files. Only useful with cgo or SWIG, and always - compiled with the OS-native compiler. - .m - Objective-C source files. Only useful with cgo, and always - compiled with the OS-native compiler. - .s, .S - Assembler source files. - If the package uses cgo, these will be assembled with the - OS-native assembler (typically gcc (sic)); otherwise they - will be assembled with the Go-specific support assembler, - 5a, 6a, or 8a, etc., as appropriate. - .swig, .swigcxx - SWIG definition files. - .syso - System object files. - -Files of each of these types except .syso may contain build -constraints, but the go command stops scanning for build constraints -at the first item in the file that is not a blank line or //-style -line comment. - - -GOPATH environment variable - -The Go path is used to resolve import statements. -It is implemented by and documented in the go/build package. - -The GOPATH environment variable lists places to look for Go code. -On Unix, the value is a colon-separated string. -On Windows, the value is a semicolon-separated string. -On Plan 9, the value is a list. - -GOPATH must be set to get, build and install packages outside the -standard Go tree. - -Each directory listed in GOPATH must have a prescribed structure: - -The src/ directory holds source code. The path below 'src' -determines the import path or executable name. - -The pkg/ directory holds installed package objects. -As in the Go tree, each target operating system and -architecture pair has its own subdirectory of pkg -(pkg/GOOS_GOARCH). - -If DIR is a directory listed in the GOPATH, a package with -source in DIR/src/foo/bar can be imported as "foo/bar" and -has its compiled form installed to "DIR/pkg/GOOS_GOARCH/foo/bar.a". - -The bin/ directory holds compiled commands. -Each command is named for its source directory, but only -the final element, not the entire path. That is, the -command with source in DIR/src/foo/quux is installed into -DIR/bin/quux, not DIR/bin/foo/quux. The foo/ is stripped -so that you can add DIR/bin to your PATH to get at the -installed commands. If the GOBIN environment variable is -set, commands are installed to the directory it names instead -of DIR/bin. - -Here's an example directory layout: - - GOPATH=/home/user/gocode - - /home/user/gocode/ - src/ - foo/ - bar/ (go code in package bar) - x.go - quux/ (go code in package main) - y.go - bin/ - quux (installed command) - pkg/ - linux_amd64/ - foo/ - bar.a (installed package object) - -Go searches each directory listed in GOPATH to find source code, -but new packages are always downloaded into the first directory -in the list. - - -Import path syntax - -An import path (see 'go help packages') denotes a package -stored in the local file system. In general, an import path denotes -either a standard package (such as "unicode/utf8") or a package -found in one of the work spaces (see 'go help gopath'). - -Relative import paths - -An import path beginning with ./ or ../ is called a relative path. -The toolchain supports relative import paths as a shortcut in two ways. - -First, a relative path can be used as a shorthand on the command line. -If you are working in the directory containing the code imported as -"unicode" and want to run the tests for "unicode/utf8", you can type -"go test ./utf8" instead of needing to specify the full path. -Similarly, in the reverse situation, "go test .." will test "unicode" from -the "unicode/utf8" directory. Relative patterns are also allowed, like -"go test ./..." to test all subdirectories. See 'go help packages' for details -on the pattern syntax. - -Second, if you are compiling a Go program not in a work space, -you can use a relative path in an import statement in that program -to refer to nearby code also not in a work space. -This makes it easy to experiment with small multipackage programs -outside of the usual work spaces, but such programs cannot be -installed with "go install" (there is no work space in which to install them), -so they are rebuilt from scratch each time they are built. -To avoid ambiguity, Go programs cannot use relative import paths -within a work space. - -Remote import paths - -Certain import paths also -describe how to obtain the source code for the package using -a revision control system. - -A few common code hosting sites have special syntax: - - Bitbucket (Git, Mercurial) - - import "bitbucket.org/user/project" - import "bitbucket.org/user/project/sub/directory" - - GitHub (Git) - - import "github.com/user/project" - import "github.com/user/project/sub/directory" - - Google Code Project Hosting (Git, Mercurial, Subversion) - - import "code.google.com/p/project" - import "code.google.com/p/project/sub/directory" - - import "code.google.com/p/project.subrepository" - import "code.google.com/p/project.subrepository/sub/directory" - - Launchpad (Bazaar) - - import "launchpad.net/project" - import "launchpad.net/project/series" - import "launchpad.net/project/series/sub/directory" - - import "launchpad.net/~user/project/branch" - import "launchpad.net/~user/project/branch/sub/directory" - - IBM DevOps Services (Git) - - import "hub.jazz.net/git/user/project" - import "hub.jazz.net/git/user/project/sub/directory" - -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 tag in the HTML. - -To declare the code location, an import path of the form - - repository.vcs/path - -specifies the given repository, with or without the .vcs suffix, -using the named version control system, and then the path inside -that repository. The supported version control systems are: - - Bazaar .bzr - Git .git - Mercurial .hg - Subversion .svn - -For example, - - import "example.org/user/foo.hg" - -denotes the root directory of the Mercurial repository at -example.org/user/foo or foo.hg, and - - import "example.org/repo.git/foo/bar" - -denotes the foo/bar directory of the Git repository at -example.org/repo or repo.git. - -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 tag in the document's HTML -. - -The meta tag has the form: - - - -The import-prefix is the import path corresponding 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 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 - - - -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'). - -The go command attempts to download the version of the -package appropriate for the Go release being used. -Run 'go help get' for more. - -Import path checking - -When the custom import path feature described above redirects to a -known code hosting site, each of the resulting packages has two possible -import paths, using the custom domain or the known hosting site. - -A package statement is said to have an "import comment" if it is immediately -followed (before the next newline) by a comment of one of these two forms: - - package math // import "path" - package math /* import "path" * / - -The go command will refuse to install a package with an import comment -unless it is being referred to by that import path. In this way, import comments -let package authors make sure the custom import path is used and not a -direct path to the underlying code hosting site. - -See https://golang.org/s/go14customimport for details. - - -Description of package lists - -Many commands apply to a set of packages: - - go action [packages] - -Usually, [packages] is a list of import paths. - -An import path that is a rooted path or that begins with -a . or .. element is interpreted as a file system path and -denotes the package in that directory. - -Otherwise, the import path P denotes the package found in -the directory DIR/src/P for some DIR listed in the GOPATH -environment variable (see 'go help gopath'). - -If no import paths are given, the action applies to the -package in the current directory. - -There are three reserved names for paths that should not be used -for packages to be built with the go tool: - -- "main" denotes the top-level package in a stand-alone executable. - -- "all" expands to all package directories found in all the GOPATH -trees. For example, 'go list all' lists all the packages on the local -system. - -- "std" is like all but expands to just the packages in the standard -Go library. - -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. 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 importpath' for details. - -Every package in a program must have a unique import path. -By convention, this is arranged by starting each path with a -unique prefix that belongs to you. For example, paths used -internally at Google all begin with 'google', and paths -denoting remote repositories begin with the path to the code, -such as 'code.google.com/p/project'. - -As a special case, if the package list is a list of .go files from a -single directory, the command is applied to a single synthesized -package made up of exactly those files, ignoring any build constraints -in those files and ignoring any other files in the directory. - -Directory and file names that begin with "." or "_" are ignored -by the go tool, as are directories named "testdata". - - -Description of testing flags - -The 'go test' command takes both flags that apply to 'go test' itself -and flags that apply to the resulting test binary. - -Several of the flags control profiling and write an execution profile -suitable for "go tool pprof"; run "go tool pprof help" for more -information. The --alloc_space, --alloc_objects, and --show_bytes -options of pprof control how the information is presented. - -The following flags are recognized by the 'go test' command and -control the execution of any test: - - -bench regexp - Run benchmarks matching the regular expression. - By default, no benchmarks run. To run all benchmarks, - use '-bench .' or '-bench=.'. - - -benchmem - Print memory allocation statistics for benchmarks. - - -benchtime t - Run enough iterations of each benchmark to take t, specified - as a time.Duration (for example, -benchtime 1h30s). - The default is 1 second (1s). - - -blockprofile block.out - Write a goroutine blocking profile to the specified file - when all tests are complete. - Writes test binary as -c would. - - -blockprofilerate n - Control the detail provided in goroutine blocking profiles by - calling runtime.SetBlockProfileRate with n. - See 'godoc runtime SetBlockProfileRate'. - The profiler aims to sample, on average, one blocking event every - n nanoseconds the program spends blocked. By default, - if -test.blockprofile is set without this flag, all blocking events - are recorded, equivalent to -test.blockprofilerate=1. - - -cover - Enable coverage analysis. - - -covermode set,count,atomic - Set the mode for coverage analysis for the package[s] - being tested. The default is "set" unless -race is enabled, - in which case it is "atomic". - The values: - set: bool: does this statement run? - count: int: how many times does this statement run? - atomic: int: count, but correct in multithreaded tests; - significantly more expensive. - Sets -cover. - - -coverpkg pkg1,pkg2,pkg3 - Apply coverage analysis in each test to the given list of packages. - The default is for each test to analyze only the package being tested. - Packages are specified as import paths. - Sets -cover. - - -coverprofile cover.out - Write a coverage profile to the file after all tests have passed. - Sets -cover. - - -cpu 1,2,4 - Specify a list of GOMAXPROCS values for which the tests or - benchmarks should be executed. The default is the current value - of GOMAXPROCS. - - -cpuprofile cpu.out - Write a CPU profile to the specified file before exiting. - Writes test binary as -c would. - - -memprofile mem.out - Write a memory profile to the file after all tests have passed. - Writes test binary as -c would. - - -memprofilerate n - Enable more precise (and expensive) memory profiles by setting - runtime.MemProfileRate. See 'godoc runtime MemProfileRate'. - To profile all memory allocations, use -test.memprofilerate=1 - and pass --alloc_space flag to the pprof tool. - - -outputdir directory - Place output files from profiling in the specified directory, - by default the directory in which "go test" is running. - - -parallel n - Allow parallel execution of test functions that call t.Parallel. - The value of this flag is the maximum number of tests to run - simultaneously; by default, it is set to the value of GOMAXPROCS. - - -run regexp - Run only those tests and examples matching the regular - expression. - - -short - Tell long-running tests to shorten their run time. - It is off by default but set during all.bash so that installing - the Go tree can run a sanity check but not spend time running - exhaustive tests. - - -timeout t - If a test runs longer than t, panic. - - -v - Verbose output: log all tests as they are run. Also print all - text from Log and Logf calls even if the test succeeds. - -The test binary, called pkg.test where pkg is the name of the -directory containing the package sources, can be invoked directly -after building it with 'go test -c'. When invoking the test binary -directly, each of the standard flag names must be prefixed with 'test.', -as in -test.run=TestMyFunc or -test.v. - -When running 'go test', flags not listed above are passed through -unaltered. For instance, the command - - go test -x -v -cpuprofile=prof.out -dir=testdata -update - -will compile the test binary and then run it as - - pkg.test -test.v -test.cpuprofile=prof.out -dir=testdata -update - -The test flags that generate profiles (other than for coverage) also -leave the test binary in pkg.test for use when analyzing the profiles. - -Flags not recognized by 'go test' must be placed after any specified packages. - - -Description of testing functions - -The 'go test' command expects to find test, benchmark, and example functions -in the "*_test.go" files corresponding to the package under test. - -A test function is one named TestXXX (where XXX is any alphanumeric string -not starting with a lower case letter) and should have the signature, - - func TestXXX(t *testing.T) { ... } - -A benchmark function is one named BenchmarkXXX and should have the signature, - - func BenchmarkXXX(b *testing.B) { ... } - -An example function is similar to a test function but, instead of using -*testing.T to report success or failure, prints output to os.Stdout. -That output is compared against the function's "Output:" comment, which -must be the last comment in the function body (see example below). An -example with no such comment, or with no text after "Output:" is compiled -but not executed. - -Godoc displays the body of ExampleXXX to demonstrate the use -of the function, constant, or variable XXX. An example of a method M with -receiver type T or *T is named ExampleT_M. There may be multiple examples -for a given function, constant, or variable, distinguished by a trailing _xxx, -where xxx is a suffix not beginning with an upper case letter. - -Here is an example of an example: - - func ExamplePrintln() { - Println("The output of\nthis example.") - // Output: The output of - // this example. - } - -The entire test file is presented as the example when it contains a single -example function, at least one other function, type, variable, or constant -declaration, and no test or benchmark functions. - -See the documentation of the testing package for more information. - - -*/ -package main + Respect case when matching symbols. + -cmd + Treat a command (package main) like a regular package. + Otherwise package main's exported symbols are hidden + when showing the package's top-level documentation. + -u + Show documentation for unexported as well as exported + symbols and methods. +`, +} + +func runDoc(cmd *Command, args []string) { + run(buildToolExec, tool("doc"), args) +} diff --git a/libgo/go/cmd/go/env.go b/libgo/go/cmd/go/env.go index 26d37df4f9b..600accac03f 100644 --- a/libgo/go/cmd/go/env.go +++ b/libgo/go/cmd/go/env.go @@ -36,7 +36,6 @@ func mkEnv() []envVar { env := []envVar{ {"GOARCH", goarch}, {"GOBIN", gobin}, - {"GOCHAR", archChar}, {"GOEXE", exeSuffix}, {"GOHOSTARCH", runtime.GOARCH}, {"GOHOSTOS", runtime.GOOS}, @@ -45,6 +44,7 @@ func mkEnv() []envVar { {"GORACE", os.Getenv("GORACE")}, {"GOROOT", goroot}, {"GOTOOLDIR", toolDir}, + {"GO15VENDOREXPERIMENT", os.Getenv("GO15VENDOREXPERIMENT")}, // disable escape codes in clang errors {"TERM", "dumb"}, diff --git a/libgo/go/cmd/go/fix.go b/libgo/go/cmd/go/fix.go index 8736cce3e2a..94fd22e3c21 100644 --- a/libgo/go/cmd/go/fix.go +++ b/libgo/go/cmd/go/fix.go @@ -11,7 +11,7 @@ var cmdFix = &Command{ Long: ` Fix runs the Go fix command on the packages named by the import paths. -For more about fix, see 'godoc fix'. +For more about fix, see 'go doc cmd/fix'. For more about specifying packages, see 'go help packages'. To run fix with specific options, run 'go tool fix'. @@ -25,6 +25,6 @@ func runFix(cmd *Command, args []string) { // Use pkg.gofiles instead of pkg.Dir so that // the command only applies to this package, // not to packages in subdirectories. - run(stringList(tool("fix"), relPaths(pkg.allgofiles))) + run(stringList(buildToolExec, tool("fix"), relPaths(pkg.allgofiles))) } } diff --git a/libgo/go/cmd/go/fmt.go b/libgo/go/cmd/go/fmt.go index 65dc3ca5990..57c02ad2647 100644 --- a/libgo/go/cmd/go/fmt.go +++ b/libgo/go/cmd/go/fmt.go @@ -4,6 +4,11 @@ package main +import ( + "os" + "path/filepath" +) + func init() { addBuildFlagsNX(cmdFmt) } @@ -16,7 +21,7 @@ var cmdFmt = &Command{ Fmt runs the command 'gofmt -l -w' on the packages named by the import paths. It prints the names of the files that are modified. -For more about gofmt, see 'godoc gofmt'. +For more about gofmt, see 'go doc cmd/gofmt'. For more about specifying packages, see 'go help packages'. The -n flag prints commands that would be executed. @@ -29,10 +34,31 @@ See also: go fix, go vet. } func runFmt(cmd *Command, args []string) { + gofmt := gofmtPath() for _, pkg := range packages(args) { // Use pkg.gofiles instead of pkg.Dir so that // the command only applies to this package, // not to packages in subdirectories. - run(stringList("gofmt", "-l", "-w", relPaths(pkg.allgofiles))) + run(stringList(gofmt, "-l", "-w", relPaths(pkg.allgofiles))) } } + +func gofmtPath() string { + gofmt := "gofmt" + if toolIsWindows { + gofmt += toolWindowsExtension + } + + gofmtPath := filepath.Join(gobin, gofmt) + if _, err := os.Stat(gofmtPath); err == nil { + return gofmtPath + } + + gofmtPath = filepath.Join(goroot, "bin", gofmt) + if _, err := os.Stat(gofmtPath); err == nil { + return gofmtPath + } + + // fallback to looking for gofmt in $PATH + return "gofmt" +} diff --git a/libgo/go/cmd/go/generate.go b/libgo/go/cmd/go/generate.go index 3c0af8760b5..efdc229b228 100644 --- a/libgo/go/cmd/go/generate.go +++ b/libgo/go/cmd/go/generate.go @@ -13,11 +13,11 @@ import ( "os" "os/exec" "path/filepath" + "regexp" "runtime" "strconv" "strings" "unicode" - "unicode/utf8" ) var cmdGenerate = &Command{ @@ -62,8 +62,12 @@ Go generate sets several variables when it runs the generator: The execution operating system (linux, windows, etc.) $GOFILE The base name of the file. + $GOLINE + The line number of the directive in the source file. $GOPACKAGE The name of the package of the file containing the directive. + $DOLLAR + A dollar sign. Other than variable substitution and quoted-string evaluation, no special processing such as "globbing" is performed on the command @@ -106,9 +110,10 @@ The generator is run in the package's source directory. Go generate accepts one specific flag: -run="" - TODO: This flag is unimplemented. - if non-empty, specifies a regular expression to - select directives whose command matches the expression. + if non-empty, specifies a regular expression to select + directives whose full original source text (excluding + any trailing spaces and final newline) matches the + expression. It also accepts the standard build flags -v, -n, and -x. The -v flag prints the names of packages and files as they are @@ -120,7 +125,10 @@ For more about specifying packages, see 'go help packages'. `, } -var generateRunFlag string // generate -run flag +var ( + generateRunFlag string // generate -run flag + generateRunRE *regexp.Regexp // compiled expression for -run +) func init() { addBuildFlags(cmdGenerate) @@ -128,6 +136,13 @@ func init() { } func runGenerate(cmd *Command, args []string) { + if generateRunFlag != "" { + var err error + generateRunRE, err = regexp.Compile(generateRunFlag) + if err != nil { + log.Fatalf("generate: %s", err) + } + } // Even if the arguments are .go files, this loop suffices. for _, pkg := range packages(args) { for _, file := range pkg.gofiles { @@ -163,7 +178,7 @@ type Generator struct { file string // base name of file. pkg string commands map[string][]string - lineNum int + lineNum int // current line number. } // run runs the generators in the current file. @@ -221,6 +236,11 @@ func (g *Generator) run() (ok bool) { if !isGoGenerate(buf) { continue } + if generateRunFlag != "" { + if !generateRunRE.Match(bytes.TrimSpace(buf)) { + continue + } + } words := g.split(string(buf)) if len(words) == 0 { @@ -306,7 +326,7 @@ Words: } // Substitute environment variables. for i, word := range words { - words[i] = g.expandEnv(word) + words[i] = os.Expand(word, g.expandVar) } return words } @@ -322,38 +342,25 @@ func (g *Generator) errorf(format string, args ...interface{}) { panic(stop) } -// expandEnv expands any $XXX invocations in word. -func (g *Generator) expandEnv(word string) string { - if !strings.ContainsRune(word, '$') { - return word - } - var buf bytes.Buffer - var w int - var r rune - for i := 0; i < len(word); i += w { - r, w = utf8.DecodeRuneInString(word[i:]) - if r != '$' { - buf.WriteRune(r) - continue - } - w += g.identLength(word[i+w:]) - envVar := word[i+1 : i+w] - var sub string - switch envVar { - case "GOARCH": - sub = runtime.GOARCH - case "GOOS": - sub = runtime.GOOS - case "GOFILE": - sub = g.file - case "GOPACKAGE": - sub = g.pkg - default: - sub = os.Getenv(envVar) - } - buf.WriteString(sub) +// expandVar expands the $XXX invocation in word. It is called +// by os.Expand. +func (g *Generator) expandVar(word string) string { + switch word { + case "GOARCH": + return buildContext.GOARCH + case "GOOS": + return buildContext.GOOS + case "GOFILE": + return g.file + case "GOLINE": + return fmt.Sprint(g.lineNum) + case "GOPACKAGE": + return g.pkg + case "DOLLAR": + return "$" + default: + return os.Getenv(word) } - return buf.String() } // identLength returns the length of the identifier beginning the string. @@ -395,7 +402,7 @@ func (g *Generator) exec(words []string) { "GOFILE=" + g.file, "GOPACKAGE=" + g.pkg, } - cmd.Env = mergeEnvLists(env, os.Environ()) + cmd.Env = mergeEnvLists(env, origEnv) err := cmd.Run() if err != nil { g.errorf("running %q: %s", words[0], err) diff --git a/libgo/go/cmd/go/generate_test.go b/libgo/go/cmd/go/generate_test.go index 2ec548630ac..169d71ca812 100644 --- a/libgo/go/cmd/go/generate_test.go +++ b/libgo/go/cmd/go/generate_test.go @@ -26,6 +26,7 @@ var splitTests = []splitTest{ {"$GOPACKAGE", []string{"sys"}}, {"a $XXNOTDEFINEDXX b", []string{"a", "", "b"}}, {"/$XXNOTDEFINED/", []string{"//"}}, + {"/$DOLLAR/", []string{"/$/"}}, {"yacc -o $GOARCH/yacc_$GOFILE", []string{"go", "tool", "yacc", "-o", runtime.GOARCH + "/yacc_proc.go"}}, } diff --git a/libgo/go/cmd/go/get.go b/libgo/go/cmd/go/get.go index 50e0ca93bf4..e95201a6930 100644 --- a/libgo/go/cmd/go/get.go +++ b/libgo/go/cmd/go/get.go @@ -16,7 +16,7 @@ import ( ) var cmdGet = &Command{ - UsageLine: "get [-d] [-f] [-fix] [-t] [-u] [build flags] [packages]", + UsageLine: "get [-d] [-f] [-fix] [-insecure] [-t] [-u] [build flags] [packages]", Short: "download and install packages and dependencies", Long: ` Get downloads and installs the packages named by the import paths, @@ -33,6 +33,9 @@ of the original. The -fix flag instructs get to run the fix tool on the downloaded packages before resolving dependencies or building the code. +The -insecure flag permits fetching from repositories and resolving +custom domains using insecure schemes such as HTTP. Use with caution. + The -t flag instructs get to also download the packages required to build the tests for the specified packages. @@ -48,6 +51,10 @@ rule is that if the local installation is running version "go1", get searches for a branch or tag named "go1". If no such version exists it retrieves the most recent version of the package. +If the vendoring experiment is enabled (see 'go help gopath'), +then when go get checks out or updates a Git repository, +it also updates any git submodules referenced by the repository. + For more about specifying packages, see 'go help packages'. For more about how 'go get' finds source code to @@ -62,6 +69,7 @@ var getF = cmdGet.Flag.Bool("f", false, "") var getT = cmdGet.Flag.Bool("t", false, "") var getU = cmdGet.Flag.Bool("u", false, "") var getFix = cmdGet.Flag.Bool("fix", false, "") +var getInsecure = cmdGet.Flag.Bool("insecure", false, "") func init() { addBuildFlags(cmdGet) @@ -73,10 +81,20 @@ func runGet(cmd *Command, args []string) { fatalf("go get: cannot use -f flag without -u") } + // Disable any prompting for passwords by Git. + // Only has an effect for 2.3.0 or later, but avoiding + // the prompt in earlier versions is just too hard. + // See golang.org/issue/9341. + os.Setenv("GIT_TERMINAL_PROMPT", "0") + // Phase 1. Download/update. var stk importStack + mode := 0 + if *getT { + mode |= getTestDeps + } for _, arg := range downloadPaths(args) { - download(arg, &stk, *getT) + download(arg, nil, &stk, mode) } exitIfErrors() @@ -92,12 +110,13 @@ func runGet(cmd *Command, args []string) { } args = importPaths(args) + packagesForBuild(args) // Phase 3. Install. if *getD { // Download only. // Check delayed until now so that importPaths - // has a chance to print errors. + // and packagesForBuild have a chance to print errors. return } @@ -148,13 +167,30 @@ var downloadRootCache = map[string]bool{} // download runs the download half of the get command // for the package named by the argument. -func download(arg string, stk *importStack, getTestDeps bool) { - p := loadPackage(arg, stk) +func download(arg string, parent *Package, stk *importStack, mode int) { + load := func(path string, mode int) *Package { + if parent == nil { + return loadPackage(path, stk) + } + return loadImport(path, parent.Dir, parent, stk, nil, mode) + } + + p := load(arg, mode) if p.Error != nil && p.Error.hard { errorf("%s", p.Error) return } + // loadPackage inferred the canonical ImportPath from arg. + // Use that in the following to prevent hysteresis effects + // in e.g. downloadCache and packageCache. + // This allows invocations such as: + // mkdir -p $GOPATH/src/github.com/user + // cd $GOPATH/src/github.com/user + // go get ./foo + // see: golang.org/issue/9767 + arg = p.ImportPath + // There's nothing to do if this is a package in the standard library. if p.Standard { return @@ -163,7 +199,7 @@ func download(arg string, stk *importStack, getTestDeps bool) { // Only process each package once. // (Unless we're fetching test dependencies for this package, // in which case we want to process it again.) - if downloadCache[arg] && !getTestDeps { + if downloadCache[arg] && mode&getTestDeps == 0 { return } downloadCache[arg] = true @@ -175,7 +211,7 @@ func download(arg string, stk *importStack, getTestDeps bool) { // Download if the package is missing, or update if we're using -u. if p.Dir == "" || *getU { // The actual download. - stk.push(p.ImportPath) + stk.push(arg) err := downloadPackage(p) if err != nil { errorf("%s", &PackageError{ImportStack: stk.copy(), Err: err.Error()}) @@ -183,6 +219,17 @@ func download(arg string, stk *importStack, getTestDeps bool) { return } + // Warn that code.google.com is shutting down. We + // issue the warning here because this is where we + // have the import stack. + if strings.HasPrefix(p.ImportPath, "code.google.com") { + fmt.Fprintf(os.Stderr, "warning: code.google.com is shutting down; import path %v will stop working\n", p.ImportPath) + if len(*stk) > 1 { + fmt.Fprintf(os.Stderr, "warning: package %v\n", strings.Join(*stk, "\n\timports ")) + } + } + stk.pop() + 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 @@ -208,9 +255,10 @@ func download(arg string, stk *importStack, getTestDeps bool) { pkgs = pkgs[:0] for _, arg := range args { - stk.push(arg) - p := loadPackage(arg, stk) - stk.pop() + // Note: load calls loadPackage or loadImport, + // which push arg onto stk already. + // Do not push here too, or else stk will say arg imports arg. + p := load(arg, mode) if p.Error != nil { errorf("%s", p.Error) continue @@ -223,7 +271,7 @@ func download(arg string, stk *importStack, getTestDeps bool) { // due to wildcard expansion. for _, p := range pkgs { if *getFix { - run(stringList(tool("fix"), relPaths(p.allgofiles))) + run(buildToolExec, stringList(tool("fix"), relPaths(p.allgofiles))) // The imports might have changed, so reload again. p = reloadPackage(arg, stk) @@ -240,18 +288,31 @@ func download(arg string, stk *importStack, getTestDeps bool) { } // Process dependencies, now that we know what they are. - for _, dep := range p.deps { + for _, path := range p.Imports { + if path == "C" { + continue + } // Don't get test dependencies recursively. - download(dep.ImportPath, stk, false) + // Imports is already vendor-expanded. + download(path, p, stk, 0) } - if getTestDeps { + if mode&getTestDeps != 0 { // Process test dependencies when -t is specified. // (Don't get test dependencies for test dependencies.) + // We pass useVendor here because p.load does not + // vendor-expand TestImports and XTestImports. + // The call to loadImport inside download needs to do that. for _, path := range p.TestImports { - download(path, stk, false) + if path == "C" { + continue + } + download(path, p, stk, useVendor) } for _, path := range p.XTestImports { - download(path, stk, false) + if path == "C" { + continue + } + download(path, p, stk, useVendor) } } @@ -269,6 +330,12 @@ func downloadPackage(p *Package) error { repo, rootPath string err error ) + + security := secure + if *getInsecure { + security = insecure + } + if p.build.SrcRoot != "" { // Directory exists. Look for checkout along path to src. vcs, rootPath, err = vcsForDir(p) @@ -278,10 +345,15 @@ func downloadPackage(p *Package) error { repo = "" // should be unused; make distinctive // Double-check where it came from. - if *getU && vcs.remoteRepo != nil && !*getF { + if *getU && vcs.remoteRepo != nil { dir := filepath.Join(p.build.SrcRoot, rootPath) - if remote, err := vcs.remoteRepo(vcs, dir); err == nil { - if rr, err := repoRootForImportPath(p.ImportPath); err == nil { + remote, err := vcs.remoteRepo(vcs, dir) + if err != nil { + return err + } + repo = remote + if !*getF { + if rr, err := repoRootForImportPath(p.ImportPath, security); err == nil { repo := rr.repo if rr.vcs.resolveRepo != nil { resolved, err := rr.vcs.resolveRepo(rr.vcs, dir, repo) @@ -289,7 +361,7 @@ func downloadPackage(p *Package) error { repo = resolved } } - if remote != repo { + if remote != repo && p.ImportComment != "" { return fmt.Errorf("%s is a custom import path for %s, but %s is checked out from %s", rr.root, repo, dir, remote) } } @@ -298,12 +370,15 @@ 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. - rr, err := repoRootForImportPath(p.ImportPath) + rr, err := repoRootForImportPath(p.ImportPath, security) if err != nil { return err } vcs, repo, rootPath = rr.vcs, rr.repo, rr.root } + if !vcs.isSecure(repo) && !*getInsecure { + return fmt.Errorf("cannot download, %v uses insecure protocol", repo) + } if p.build.SrcRoot == "" { // Package not found. Put in first directory of $GOPATH. diff --git a/libgo/go/cmd/go/go_test.go b/libgo/go/cmd/go/go_test.go new file mode 100644 index 00000000000..77b2628982b --- /dev/null +++ b/libgo/go/cmd/go/go_test.go @@ -0,0 +1,2389 @@ +// Copyright 2015 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_test + +import ( + "bytes" + "flag" + "fmt" + "go/build" + "go/format" + "internal/testenv" + "io" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "regexp" + "runtime" + "strconv" + "strings" + "testing" + "time" +) + +var ( + canRun = true // whether we can run go or ./testgo + canRace = false // whether we can run the race detector + canCgo = false // whether we can use cgo + + exeSuffix string // ".exe" on Windows + + builder = testenv.Builder() + skipExternalBuilder = false // skip external tests on this builder +) + +func init() { + switch runtime.GOOS { + case "android", "nacl": + canRun = false + case "darwin": + switch runtime.GOARCH { + case "arm", "arm64": + canRun = false + } + } + + if strings.HasPrefix(builder+"-", "freebsd-arm-") { + skipExternalBuilder = true + canRun = false + } + + switch runtime.GOOS { + case "windows": + exeSuffix = ".exe" + } +} + +// The TestMain function creates a go command for testing purposes and +// deletes it after the tests have been run. +func TestMain(m *testing.M) { + flag.Parse() + + if canRun { + out, err := exec.Command("go", "build", "-tags", "testgo", "-o", "testgo"+exeSuffix).CombinedOutput() + if err != nil { + fmt.Fprintf(os.Stderr, "building testgo failed: %v\n%s", err, out) + os.Exit(2) + } + + if out, err := exec.Command("./testgo"+exeSuffix, "env", "CGO_ENABLED").Output(); err != nil { + fmt.Fprintf(os.Stderr, "running testgo failed: %v\n", err) + canRun = false + } else { + canCgo, err = strconv.ParseBool(strings.TrimSpace(string(out))) + if err != nil { + fmt.Fprintf(os.Stderr, "can't parse go env CGO_ENABLED output: %v\n", strings.TrimSpace(string(out))) + } + } + + switch runtime.GOOS { + case "linux", "darwin", "freebsd", "windows": + canRace = canCgo && runtime.GOARCH == "amd64" + } + + measureTick("./testgo" + exeSuffix) + } + + // Don't let these environment variables confuse the test. + os.Unsetenv("GOBIN") + os.Unsetenv("GOPATH") + + r := m.Run() + + if canRun { + os.Remove("testgo" + exeSuffix) + } + + os.Exit(r) +} + +// The length of an mtime tick on this system. This is an estimate of +// how long we need to sleep to ensure that the mtime of two files is +// different. +var mtimeTick time.Duration + +// measureTick sets mtimeTick by looking at the rounding of the mtime +// of a file. +func measureTick(path string) { + st, err := os.Stat(path) + if err != nil { + // Default to one second, the most conservative value. + mtimeTick = time.Second + return + } + mtime := st.ModTime() + t := time.Microsecond + for mtime.Round(t).Equal(mtime) && t < time.Second { + t *= 10 + } + mtimeTick = t +} + +// Manage a single run of the testgo binary. +type testgoData struct { + t *testing.T + temps []string + wd string + env []string + tempdir string + ran bool + inParallel bool + stdout, stderr bytes.Buffer +} + +// testgo sets up for a test that runs testgo. +func testgo(t *testing.T) *testgoData { + testenv.MustHaveGoBuild(t) + + if skipExternalBuilder { + t.Skip("skipping external tests on %s builder", builder) + } + + return &testgoData{t: t} +} + +// must gives a fatal error if err is not nil. +func (tg *testgoData) must(err error) { + if err != nil { + tg.t.Fatal(err) + } +} + +// check gives a test non-fatal error if err is not nil. +func (tg *testgoData) check(err error) { + if err != nil { + tg.t.Error(err) + } +} + +// parallel runs the test in parallel by calling t.Parallel. +func (tg *testgoData) parallel() { + if tg.ran { + tg.t.Fatal("internal testsuite error: call to parallel after run") + } + if tg.wd != "" { + tg.t.Fatal("internal testsuite error: call to parallel after cd") + } + for _, e := range tg.env { + if strings.HasPrefix(e, "GOROOT=") || strings.HasPrefix(e, "GOPATH=") || strings.HasPrefix(e, "GOBIN=") { + val := e[strings.Index(e, "=")+1:] + if strings.HasPrefix(val, "testdata") || strings.HasPrefix(val, "./testdata") { + tg.t.Fatalf("internal testsuite error: call to parallel with testdata in environment (%s)", e) + } + } + } + tg.inParallel = true + tg.t.Parallel() +} + +// pwd returns the current directory. +func (tg *testgoData) pwd() string { + wd, err := os.Getwd() + if err != nil { + tg.t.Fatalf("could not get working directory: %v", err) + } + return wd +} + +// cd changes the current directory to the named directory. Note that +// using this means that the test must not be run in parallel with any +// other tests. +func (tg *testgoData) cd(dir string) { + if tg.inParallel { + tg.t.Fatal("internal testsuite error: changing directory when running in parallel") + } + if tg.wd == "" { + tg.wd = tg.pwd() + } + abs, err := filepath.Abs(dir) + tg.must(os.Chdir(dir)) + if err == nil { + tg.setenv("PWD", abs) + } +} + +// sleep sleeps for one tick, where a tick is a conservative estimate +// of how long it takes for a file modification to get a different +// mtime. +func (tg *testgoData) sleep() { + time.Sleep(mtimeTick) +} + +// setenv sets an environment variable to use when running the test go +// command. +func (tg *testgoData) setenv(name, val string) { + if tg.inParallel && (name == "GOROOT" || name == "GOPATH" || name == "GOBIN") && (strings.HasPrefix(val, "testdata") || strings.HasPrefix(val, "./testdata")) { + tg.t.Fatalf("internal testsuite error: call to setenv with testdata (%s=%s) after parallel", name, val) + } + tg.unsetenv(name) + tg.env = append(tg.env, name+"="+val) +} + +// unsetenv removes an environment variable. +func (tg *testgoData) unsetenv(name string) { + if tg.env == nil { + tg.env = append([]string(nil), os.Environ()...) + } + for i, v := range tg.env { + if strings.HasPrefix(v, name+"=") { + tg.env = append(tg.env[:i], tg.env[i+1:]...) + break + } + } +} + +// doRun runs the test go command, recording stdout and stderr and +// returning exit status. +func (tg *testgoData) doRun(args []string) error { + if !canRun { + panic("testgoData.doRun called but canRun false") + } + if tg.inParallel { + for _, arg := range args { + if strings.HasPrefix(arg, "testdata") || strings.HasPrefix(arg, "./testdata") { + tg.t.Fatal("internal testsuite error: parallel run using testdata") + } + } + } + tg.t.Logf("running testgo %v", args) + var prog string + if tg.wd == "" { + prog = "./testgo" + exeSuffix + } else { + prog = filepath.Join(tg.wd, "testgo"+exeSuffix) + } + cmd := exec.Command(prog, args...) + tg.stdout.Reset() + tg.stderr.Reset() + cmd.Stdout = &tg.stdout + cmd.Stderr = &tg.stderr + cmd.Env = tg.env + status := cmd.Run() + if tg.stdout.Len() > 0 { + tg.t.Log("standard output:") + tg.t.Log(tg.stdout.String()) + } + if tg.stderr.Len() > 0 { + tg.t.Log("standard error:") + tg.t.Log(tg.stderr.String()) + } + tg.ran = true + return status +} + +// run runs the test go command, and expects it to succeed. +func (tg *testgoData) run(args ...string) { + if status := tg.doRun(args); status != nil { + tg.t.Logf("go %v failed unexpectedly: %v", args, status) + tg.t.FailNow() + } +} + +// runFail runs the test go command, and expects it to fail. +func (tg *testgoData) runFail(args ...string) { + if status := tg.doRun(args); status == nil { + tg.t.Fatal("testgo succeeded unexpectedly") + } else { + tg.t.Log("testgo failed as expected:", status) + } +} + +// runGit runs a git command, and expects it to succeed. +func (tg *testgoData) runGit(dir string, args ...string) { + cmd := exec.Command("git", args...) + tg.stdout.Reset() + tg.stderr.Reset() + cmd.Stdout = &tg.stdout + cmd.Stderr = &tg.stderr + cmd.Dir = dir + cmd.Env = tg.env + status := cmd.Run() + if tg.stdout.Len() > 0 { + tg.t.Log("git standard output:") + tg.t.Log(tg.stdout.String()) + } + if tg.stderr.Len() > 0 { + tg.t.Log("git standard error:") + tg.t.Log(tg.stderr.String()) + } + if status != nil { + tg.t.Logf("git %v failed unexpectedly: %v", args, status) + tg.t.FailNow() + } +} + +// getStdout returns standard output of the testgo run as a string. +func (tg *testgoData) getStdout() string { + if !tg.ran { + tg.t.Fatal("internal testsuite error: stdout called before run") + } + return tg.stdout.String() +} + +// getStderr returns standard error of the testgo run as a string. +func (tg *testgoData) getStderr() string { + if !tg.ran { + tg.t.Fatal("internal testsuite error: stdout called before run") + } + return tg.stderr.String() +} + +// doGrepMatch looks for a regular expression in a buffer, and returns +// whether it is found. The regular expression is matched against +// each line separately, as with the grep command. +func (tg *testgoData) doGrepMatch(match string, b *bytes.Buffer) bool { + if !tg.ran { + tg.t.Fatal("internal testsuite error: grep called before run") + } + re := regexp.MustCompile(match) + for _, ln := range bytes.Split(b.Bytes(), []byte{'\n'}) { + if re.Match(ln) { + return true + } + } + return false +} + +// doGrep looks for a regular expression in a buffer and fails if it +// is not found. The name argument is the name of the output we are +// searching, "output" or "error". The msg argument is logged on +// failure. +func (tg *testgoData) doGrep(match string, b *bytes.Buffer, name, msg string) { + if !tg.doGrepMatch(match, b) { + tg.t.Log(msg) + tg.t.Logf("pattern %v not found in standard %s", match, name) + tg.t.FailNow() + } +} + +// grepStdout looks for a regular expression in the test run's +// standard output and fails, logging msg, if it is not found. +func (tg *testgoData) grepStdout(match, msg string) { + tg.doGrep(match, &tg.stdout, "output", msg) +} + +// grepStderr looks for a regular expression in the test run's +// standard error and fails, logging msg, if it is not found. +func (tg *testgoData) grepStderr(match, msg string) { + tg.doGrep(match, &tg.stderr, "error", msg) +} + +// grepBoth looks for a regular expression in the test run's standard +// output or stand error and fails, logging msg, if it is not found. +func (tg *testgoData) grepBoth(match, msg string) { + if !tg.doGrepMatch(match, &tg.stdout) && !tg.doGrepMatch(match, &tg.stderr) { + tg.t.Log(msg) + tg.t.Logf("pattern %v not found in standard output or standard error", match) + tg.t.FailNow() + } +} + +// doGrepNot looks for a regular expression in a buffer and fails if +// it is found. The name and msg arguments are as for doGrep. +func (tg *testgoData) doGrepNot(match string, b *bytes.Buffer, name, msg string) { + if tg.doGrepMatch(match, b) { + tg.t.Log(msg) + tg.t.Logf("pattern %v found unexpectedly in standard %s", match, name) + tg.t.FailNow() + } +} + +// grepStdoutNot looks for a regular expression in the test run's +// standard output and fails, logging msg, if it is found. +func (tg *testgoData) grepStdoutNot(match, msg string) { + tg.doGrepNot(match, &tg.stdout, "output", msg) +} + +// grepStderrNot looks for a regular expression in the test run's +// standard error and fails, logging msg, if it is found. +func (tg *testgoData) grepStderrNot(match, msg string) { + tg.doGrepNot(match, &tg.stderr, "error", msg) +} + +// grepBothNot looks for a regular expression in the test run's +// standard output or stand error and fails, logging msg, if it is +// found. +func (tg *testgoData) grepBothNot(match, msg string) { + if tg.doGrepMatch(match, &tg.stdout) || tg.doGrepMatch(match, &tg.stderr) { + tg.t.Log(msg) + tg.t.Fatalf("pattern %v found unexpectedly in standard output or standard error", match) + } +} + +// doGrepCount counts the number of times a regexp is seen in a buffer. +func (tg *testgoData) doGrepCount(match string, b *bytes.Buffer) int { + if !tg.ran { + tg.t.Fatal("internal testsuite error: doGrepCount called before run") + } + re := regexp.MustCompile(match) + c := 0 + for _, ln := range bytes.Split(b.Bytes(), []byte{'\n'}) { + if re.Match(ln) { + c++ + } + } + return c +} + +// grepCountStdout returns the number of times a regexp is seen in +// standard output. +func (tg *testgoData) grepCountStdout(match string) int { + return tg.doGrepCount(match, &tg.stdout) +} + +// grepCountStderr returns the number of times a regexp is seen in +// standard error. +func (tg *testgoData) grepCountStderr(match string) int { + return tg.doGrepCount(match, &tg.stderr) +} + +// grepCountBoth returns the number of times a regexp is seen in both +// standard output and standard error. +func (tg *testgoData) grepCountBoth(match string) int { + return tg.doGrepCount(match, &tg.stdout) + tg.doGrepCount(match, &tg.stderr) +} + +// creatingTemp records that the test plans to create a temporary file +// or directory. If the file or directory exists already, it will be +// removed. When the test completes, the file or directory will be +// removed if it exists. +func (tg *testgoData) creatingTemp(path string) { + if filepath.IsAbs(path) && !strings.HasPrefix(path, tg.tempdir) { + tg.t.Fatal("internal testsuite error: creatingTemp(%q) with absolute path not in temporary directory", path) + } + // If we have changed the working directory, make sure we have + // an absolute path, because we are going to change directory + // back before we remove the temporary. + if tg.wd != "" && !filepath.IsAbs(path) { + path = filepath.Join(tg.pwd(), path) + } + tg.must(os.RemoveAll(path)) + tg.temps = append(tg.temps, path) +} + +// makeTempdir makes a temporary directory for a run of testgo. If +// the temporary directory was already created, this does nothing. +func (tg *testgoData) makeTempdir() { + if tg.tempdir == "" { + var err error + tg.tempdir, err = ioutil.TempDir("", "gotest") + tg.must(err) + } +} + +// tempFile adds a temporary file for a run of testgo. +func (tg *testgoData) tempFile(path, contents string) { + tg.makeTempdir() + tg.must(os.MkdirAll(filepath.Join(tg.tempdir, filepath.Dir(path)), 0755)) + bytes := []byte(contents) + if strings.HasSuffix(path, ".go") { + formatted, err := format.Source(bytes) + if err == nil { + bytes = formatted + } + } + tg.must(ioutil.WriteFile(filepath.Join(tg.tempdir, path), bytes, 0644)) +} + +// tempDir adds a temporary directory for a run of testgo. +func (tg *testgoData) tempDir(path string) { + tg.makeTempdir() + if err := os.MkdirAll(filepath.Join(tg.tempdir, path), 0755); err != nil && !os.IsExist(err) { + tg.t.Fatal(err) + } +} + +// path returns the absolute pathname to file with the temporary +// directory. +func (tg *testgoData) path(name string) string { + if tg.tempdir == "" { + tg.t.Fatalf("internal testsuite error: path(%q) with no tempdir", name) + } + if name == "." { + return tg.tempdir + } + return filepath.Join(tg.tempdir, name) +} + +// mustNotExist fails if path exists. +func (tg *testgoData) mustNotExist(path string) { + if _, err := os.Stat(path); err == nil || !os.IsNotExist(err) { + tg.t.Fatalf("%s exists but should not (%v)", path, err) + } +} + +// wantExecutable fails with msg if path is not executable. +func (tg *testgoData) wantExecutable(path, msg string) { + if st, err := os.Stat(path); err != nil { + if !os.IsNotExist(err) { + tg.t.Log(err) + } + tg.t.Fatal(msg) + } else { + if runtime.GOOS != "windows" && st.Mode()&0111 == 0 { + tg.t.Fatalf("binary %s exists but is not executable", path) + } + } +} + +// wantArchive fails if path is not an archive. +func (tg *testgoData) wantArchive(path string) { + f, err := os.Open(path) + if err != nil { + tg.t.Fatal(err) + } + buf := make([]byte, 100) + io.ReadFull(f, buf) + f.Close() + if !bytes.HasPrefix(buf, []byte("!\n")) { + tg.t.Fatalf("file %s exists but is not an archive", path) + } +} + +// isStale returns whether pkg is stale. +func (tg *testgoData) isStale(pkg string) bool { + tg.run("list", "-f", "{{.Stale}}", pkg) + switch v := strings.TrimSpace(tg.getStdout()); v { + case "true": + return true + case "false": + return false + default: + tg.t.Fatalf("unexpected output checking staleness of package %v: %v", pkg, v) + panic("unreachable") + } +} + +// wantStale fails with msg if pkg is not stale. +func (tg *testgoData) wantStale(pkg, msg string) { + if !tg.isStale(pkg) { + tg.t.Fatal(msg) + } +} + +// wantNotStale fails with msg if pkg is stale. +func (tg *testgoData) wantNotStale(pkg, msg string) { + if tg.isStale(pkg) { + tg.t.Fatal(msg) + } +} + +// cleanup cleans up a test that runs testgo. +func (tg *testgoData) cleanup() { + if tg.wd != "" { + if err := os.Chdir(tg.wd); err != nil { + // We are unlikely to be able to continue. + fmt.Fprintln(os.Stderr, "could not restore working directory, crashing:", err) + os.Exit(2) + } + } + for _, path := range tg.temps { + tg.check(os.RemoveAll(path)) + } + if tg.tempdir != "" { + tg.check(os.RemoveAll(tg.tempdir)) + } +} + +// resetReadOnlyFlagAll resets windows read-only flag +// set on path and any children it contains. +// The flag is set by git and has to be removed. +// os.Remove refuses to remove files with read-only flag set. +func (tg *testgoData) resetReadOnlyFlagAll(path string) { + fi, err := os.Stat(path) + if err != nil { + tg.t.Fatalf("resetReadOnlyFlagAll(%q) failed: %v", path, err) + } + if !fi.IsDir() { + err := os.Chmod(path, 0666) + if err != nil { + tg.t.Fatalf("resetReadOnlyFlagAll(%q) failed: %v", path, err) + } + } + fd, err := os.Open(path) + if err != nil { + tg.t.Fatalf("resetReadOnlyFlagAll(%q) failed: %v", path, err) + } + defer fd.Close() + names, _ := fd.Readdirnames(-1) + for _, name := range names { + tg.resetReadOnlyFlagAll(path + string(filepath.Separator) + name) + } +} + +// failSSH puts an ssh executable in the PATH that always fails. +// This is to stub out uses of ssh by go get. +func (tg *testgoData) failSSH() { + wd, err := os.Getwd() + if err != nil { + tg.t.Fatal(err) + } + fail := filepath.Join(wd, "testdata/failssh") + tg.setenv("PATH", fmt.Sprintf("%v%c%v", fail, filepath.ListSeparator, os.Getenv("PATH"))) +} + +func TestFileLineInErrorMessages(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.tempFile("err.go", `package main; import "bar"`) + path := tg.path("err.go") + tg.runFail("run", path) + shortPath := path + if rel, err := filepath.Rel(tg.pwd(), path); err == nil && len(rel) < len(path) { + shortPath = rel + } + tg.grepStderr("^"+regexp.QuoteMeta(shortPath)+":", "missing file:line in error message") +} + +func TestProgramNameInCrashMessages(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.tempFile("triv.go", `package main; func main() {}`) + tg.runFail("build", "-ldflags", "-crash_for_testing", tg.path("triv.go")) + tg.grepStderr(`[/\\]tool[/\\].*[/\\]link`, "missing linker name in error message") +} + +func TestBrokenTestsWithoutTestFunctionsAllFail(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.runFail("test", "./testdata/src/badtest/...") + tg.grepBothNot("^ok", "test passed unexpectedly") + tg.grepBoth("FAIL.*badtest/badexec", "test did not run everything") + tg.grepBoth("FAIL.*badtest/badsyntax", "test did not run everything") + tg.grepBoth("FAIL.*badtest/badvar", "test did not run everything") +} + +func TestGoBuildDashAInDevBranch(t *testing.T) { + if testing.Short() { + t.Skip("don't rebuild the standard library in short mode") + } + + tg := testgo(t) + defer tg.cleanup() + tg.run("install", "math") // should be up to date already but just in case + tg.setenv("TESTGO_IS_GO_RELEASE", "0") + tg.run("build", "-v", "-a", "math") + tg.grepStderr("runtime", "testgo build -a math in dev branch DID NOT build runtime, but should have") +} + +func TestGoBuilDashAInReleaseBranch(t *testing.T) { + if testing.Short() { + t.Skip("don't rebuild the standard library in short mode") + } + + tg := testgo(t) + defer tg.cleanup() + tg.run("install", "math") // should be up to date already but just in case + tg.setenv("TESTGO_IS_GO_RELEASE", "1") + tg.run("build", "-v", "-a", "math") + tg.grepStderr("runtime", "testgo build -a math in dev branch did not build runtime, but should have") +} + +func TestGoInstallCleansUpAfterGoBuild(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.tempFile("src/mycmd/main.go", `package main; func main(){}`) + tg.setenv("GOPATH", tg.path(".")) + tg.cd(tg.path("src/mycmd")) + + doesNotExist := func(file, msg string) { + if _, err := os.Stat(file); err == nil { + t.Fatal(msg) + } else if !os.IsNotExist(err) { + t.Fatal(msg, "error:", err) + } + } + + tg.run("build") + tg.wantExecutable("mycmd"+exeSuffix, "testgo build did not write command binary") + tg.run("install") + doesNotExist("mycmd"+exeSuffix, "testgo install did not remove command binary") + tg.run("build") + tg.wantExecutable("mycmd"+exeSuffix, "testgo build did not write command binary (second time)") + // Running install with arguments does not remove the target, + // even in the same directory. + tg.run("install", "mycmd") + tg.wantExecutable("mycmd"+exeSuffix, "testgo install mycmd removed command binary when run in mycmd") + tg.run("build") + tg.wantExecutable("mycmd"+exeSuffix, "testgo build did not write command binary (third time)") + // And especially not outside the directory. + tg.cd(tg.path(".")) + if data, err := ioutil.ReadFile("src/mycmd/mycmd" + exeSuffix); err != nil { + t.Fatal("could not read file:", err) + } else { + if err := ioutil.WriteFile("mycmd"+exeSuffix, data, 0555); err != nil { + t.Fatal("could not write file:", err) + } + } + tg.run("install", "mycmd") + tg.wantExecutable("src/mycmd/mycmd"+exeSuffix, "testgo install mycmd removed command binary from its source dir when run outside mycmd") + tg.wantExecutable("mycmd"+exeSuffix, "testgo install mycmd removed command binary from current dir when run outside mycmd") +} + +func TestGoInstallRebuildsStalePackagesInOtherGOPATH(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.tempFile("d1/src/p1/p1.go", `package p1 + import "p2" + func F() { p2.F() }`) + tg.tempFile("d2/src/p2/p2.go", `package p2 + func F() {}`) + sep := string(filepath.ListSeparator) + tg.setenv("GOPATH", tg.path("d1")+sep+tg.path("d2")) + tg.run("install", "p1") + tg.wantNotStale("p1", "./testgo list mypkg claims p1 is stale, incorrectly") + tg.wantNotStale("p2", "./testgo list mypkg claims p2 is stale, incorrectly") + tg.sleep() + if f, err := os.OpenFile(tg.path("d2/src/p2/p2.go"), os.O_WRONLY|os.O_APPEND, 0); err != nil { + t.Fatal(err) + } else if _, err = f.WriteString(`func G() {}`); err != nil { + t.Fatal(err) + } else { + tg.must(f.Close()) + } + tg.wantStale("p2", "./testgo list mypkg claims p2 is NOT stale, incorrectly") + tg.wantStale("p1", "./testgo list mypkg claims p1 is NOT stale, incorrectly") + + tg.run("install", "p1") + tg.wantNotStale("p2", "./testgo list mypkg claims p2 is stale after reinstall, incorrectly") + tg.wantNotStale("p1", "./testgo list mypkg claims p1 is stale after reinstall, incorrectly") +} + +func TestGoInstallDetectsRemovedFiles(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.tempFile("src/mypkg/x.go", `package mypkg`) + tg.tempFile("src/mypkg/y.go", `package mypkg`) + tg.tempFile("src/mypkg/z.go", `// +build missingtag + + package mypkg`) + tg.setenv("GOPATH", tg.path(".")) + tg.run("install", "mypkg") + tg.wantNotStale("mypkg", "./testgo list mypkg claims mypkg is stale, incorrectly") + // z.go was not part of the build; removing it is okay. + tg.must(os.Remove(tg.path("src/mypkg/z.go"))) + tg.wantNotStale("mypkg", "./testgo list mypkg claims mypkg is stale after removing z.go; should not be stale") + // y.go was part of the package; removing it should be detected. + tg.must(os.Remove(tg.path("src/mypkg/y.go"))) + tg.wantStale("mypkg", "./testgo list mypkg claims mypkg is NOT stale after removing y.go; should be stale") +} + +func TestGoInstallErrorOnCrossCompileToBin(t *testing.T) { + if testing.Short() { + t.Skip("don't install into GOROOT in short mode") + } + + tg := testgo(t) + defer tg.cleanup() + tg.tempFile("src/mycmd/x.go", `package main + func main() {}`) + tg.setenv("GOPATH", tg.path(".")) + tg.cd(tg.path("src/mycmd")) + + tg.run("build", "mycmd") + + goarch := "386" + if runtime.GOARCH == "386" { + goarch = "amd64" + } + tg.setenv("GOOS", "linux") + tg.setenv("GOARCH", goarch) + tg.run("install", "mycmd") + tg.setenv("GOBIN", tg.path(".")) + tg.runFail("install", "mycmd") + tg.run("install", "cmd/pack") +} + +func TestGoInstallDetectsRemovedFilesInPackageMain(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.tempFile("src/mycmd/x.go", `package main + func main() {}`) + tg.tempFile("src/mycmd/y.go", `package main`) + tg.tempFile("src/mycmd/z.go", `// +build missingtag + + package main`) + tg.setenv("GOPATH", tg.path(".")) + tg.run("install", "mycmd") + tg.wantNotStale("mycmd", "./testgo list mypkg claims mycmd is stale, incorrectly") + // z.go was not part of the build; removing it is okay. + tg.must(os.Remove(tg.path("src/mycmd/z.go"))) + tg.wantNotStale("mycmd", "./testgo list mycmd claims mycmd is stale after removing z.go; should not be stale") + // y.go was part of the package; removing it should be detected. + tg.must(os.Remove(tg.path("src/mycmd/y.go"))) + tg.wantStale("mycmd", "./testgo list mycmd claims mycmd is NOT stale after removing y.go; should be stale") +} + +func testLocalRun(tg *testgoData, exepath, local, match string) { + out, err := exec.Command(exepath).Output() + if err != nil { + tg.t.Fatalf("error running %v: %v", exepath, err) + } + if !regexp.MustCompile(match).Match(out) { + tg.t.Log(string(out)) + tg.t.Errorf("testdata/%s/easy.go did not generate expected output", local) + } +} + +func testLocalEasy(tg *testgoData, local string) { + exepath := "./easy" + exeSuffix + tg.creatingTemp(exepath) + tg.run("build", "-o", exepath, filepath.Join("testdata", local, "easy.go")) + testLocalRun(tg, exepath, local, `(?m)^easysub\.Hello`) +} + +func testLocalEasySub(tg *testgoData, local string) { + exepath := "./easysub" + exeSuffix + tg.creatingTemp(exepath) + tg.run("build", "-o", exepath, filepath.Join("testdata", local, "easysub", "main.go")) + testLocalRun(tg, exepath, local, `(?m)^easysub\.Hello`) +} + +func testLocalHard(tg *testgoData, local string) { + exepath := "./hard" + exeSuffix + tg.creatingTemp(exepath) + tg.run("build", "-o", exepath, filepath.Join("testdata", local, "hard.go")) + testLocalRun(tg, exepath, local, `(?m)^sub\.Hello`) +} + +func testLocalInstall(tg *testgoData, local string) { + tg.runFail("install", filepath.Join("testdata", local, "easy.go")) +} + +func TestLocalImportsEasy(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + testLocalEasy(tg, "local") +} + +func TestLocalImportsEasySub(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + testLocalEasySub(tg, "local") +} + +func TestLocalImportsHard(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + testLocalHard(tg, "local") +} + +func TestLocalImportsGoInstallShouldFail(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + testLocalInstall(tg, "local") +} + +const badDirName = `#$%:, &()*;<=>?\^{}` + +func copyBad(tg *testgoData) { + if runtime.GOOS == "windows" { + tg.t.Skipf("skipping test because %q is an invalid directory name", badDirName) + } + + tg.must(filepath.Walk("testdata/local", + func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if info.IsDir() { + return nil + } + var data []byte + data, err = ioutil.ReadFile(path) + if err != nil { + return err + } + newpath := strings.Replace(path, "local", badDirName, 1) + tg.tempFile(newpath, string(data)) + return nil + })) + tg.cd(tg.path(".")) +} + +func TestBadImportsEasy(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + copyBad(tg) + testLocalEasy(tg, badDirName) +} + +func TestBadImportsEasySub(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + copyBad(tg) + testLocalEasySub(tg, badDirName) +} + +func TestBadImportsHard(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + copyBad(tg) + testLocalHard(tg, badDirName) +} + +func TestBadImportsGoInstallShouldFail(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + copyBad(tg) + testLocalInstall(tg, badDirName) +} + +func TestInternalPackagesInGOROOTAreRespected(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.runFail("build", "-v", "./testdata/testinternal") + tg.grepBoth("use of internal package not allowed", "wrong error message for testdata/testinternal") +} + +func TestInternalPackagesOutsideGOROOTAreRespected(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.runFail("build", "-v", "./testdata/testinternal2") + tg.grepBoth("use of internal package not allowed", "wrote error message for testdata/testinternal2") +} + +func testMove(t *testing.T, vcs, url, base, config string) { + testenv.MustHaveExternalNetwork(t) + + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.tempDir("src") + tg.setenv("GOPATH", tg.path(".")) + tg.run("get", "-d", url) + tg.run("get", "-d", "-u", url) + switch vcs { + case "svn": + // SVN doesn't believe in text files so we can't just edit the config. + // Check out a different repo into the wrong place. + tg.must(os.RemoveAll(tg.path("src/code.google.com/p/rsc-svn"))) + tg.run("get", "-d", "-u", "code.google.com/p/rsc-svn2/trunk") + tg.must(os.Rename(tg.path("src/code.google.com/p/rsc-svn2"), tg.path("src/code.google.com/p/rsc-svn"))) + default: + path := tg.path(filepath.Join("src", config)) + data, err := ioutil.ReadFile(path) + tg.must(err) + data = bytes.Replace(data, []byte(base), []byte(base+"XXX"), -1) + tg.must(ioutil.WriteFile(path, data, 0644)) + } + if vcs == "git" { + // git will ask for a username and password when we + // run go get -d -f -u. An empty username and + // password will work. Prevent asking by setting + // GIT_ASKPASS. + tg.creatingTemp("sink" + exeSuffix) + tg.tempFile("src/sink/sink.go", `package main; func main() {}`) + tg.run("build", "-o", "sink"+exeSuffix, "sink") + tg.setenv("GIT_ASKPASS", filepath.Join(tg.pwd(), "sink"+exeSuffix)) + } + tg.runFail("get", "-d", "-u", url) + tg.grepStderr("is a custom import path for", "go get -d -u "+url+" failed for wrong reason") + tg.runFail("get", "-d", "-f", "-u", url) + tg.grepStderr("validating server certificate|not found", "go get -d -f -u "+url+" failed for wrong reason") +} + +func TestInternalPackageErrorsAreHandled(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.run("list", "./testdata/testinternal3") +} + +func TestInternalCache(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata/testinternal4")) + tg.runFail("build", "p") + tg.grepStderr("internal", "did not fail to build p") +} + +func TestMoveGit(t *testing.T) { + testMove(t, "git", "rsc.io/pdf", "pdf", "rsc.io/pdf/.git/config") +} + +// TODO(rsc): Set up a test case on bitbucket for hg. +// func TestMoveHG(t *testing.T) { +// testMove(t, "hg", "rsc.io/x86/x86asm", "x86", "rsc.io/x86/.hg/hgrc") +// } + +// TODO(rsc): Set up a test case on SourceForge (?) for svn. +// func testMoveSVN(t *testing.T) { +// testMove(t, "svn", "code.google.com/p/rsc-svn/trunk", "-", "-") +// } + +func TestImportCommandMatch(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata/importcom")) + tg.run("build", "./testdata/importcom/works.go") +} + +func TestImportCommentMismatch(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata/importcom")) + tg.runFail("build", "./testdata/importcom/wrongplace.go") + tg.grepStderr(`wrongplace expects import "my/x"`, "go build did not mention incorrect import") +} + +func TestImportCommentSyntaxError(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata/importcom")) + tg.runFail("build", "./testdata/importcom/bad.go") + tg.grepStderr("cannot parse import comment", "go build did not mention syntax error") +} + +func TestImportCommentConflict(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata/importcom")) + tg.runFail("build", "./testdata/importcom/conflict.go") + tg.grepStderr("found import comments", "go build did not mention comment conflict") +} + +// cmd/go: custom import path checking should not apply to github.com/xxx/yyy. +func TestIssue10952(t *testing.T) { + testenv.MustHaveExternalNetwork(t) + + if _, err := exec.LookPath("git"); err != nil { + t.Skip("skipping because git binary not found") + } + + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.tempDir("src") + tg.setenv("GOPATH", tg.path(".")) + const importPath = "github.com/zombiezen/go-get-issue-10952" + tg.run("get", "-d", "-u", importPath) + repoDir := tg.path("src/" + importPath) + defer tg.resetReadOnlyFlagAll(repoDir) + tg.runGit(repoDir, "remote", "set-url", "origin", "https://"+importPath+".git") + tg.run("get", "-d", "-u", importPath) +} + +func TestDisallowedCSourceFiles(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) + tg.runFail("build", "badc") + tg.grepStderr("C source files not allowed", "go test did not say C source files not allowed") +} + +func TestErrorMessageForSyntaxErrorInTestGoFileSaysFAIL(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) + tg.runFail("test", "syntaxerror") + tg.grepStderr("FAIL", "go test did not say FAIL") +} + +func TestWildcardsDoNotLookInUselessDirectories(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) + tg.runFail("list", "...") + tg.grepBoth("badpkg", "go list ... failure does not mention badpkg") + tg.run("list", "m...") +} + +func TestRelativeImportsGoTest(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.run("test", "./testdata/testimport") +} + +func TestRelativeImportsGoTestDashI(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.run("test", "-i", "./testdata/testimport") +} + +func TestRelativeImportsInCommandLinePackage(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + files, err := filepath.Glob("./testdata/testimport/*.go") + tg.must(err) + tg.run(append([]string{"test"}, files...)...) +} + +func TestVersionControlErrorMessageIncludesCorrectDirectory(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata/shadow/root1")) + tg.runFail("get", "-u", "foo") + + // TODO(iant): We should not have to use strconv.Quote here. + // The code in vcs.go should be changed so that it is not required. + quoted := strconv.Quote(filepath.Join("testdata", "shadow", "root1", "src", "foo")) + quoted = quoted[1 : len(quoted)-1] + + tg.grepStderr(regexp.QuoteMeta(quoted), "go get -u error does not mention shadow/root1/src/foo") +} + +func TestInstallFailsWithNoBuildableFiles(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) + tg.setenv("CGO_ENABLED", "0") + tg.runFail("install", "cgotest") + tg.grepStderr("no buildable Go source files", "go install cgotest did not report 'no buildable Go Source files'") +} + +// Test that without $GOBIN set, binaries get installed +// into the GOPATH bin directory. +func TestInstallIntoGOPATH(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.creatingTemp("testdata/bin/go-cmd-test" + exeSuffix) + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) + tg.run("install", "go-cmd-test") + tg.wantExecutable("testdata/bin/go-cmd-test"+exeSuffix, "go install go-cmd-test did not write to testdata/bin/go-cmd-test") +} + +func TestPackageMainTestImportsArchiveNotBinary(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + gobin := filepath.Join(tg.pwd(), "testdata", "bin") + tg.creatingTemp(gobin) + tg.setenv("GOBIN", gobin) + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) + tg.must(os.Chtimes("./testdata/src/main_test/m.go", time.Now(), time.Now())) + tg.sleep() + tg.run("test", "main_test") + tg.run("install", "main_test") + tg.wantNotStale("main_test", "after go install, main listed as stale") + tg.run("test", "main_test") +} + +// With $GOBIN set, binaries get installed to $GOBIN. +func TestInstallIntoGOBIN(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + gobin := filepath.Join(tg.pwd(), "testdata", "bin1") + tg.creatingTemp(gobin) + tg.setenv("GOBIN", gobin) + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) + tg.run("install", "go-cmd-test") + tg.wantExecutable("testdata/bin1/go-cmd-test"+exeSuffix, "go install go-cmd-test did not write to testdata/bin1/go-cmd-test") +} + +// Issue 11065 +func TestInstallToCurrentDirectoryCreatesExecutable(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + pkg := filepath.Join(tg.pwd(), "testdata", "src", "go-cmd-test") + tg.creatingTemp(filepath.Join(pkg, "go-cmd-test"+exeSuffix)) + tg.setenv("GOBIN", pkg) + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) + tg.cd(pkg) + tg.run("install") + tg.wantExecutable("go-cmd-test"+exeSuffix, "go install did not write to current directory") +} + +// Without $GOBIN set, installing a program outside $GOPATH should fail +// (there is nowhere to install it). +func TestInstallWithoutDestinationFails(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.runFail("install", "testdata/src/go-cmd-test/helloworld.go") + tg.grepStderr("no install location for .go files listed on command line", "wrong error") +} + +// With $GOBIN set, should install there. +func TestInstallToGOBINCommandLinePackage(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + gobin := filepath.Join(tg.pwd(), "testdata", "bin1") + tg.creatingTemp(gobin) + tg.setenv("GOBIN", gobin) + tg.run("install", "testdata/src/go-cmd-test/helloworld.go") + tg.wantExecutable("testdata/bin1/helloworld"+exeSuffix, "go install testdata/src/go-cmd-test/helloworld.go did not write testdata/bin1/helloworld") +} + +func TestGodocInstalls(t *testing.T) { + testenv.MustHaveExternalNetwork(t) + + // godoc installs into GOBIN + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.tempDir("gobin") + tg.setenv("GOPATH", tg.path(".")) + tg.setenv("GOBIN", tg.path("gobin")) + tg.run("get", "golang.org/x/tools/cmd/godoc") + tg.wantExecutable(tg.path("gobin/godoc"), "did not install godoc to $GOBIN") + tg.unsetenv("GOBIN") + + // godoc installs into GOROOT + goroot := runtime.GOROOT() + tg.setenv("GOROOT", goroot) + tg.check(os.RemoveAll(filepath.Join(goroot, "bin", "godoc"))) + tg.run("install", "golang.org/x/tools/cmd/godoc") + tg.wantExecutable(filepath.Join(goroot, "bin", "godoc"), "did not install godoc to $GOROOT/bin") +} + +func TestGoGetNonPkg(t *testing.T) { + testenv.MustHaveExternalNetwork(t) + + tg := testgo(t) + defer tg.cleanup() + tg.tempDir("gobin") + tg.setenv("GOPATH", tg.path(".")) + tg.setenv("GOBIN", tg.path("gobin")) + tg.runFail("get", "-d", "golang.org/x/tools") + tg.grepStderr("golang.org/x/tools: no buildable Go source files", "missing error") + tg.runFail("get", "-d", "-u", "golang.org/x/tools") + tg.grepStderr("golang.org/x/tools: no buildable Go source files", "missing error") + tg.runFail("get", "-d", "golang.org/x/tools") + tg.grepStderr("golang.org/x/tools: no buildable Go source files", "missing error") +} + +func TestInstalls(t *testing.T) { + if testing.Short() { + t.Skip("don't install into GOROOT in short mode") + } + + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.tempDir("gobin") + tg.setenv("GOPATH", tg.path(".")) + goroot := runtime.GOROOT() + tg.setenv("GOROOT", goroot) + + // cmd/fix installs into tool + tg.run("env", "GOOS") + goos := strings.TrimSpace(tg.getStdout()) + tg.setenv("GOOS", goos) + tg.run("env", "GOARCH") + goarch := strings.TrimSpace(tg.getStdout()) + tg.setenv("GOARCH", goarch) + fixbin := filepath.Join(goroot, "pkg", "tool", goos+"_"+goarch, "fix") + exeSuffix + tg.must(os.RemoveAll(fixbin)) + tg.run("install", "cmd/fix") + tg.wantExecutable(fixbin, "did not install cmd/fix to $GOROOT/pkg/tool") + tg.must(os.Remove(fixbin)) + tg.setenv("GOBIN", tg.path("gobin")) + tg.run("install", "cmd/fix") + tg.wantExecutable(fixbin, "did not install cmd/fix to $GOROOT/pkg/tool with $GOBIN set") + tg.unsetenv("GOBIN") + + // gopath program installs into GOBIN + tg.tempFile("src/progname/p.go", `package main; func main() {}`) + tg.setenv("GOBIN", tg.path("gobin")) + tg.run("install", "progname") + tg.unsetenv("GOBIN") + tg.wantExecutable(tg.path("gobin/progname")+exeSuffix, "did not install progname to $GOBIN/progname") + + // gopath program installs into GOPATH/bin + tg.run("install", "progname") + tg.wantExecutable(tg.path("bin/progname")+exeSuffix, "did not install progname to $GOPATH/bin/progname") +} + +func TestRejectRelativeDotPathInGOPATHCommandLinePackage(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.setenv("GOPATH", ".") + tg.runFail("build", "testdata/src/go-cmd-test/helloworld.go") + tg.grepStderr("GOPATH entry is relative", "expected an error message rejecting relative GOPATH entries") +} + +func TestRejectRelativePathsInGOPATH(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + sep := string(filepath.ListSeparator) + tg.setenv("GOPATH", sep+filepath.Join(tg.pwd(), "testdata")+sep+".") + tg.runFail("build", "go-cmd-test") + tg.grepStderr("GOPATH entry is relative", "expected an error message rejecting relative GOPATH entries") +} + +func TestRejectRelativePathsInGOPATHCommandLinePackage(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.setenv("GOPATH", "testdata") + tg.runFail("build", "testdata/src/go-cmd-test/helloworld.go") + tg.grepStderr("GOPATH entry is relative", "expected an error message rejecting relative GOPATH entries") +} + +// Issue 4104. +func TestGoTestWithPackageListedMultipleTimes(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.run("test", "errors", "errors", "errors", "errors", "errors") + if strings.Index(strings.TrimSpace(tg.getStdout()), "\n") != -1 { + t.Error("go test errors errors errors errors errors tested the same package multiple times") + } +} + +func TestGoListHasAConsistentOrder(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.run("list", "std") + first := tg.getStdout() + tg.run("list", "std") + if first != tg.getStdout() { + t.Error("go list std ordering is inconsistent") + } +} + +func TestGoListStdDoesNotIncludeCommands(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.run("list", "std") + tg.grepStdoutNot("cmd/", "go list std shows commands") +} + +func TestGoListCmdOnlyShowsCommands(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.run("list", "cmd") + out := strings.TrimSpace(tg.getStdout()) + for _, line := range strings.Split(out, "\n") { + if strings.Index(line, "cmd/") == -1 { + t.Error("go list cmd shows non-commands") + break + } + } +} + +// Issue 4096. Validate the output of unsuccessful go install foo/quxx. +func TestUnsuccessfulGoInstallShouldMentionMissingPackage(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.runFail("install", "foo/quxx") + if tg.grepCountBoth(`cannot find package "foo/quxx" in any of`) != 1 { + t.Error(`go install foo/quxx expected error: .*cannot find package "foo/quxx" in any of`) + } +} + +func TestGOROOTSearchFailureReporting(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.runFail("install", "foo/quxx") + if tg.grepCountBoth(regexp.QuoteMeta(filepath.Join("foo", "quxx"))+` \(from \$GOROOT\)$`) != 1 { + t.Error(`go install foo/quxx expected error: .*foo/quxx (from $GOROOT)`) + } +} + +func TestMultipleGOPATHEntriesReportedSeparately(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + sep := string(filepath.ListSeparator) + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata", "a")+sep+filepath.Join(tg.pwd(), "testdata", "b")) + tg.runFail("install", "foo/quxx") + if tg.grepCountBoth(`testdata[/\\].[/\\]src[/\\]foo[/\\]quxx`) != 2 { + t.Error(`go install foo/quxx expected error: .*testdata/a/src/foo/quxx (from $GOPATH)\n.*testdata/b/src/foo/quxx`) + } +} + +// Test (from $GOPATH) annotation is reported for the first GOPATH entry, +func TestMentionGOPATHInFirstGOPATHEntry(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + sep := string(filepath.ListSeparator) + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata", "a")+sep+filepath.Join(tg.pwd(), "testdata", "b")) + tg.runFail("install", "foo/quxx") + if tg.grepCountBoth(regexp.QuoteMeta(filepath.Join("testdata", "a", "src", "foo", "quxx"))+` \(from \$GOPATH\)$`) != 1 { + t.Error(`go install foo/quxx expected error: .*testdata/a/src/foo/quxx (from $GOPATH)`) + } +} + +// but not on the second. +func TestMentionGOPATHNotOnSecondEntry(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + sep := string(filepath.ListSeparator) + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata", "a")+sep+filepath.Join(tg.pwd(), "testdata", "b")) + tg.runFail("install", "foo/quxx") + if tg.grepCountBoth(regexp.QuoteMeta(filepath.Join("testdata", "b", "src", "foo", "quxx"))+`$`) != 1 { + t.Error(`go install foo/quxx expected error: .*testdata/b/src/foo/quxx`) + } +} + +// Test missing GOPATH is reported. +func TestMissingGOPATHIsReported(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.setenv("GOPATH", "") + tg.runFail("install", "foo/quxx") + if tg.grepCountBoth(`\(\$GOPATH not set\)$`) != 1 { + t.Error(`go install foo/quxx expected error: ($GOPATH not set)`) + } +} + +// Issue 4186. go get cannot be used to download packages to $GOROOT. +// Test that without GOPATH set, go get should fail. +func TestWithoutGOPATHGoGetFails(t *testing.T) { + testenv.MustHaveExternalNetwork(t) + + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.tempDir("src") + tg.setenv("GOPATH", "") + tg.setenv("GOROOT", tg.path(".")) + tg.runFail("get", "-d", "golang.org/x/codereview/cmd/hgpatch") +} + +// Test that with GOPATH=$GOROOT, go get should fail. +func TestWithGOPATHEqualsGOROOTGoGetFails(t *testing.T) { + testenv.MustHaveExternalNetwork(t) + + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.tempDir("src") + tg.setenv("GOPATH", tg.path(".")) + tg.setenv("GOROOT", tg.path(".")) + tg.runFail("get", "-d", "golang.org/x/codereview/cmd/hgpatch") +} + +func TestLdflagsArgumentsWithSpacesIssue3941(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.tempFile("main.go", `package main + var extern string + func main() { + println(extern) + }`) + tg.run("run", "-ldflags", `-X main.extern "hello world"`, tg.path("main.go")) + tg.grepStderr("^hello world", `ldflags -X main.extern 'hello world' failed`) +} + +func TestGoTestCpuprofileLeavesBinaryBehind(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.makeTempdir() + tg.cd(tg.path(".")) + tg.run("test", "-cpuprofile", "errors.prof", "errors") + tg.wantExecutable("errors.test"+exeSuffix, "go test -cpuprofile did not create errors.test") +} + +func TestGoTestCpuprofileDashOControlsBinaryLocation(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.makeTempdir() + tg.cd(tg.path(".")) + tg.run("test", "-cpuprofile", "errors.prof", "-o", "myerrors.test"+exeSuffix, "errors") + tg.wantExecutable("myerrors.test"+exeSuffix, "go test -cpuprofile -o myerrors.test did not create myerrors.test") +} + +func TestGoTestDashCDashOControlsBinaryLocation(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.makeTempdir() + tg.run("test", "-c", "-o", tg.path("myerrors.test"+exeSuffix), "errors") + tg.wantExecutable(tg.path("myerrors.test"+exeSuffix), "go test -c -o myerrors.test did not create myerrors.test") +} + +func TestGoTestDashOWritesBinary(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.makeTempdir() + tg.run("test", "-o", tg.path("myerrors.test"+exeSuffix), "errors") + tg.wantExecutable(tg.path("myerrors.test"+exeSuffix), "go test -o myerrors.test did not create myerrors.test") +} + +// Issue 4568. +func TestSymlinksDoNotConfuseGoList(t *testing.T) { + switch runtime.GOOS { + case "plan9", "windows": + t.Skipf("skipping symlink test on %s", runtime.GOOS) + } + + tg := testgo(t) + defer tg.cleanup() + tg.tempDir("src") + tg.must(os.Symlink(tg.path("."), tg.path("src/dir1"))) + tg.tempFile("src/dir1/p.go", "package p") + tg.setenv("GOPATH", tg.path(".")) + tg.cd(tg.path("src")) + tg.run("list", "-f", "{{.Root}}", "dir1") + if strings.TrimSpace(tg.getStdout()) != tg.path(".") { + t.Error("confused by symlinks") + } +} + +// Issue 4515. +func TestInstallWithTags(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.tempDir("bin") + tg.tempFile("src/example/a/main.go", `package main + func main() {}`) + tg.tempFile("src/example/b/main.go", `// +build mytag + + package main + func main() {}`) + tg.setenv("GOPATH", tg.path(".")) + tg.run("install", "-tags", "mytag", "example/a", "example/b") + tg.wantExecutable(tg.path("bin/a"+exeSuffix), "go install example/a example/b did not install binaries") + tg.wantExecutable(tg.path("bin/b"+exeSuffix), "go install example/a example/b did not install binaries") + tg.must(os.Remove(tg.path("bin/a" + exeSuffix))) + tg.must(os.Remove(tg.path("bin/b" + exeSuffix))) + tg.run("install", "-tags", "mytag", "example/...") + tg.wantExecutable(tg.path("bin/a"+exeSuffix), "go install example/... did not install binaries") + tg.wantExecutable(tg.path("bin/b"+exeSuffix), "go install example/... did not install binaries") + tg.run("list", "-tags", "mytag", "example/b...") + if strings.TrimSpace(tg.getStdout()) != "example/b" { + t.Error("go list example/b did not find example/b") + } +} + +// Issue 4773 +func TestCaseCollisions(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.tempDir("src/example/a/pkg") + tg.tempDir("src/example/a/Pkg") + tg.tempDir("src/example/b") + tg.setenv("GOPATH", tg.path(".")) + tg.tempFile("src/example/a/a.go", `package p + import ( + _ "example/a/pkg" + _ "example/a/Pkg" + )`) + tg.tempFile("src/example/a/pkg/pkg.go", `package pkg`) + tg.tempFile("src/example/a/Pkg/pkg.go", `package pkg`) + tg.runFail("list", "example/a") + tg.grepStderr("case-insensitive import collision", "go list example/a did not report import collision") + tg.tempFile("src/example/b/file.go", `package b`) + tg.tempFile("src/example/b/FILE.go", `package b`) + f, err := os.Open(tg.path("src/example/b")) + tg.must(err) + names, err := f.Readdirnames(0) + tg.must(err) + tg.check(f.Close()) + args := []string{"list"} + if len(names) == 2 { + // case-sensitive file system, let directory read find both files + args = append(args, "example/b") + } else { + // case-insensitive file system, list files explicitly on command line + args = append(args, tg.path("src/example/b/file.go"), tg.path("src/example/b/FILE.go")) + } + tg.runFail(args...) + tg.grepStderr("case-insensitive file name collision", "go list example/b did not report file name collision") +} + +// Issue 8181. +func TestGoGetDashTIssue8181(t *testing.T) { + if testing.Short() { + t.Skip("skipping test that uses network in short mode") + } + + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.makeTempdir() + tg.setenv("GOPATH", tg.path(".")) + tg.run("get", "-v", "-t", "github.com/rsc/go-get-issue-8181/a", "github.com/rsc/go-get-issue-8181/b") + tg.run("list", "...") + tg.grepStdout("x/build/cmd/cl", "missing expected x/build/cmd/cl") +} + +func TestIssue11307(t *testing.T) { + // go get -u was not working except in checkout directory + if testing.Short() { + t.Skip("skipping test that uses network in short mode") + } + + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.makeTempdir() + tg.setenv("GOPATH", tg.path(".")) + tg.run("get", "github.com/rsc/go-get-issue-11307") + tg.run("get", "-u", "github.com/rsc/go-get-issue-11307") // was failing +} + +func TestShadowingLogic(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + pwd := tg.pwd() + sep := string(filepath.ListSeparator) + tg.setenv("GOPATH", filepath.Join(pwd, "testdata", "shadow", "root1")+sep+filepath.Join(pwd, "testdata", "shadow", "root2")) + + // The math in root1 is not "math" because the standard math is. + tg.run("list", "-f", "({{.ImportPath}}) ({{.ConflictDir}})", "./testdata/shadow/root1/src/math") + pwdForwardSlash := strings.Replace(pwd, string(os.PathSeparator), "/", -1) + if !strings.HasPrefix(pwdForwardSlash, "/") { + pwdForwardSlash = "/" + pwdForwardSlash + } + // The output will have makeImportValid applies, but we only + // bother to deal with characters we might reasonably see. + pwdForwardSlash = strings.Replace(pwdForwardSlash, ":", "_", -1) + want := "(_" + pwdForwardSlash + "/testdata/shadow/root1/src/math) (" + filepath.Join(runtime.GOROOT(), "src", "math") + ")" + if strings.TrimSpace(tg.getStdout()) != want { + t.Error("shadowed math is not shadowed; looking for", want) + } + + // The foo in root1 is "foo". + tg.run("list", "-f", "({{.ImportPath}}) ({{.ConflictDir}})", "./testdata/shadow/root1/src/foo") + if strings.TrimSpace(tg.getStdout()) != "(foo) ()" { + t.Error("unshadowed foo is shadowed") + } + + // The foo in root2 is not "foo" because the foo in root1 got there first. + tg.run("list", "-f", "({{.ImportPath}}) ({{.ConflictDir}})", "./testdata/shadow/root2/src/foo") + want = "(_" + pwdForwardSlash + "/testdata/shadow/root2/src/foo) (" + filepath.Join(pwd, "testdata", "shadow", "root1", "src", "foo") + ")" + if strings.TrimSpace(tg.getStdout()) != want { + t.Error("shadowed foo is not shadowed; looking for", want) + } + + // The error for go install should mention the conflicting directory. + tg.runFail("install", "./testdata/shadow/root2/src/foo") + want = "go install: no install location for " + filepath.Join(pwd, "testdata", "shadow", "root2", "src", "foo") + ": hidden by " + filepath.Join(pwd, "testdata", "shadow", "root1", "src", "foo") + if strings.TrimSpace(tg.getStderr()) != want { + t.Error("wrong shadowed install error; looking for", want) + } +} + +// Only succeeds if source order is preserved. +func TestSourceFileNameOrderPreserved(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.run("test", "testdata/example1_test.go", "testdata/example2_test.go") +} + +// Check that coverage analysis works at all. +// Don't worry about the exact numbers but require not 0.0%. +func checkCoverage(tg *testgoData, data string) { + if regexp.MustCompile(`[^0-9]0\.0%`).MatchString(data) { + tg.t.Error("some coverage results are 0.0%") + } + tg.t.Log(data) +} + +func TestCoverageRuns(t *testing.T) { + if testing.Short() { + t.Skip("don't build libraries for coverage in short mode") + } + tg := testgo(t) + defer tg.cleanup() + tg.run("test", "-short", "-coverpkg=strings", "strings", "regexp") + data := tg.getStdout() + tg.getStderr() + tg.run("test", "-short", "-cover", "strings", "math", "regexp") + data += tg.getStdout() + tg.getStderr() + checkCoverage(tg, data) +} + +// Check that coverage analysis uses set mode. +func TestCoverageUsesSetMode(t *testing.T) { + if testing.Short() { + t.Skip("don't build libraries for coverage in short mode") + } + tg := testgo(t) + defer tg.cleanup() + tg.creatingTemp("testdata/cover.out") + tg.run("test", "-short", "-cover", "encoding/binary", "-coverprofile=testdata/cover.out") + data := tg.getStdout() + tg.getStderr() + if out, err := ioutil.ReadFile("testdata/cover.out"); err != nil { + t.Error(err) + } else { + if !bytes.Contains(out, []byte("mode: set")) { + t.Error("missing mode: set") + } + } + checkCoverage(tg, data) +} + +func TestCoverageUsesAtomicModeForRace(t *testing.T) { + if testing.Short() { + t.Skip("don't build libraries for coverage in short mode") + } + if !canRace { + t.Skip("skipping because race detector not supported") + } + + tg := testgo(t) + defer tg.cleanup() + tg.creatingTemp("testdata/cover.out") + tg.run("test", "-short", "-race", "-cover", "encoding/binary", "-coverprofile=testdata/cover.out") + data := tg.getStdout() + tg.getStderr() + if out, err := ioutil.ReadFile("testdata/cover.out"); err != nil { + t.Error(err) + } else { + if !bytes.Contains(out, []byte("mode: atomic")) { + t.Error("missing mode: atomic") + } + } + checkCoverage(tg, data) +} + +func TestCoverageUsesActualSettingToOverrideEvenForRace(t *testing.T) { + if testing.Short() { + t.Skip("don't build libraries for coverage in short mode") + } + if !canRace { + t.Skip("skipping because race detector not supported") + } + + tg := testgo(t) + defer tg.cleanup() + tg.creatingTemp("testdata/cover.out") + tg.run("test", "-short", "-race", "-cover", "encoding/binary", "-covermode=count", "-coverprofile=testdata/cover.out") + data := tg.getStdout() + tg.getStderr() + if out, err := ioutil.ReadFile("testdata/cover.out"); err != nil { + t.Error(err) + } else { + if !bytes.Contains(out, []byte("mode: count")) { + t.Error("missing mode: count") + } + } + checkCoverage(tg, data) +} + +func TestCoverageWithCgo(t *testing.T) { + if !canCgo { + t.Skip("skipping because cgo not enabled") + } + + tg := testgo(t) + defer tg.cleanup() + tg.run("test", "-short", "-cover", "./testdata/cgocover") + data := tg.getStdout() + tg.getStderr() + checkCoverage(tg, data) +} + +func TestCgoDependsOnSyscall(t *testing.T) { + if testing.Short() { + t.Skip("skipping test that removes $GOROOT/pkg/*_race in short mode") + } + if !canCgo { + t.Skip("skipping because cgo not enabled") + } + if !canRace { + t.Skip("skipping because race detector not supported") + } + + tg := testgo(t) + defer tg.cleanup() + files, err := filepath.Glob(filepath.Join(runtime.GOROOT(), "pkg", "*_race")) + tg.must(err) + for _, file := range files { + tg.check(os.RemoveAll(file)) + } + tg.tempFile("src/foo/foo.go", ` + package foo + //#include + import "C"`) + tg.setenv("GOPATH", tg.path(".")) + tg.run("build", "-race", "foo") +} + +func TestCgoShowsFullPathNames(t *testing.T) { + if !canCgo { + t.Skip("skipping because cgo not enabled") + } + + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.tempFile("src/x/y/dirname/foo.go", ` + package foo + import "C" + func f() {`) + tg.setenv("GOPATH", tg.path(".")) + tg.runFail("build", "x/y/dirname") + tg.grepBoth("x/y/dirname", "error did not use full path") +} + +func TestCgoHandlesWlORIGIN(t *testing.T) { + if !canCgo { + t.Skip("skipping because cgo not enabled") + } + + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.tempFile("src/origin/origin.go", `package origin + // #cgo !darwin LDFLAGS: -Wl,-rpath -Wl,$ORIGIN + // void f(void) {} + import "C" + func f() { C.f() }`) + tg.setenv("GOPATH", tg.path(".")) + tg.run("build", "origin") +} + +// "go test -c -test.bench=XXX errors" should not hang +func TestIssue6480(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.makeTempdir() + tg.cd(tg.path(".")) + tg.run("test", "-c", "-test.bench=XXX", "errors") +} + +// cmd/cgo: undefined reference when linking a C-library using gccgo +func TestIssue7573(t *testing.T) { + if _, err := exec.LookPath("gccgo"); err != nil { + t.Skip("skipping because no gccgo compiler found") + } + + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.tempFile("src/cgoref/cgoref.go", ` +package main +// #cgo LDFLAGS: -L alibpath -lalib +// void f(void) {} +import "C" + +func main() { C.f() }`) + tg.setenv("GOPATH", tg.path(".")) + tg.run("build", "-n", "-compiler", "gccgo", "cgoref") + tg.grepStderr(`gccgo.*\-L alibpath \-lalib`, `no Go-inline "#cgo LDFLAGS:" ("-L alibpath -lalib") passed to gccgo linking stage`) +} + +func TestListTemplateCanUseContextFunction(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.run("list", "-f", "GOARCH: {{context.GOARCH}}") +} + +// cmd/go: "go test" should fail if package does not build +func TestIssue7108(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) + tg.runFail("test", "notest") +} + +// cmd/go: go test -a foo does not rebuild regexp. +func TestIssue6844(t *testing.T) { + if testing.Short() { + t.Skip("don't rebuild the standard libary in short mode") + } + + tg := testgo(t) + defer tg.cleanup() + tg.creatingTemp("deps.test" + exeSuffix) + tg.run("test", "-x", "-a", "-c", "testdata/dep_test.go") + tg.grepStderr("regexp", "go test -x -a -c testdata/dep-test.go did not rebuild regexp") +} + +func TestBuildDashIInstallsDependencies(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.tempFile("src/x/y/foo/foo.go", `package foo + func F() {}`) + tg.tempFile("src/x/y/bar/bar.go", `package bar + import "x/y/foo" + func F() { foo.F() }`) + tg.setenv("GOPATH", tg.path(".")) + + checkbar := func(desc string) { + tg.sleep() + tg.must(os.Chtimes(tg.path("src/x/y/foo/foo.go"), time.Now(), time.Now())) + tg.sleep() + tg.run("build", "-v", "-i", "x/y/bar") + tg.grepBoth("x/y/foo", "first build -i "+desc+" did not build x/y/foo") + tg.run("build", "-v", "-i", "x/y/bar") + tg.grepBothNot("x/y/foo", "second build -i "+desc+" built x/y/foo") + } + checkbar("pkg") + tg.creatingTemp("bar" + exeSuffix) + tg.tempFile("src/x/y/bar/bar.go", `package main + import "x/y/foo" + func main() { foo.F() }`) + checkbar("cmd") +} + +func TestGoBuildInTestOnlyDirectoryFailsWithAGoodError(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.runFail("build", "./testdata/testonly") + tg.grepStderr("no buildable Go", "go build ./testdata/testonly produced unexpected error") +} + +func TestGoTestDetectsTestOnlyImportCycles(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) + tg.runFail("test", "-c", "testcycle/p3") + tg.grepStderr("import cycle not allowed in test", "go test testcycle/p3 produced unexpected error") + + tg.runFail("test", "-c", "testcycle/q1") + tg.grepStderr("import cycle not allowed in test", "go test testcycle/q1 produced unexpected error") +} + +func TestGoTestFooTestWorks(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.run("test", "testdata/standalone_test.go") +} + +func TestGoTestXtestonlyWorks(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) + tg.run("clean", "-i", "xtestonly") + tg.run("test", "xtestonly") +} + +func TestGoTestBuildsAnXtestContainingOnlyNonRunnableExamples(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.run("test", "-v", "./testdata/norunexample") + tg.grepStdout("File with non-runnable example was built.", "file with non-runnable example was not built") +} + +func TestGoGenerateHandlesSimpleCommand(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("skipping because windows has no echo command") + } + + tg := testgo(t) + defer tg.cleanup() + tg.run("generate", "./testdata/generate/test1.go") + tg.grepStdout("Success", "go generate ./testdata/generate/test1.go generated wrong output") +} + +func TestGoGenerateHandlesCommandAlias(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("skipping because windows has no echo command") + } + + tg := testgo(t) + defer tg.cleanup() + tg.run("generate", "./testdata/generate/test2.go") + tg.grepStdout("Now is the time for all good men", "go generate ./testdata/generate/test2.go generated wrong output") +} + +func TestGoGenerateVariableSubstitution(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("skipping because windows has no echo command") + } + + tg := testgo(t) + defer tg.cleanup() + tg.run("generate", "./testdata/generate/test3.go") + tg.grepStdout(runtime.GOARCH+" test3.go:7 pabc xyzp/test3.go/123", "go generate ./testdata/generate/test3.go generated wrong output") +} + +func TestGoGenerateRunFlag(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("skipping because windows has no echo command") + } + + tg := testgo(t) + defer tg.cleanup() + tg.run("generate", "-run", "y.s", "./testdata/generate/test4.go") + tg.grepStdout("yes", "go generate -run yes ./testdata/generate/test4.go did not select yes") + tg.grepStdoutNot("no", "go generate -run yes ./testdata/generate/test4.go selected no") +} + +func TestGoGetCustomDomainWildcard(t *testing.T) { + testenv.MustHaveExternalNetwork(t) + + tg := testgo(t) + defer tg.cleanup() + tg.makeTempdir() + tg.setenv("GOPATH", tg.path(".")) + tg.run("get", "-u", "rsc.io/pdf/...") + tg.wantExecutable(tg.path("bin/pdfpasswd"+exeSuffix), "did not build rsc/io/pdf/pdfpasswd") +} + +func TestGoGetInternalWildcard(t *testing.T) { + testenv.MustHaveExternalNetwork(t) + + tg := testgo(t) + defer tg.cleanup() + tg.makeTempdir() + tg.setenv("GOPATH", tg.path(".")) + // used to fail with errors about internal packages + tg.run("get", "github.com/rsc/go-get-issue-11960/...") +} + +func TestGoVetWithExternalTests(t *testing.T) { + testenv.MustHaveExternalNetwork(t) + + tg := testgo(t) + defer tg.cleanup() + tg.makeTempdir() + tg.setenv("GOPATH", tg.path(".")) + tg.run("get", "golang.org/x/tools/cmd/vet") + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) + tg.runFail("vet", "vetpkg") + tg.grepBoth("missing argument for Printf", "go vet vetpkg did not find missing argument for Printf") +} + +func TestGoVetWithTags(t *testing.T) { + testenv.MustHaveExternalNetwork(t) + + tg := testgo(t) + defer tg.cleanup() + tg.makeTempdir() + tg.setenv("GOPATH", tg.path(".")) + tg.run("get", "golang.org/x/tools/cmd/vet") + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) + tg.runFail("vet", "-tags", "tagtest", "vetpkg") + tg.grepBoth(`c\.go.*wrong number of args for format`, "go get vetpkg did not run scan tagged file") +} + +// Issue 9767. +func TestGoGetRscIoToolstash(t *testing.T) { + testenv.MustHaveExternalNetwork(t) + + tg := testgo(t) + defer tg.cleanup() + tg.tempDir("src/rsc.io") + tg.setenv("GOPATH", tg.path(".")) + tg.cd(tg.path("src/rsc.io")) + tg.run("get", "./toolstash") +} + +// Test that you can not import a main package. +func TestIssue4210(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.tempFile("src/x/main.go", `package main + var X int + func main() {}`) + tg.tempFile("src/y/main.go", `package main + import "fmt" + import xmain "x" + func main() { + fmt.Println(xmain.X) + }`) + tg.setenv("GOPATH", tg.path(".")) + tg.runFail("build", "y") + tg.grepBoth("is a program", `did not find expected error message ("is a program")`) +} + +func TestGoGetInsecure(t *testing.T) { + testenv.MustHaveExternalNetwork(t) + + tg := testgo(t) + defer tg.cleanup() + tg.makeTempdir() + tg.setenv("GOPATH", tg.path(".")) + tg.failSSH() + + const repo = "wh3rd.net/git.git" + + // Try go get -d of HTTP-only repo (should fail). + tg.runFail("get", "-d", repo) + + // Try again with -insecure (should succeed). + tg.run("get", "-d", "-insecure", repo) + + // Try updating without -insecure (should fail). + tg.runFail("get", "-d", "-u", "-f", repo) +} + +func TestGoGetUpdateInsecure(t *testing.T) { + testenv.MustHaveExternalNetwork(t) + + tg := testgo(t) + defer tg.cleanup() + tg.makeTempdir() + tg.setenv("GOPATH", tg.path(".")) + + const repo = "github.com/golang/example" + + // Clone the repo via HTTP manually. + cmd := exec.Command("git", "clone", "-q", "http://"+repo, tg.path("src/"+repo)) + if out, err := cmd.CombinedOutput(); err != nil { + t.Fatalf("cloning %v repo: %v\n%s", repo, err, out) + } + + // Update without -insecure should fail. + // Update with -insecure should succeed. + // We need -f to ignore import comments. + const pkg = repo + "/hello" + tg.runFail("get", "-d", "-u", "-f", pkg) + tg.run("get", "-d", "-u", "-f", "-insecure", pkg) +} + +func TestGoGetInsecureCustomDomain(t *testing.T) { + testenv.MustHaveExternalNetwork(t) + + tg := testgo(t) + defer tg.cleanup() + tg.makeTempdir() + tg.setenv("GOPATH", tg.path(".")) + + const repo = "wh3rd.net/repo" + tg.runFail("get", "-d", repo) + tg.run("get", "-d", "-insecure", repo) +} + +func TestIssue10193(t *testing.T) { + testenv.MustHaveExternalNetwork(t) + + tg := testgo(t) + defer tg.cleanup() + tg.parallel() + tg.tempDir("src") + tg.setenv("GOPATH", tg.path(".")) + tg.runFail("get", "code.google.com/p/rsc/pdf") + tg.grepStderr("is shutting down", "missed warning about code.google.com") +} + +func TestGoRunDirs(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.cd("testdata/rundir") + tg.runFail("run", "x.go", "sub/sub.go") + tg.grepStderr("named files must all be in one directory; have ./ and sub/", "wrong output") + tg.runFail("run", "sub/sub.go", "x.go") + tg.grepStderr("named files must all be in one directory; have sub/ and ./", "wrong output") +} + +func TestGoInstallPkgdir(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.makeTempdir() + pkg := tg.path(".") + tg.run("install", "-pkgdir", pkg, "errors") + _, err := os.Stat(filepath.Join(pkg, "errors.a")) + tg.must(err) + _, err = os.Stat(filepath.Join(pkg, "runtime.a")) + tg.must(err) +} + +func TestGoTestRaceInstallCgo(t *testing.T) { + switch sys := runtime.GOOS + "/" + runtime.GOARCH; sys { + case "darwin/amd64", "freebsd/amd64", "linux/amd64", "windows/amd64": + // ok + default: + t.Skip("no race detector on %s", sys) + } + + if !build.Default.CgoEnabled { + t.Skip("no race detector without cgo") + } + + // golang.org/issue/10500. + // This used to install a race-enabled cgo. + tg := testgo(t) + defer tg.cleanup() + tg.run("tool", "-n", "cgo") + cgo := strings.TrimSpace(tg.stdout.String()) + old, err := os.Stat(cgo) + tg.must(err) + tg.run("test", "-race", "-i", "runtime/race") + new, err := os.Stat(cgo) + tg.must(err) + if new.ModTime() != old.ModTime() { + t.Fatalf("go test -i runtime/race reinstalled cmd/cgo") + } +} + +func TestGoTestImportErrorStack(t *testing.T) { + const out = `package testdep/p1 (test) + imports testdep/p2 + imports testdep/p3: no buildable Go source files` + + tg := testgo(t) + defer tg.cleanup() + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) + tg.runFail("test", "testdep/p1") + if !strings.Contains(tg.stderr.String(), out) { + t.Fatal("did not give full import stack:\n\n%s", tg.stderr.String()) + } +} + +func TestGoGetUpdate(t *testing.T) { + // golang.org/issue/9224. + // The recursive updating was trying to walk to + // former dependencies, not current ones. + + testenv.MustHaveExternalNetwork(t) + + tg := testgo(t) + defer tg.cleanup() + tg.makeTempdir() + tg.setenv("GOPATH", tg.path(".")) + + rewind := func() { + tg.run("get", "github.com/rsc/go-get-issue-9224-cmd") + cmd := exec.Command("git", "reset", "--hard", "HEAD~") + cmd.Dir = tg.path("src/github.com/rsc/go-get-issue-9224-lib") + out, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("git: %v\n%s", err, out) + } + } + + rewind() + tg.run("get", "-u", "github.com/rsc/go-get-issue-9224-cmd") + + // Again with -d -u. + rewind() + tg.run("get", "-d", "-u", "github.com/rsc/go-get-issue-9224-cmd") +} + +func TestGoGetDomainRoot(t *testing.T) { + // golang.org/issue/9357. + // go get foo.io (not foo.io/subdir) was not working consistently. + + testenv.MustHaveExternalNetwork(t) + + tg := testgo(t) + defer tg.cleanup() + tg.makeTempdir() + tg.setenv("GOPATH", tg.path(".")) + + // go-get-issue-9357.appspot.com is running + // the code at github.com/rsc/go-get-issue-9357, + // a trivial Go on App Engine app that serves a + // tag for the domain root. + tg.run("get", "-d", "go-get-issue-9357.appspot.com") + tg.run("get", "go-get-issue-9357.appspot.com") + tg.run("get", "-u", "go-get-issue-9357.appspot.com") + + tg.must(os.RemoveAll(tg.path("src/go-get-issue-9357.appspot.com"))) + tg.run("get", "go-get-issue-9357.appspot.com") + + tg.must(os.RemoveAll(tg.path("src/go-get-issue-9357.appspot.com"))) + tg.run("get", "-u", "go-get-issue-9357.appspot.com") +} + +func TestGoInstallShadowedGOPATH(t *testing.T) { + // golang.org/issue/3652. + // go get foo.io (not foo.io/subdir) was not working consistently. + + testenv.MustHaveExternalNetwork(t) + + tg := testgo(t) + defer tg.cleanup() + tg.makeTempdir() + tg.setenv("GOPATH", tg.path("gopath1")+string(filepath.ListSeparator)+tg.path("gopath2")) + + tg.tempDir("gopath1/src/test") + tg.tempDir("gopath2/src/test") + tg.tempFile("gopath2/src/test/main.go", "package main\nfunc main(){}\n") + + tg.cd(tg.path("gopath2/src/test")) + tg.runFail("install") + tg.grepStderr("no install location for.*gopath2.src.test: hidden by .*gopath1.src.test", "missing error") +} + +func TestIssue11709(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.tempFile("run.go", ` + package main + import "os" + func main() { + if os.Getenv("TERM") != "" { + os.Exit(1) + } + }`) + tg.unsetenv("TERM") + tg.run("run", tg.path("run.go")) +} + +func TestIssue12096(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.tempFile("test_test.go", ` + package main + import ("os"; "testing") + func TestEnv(t *testing.T) { + if os.Getenv("TERM") != "" { + t.Fatal("TERM is set") + } + }`) + tg.unsetenv("TERM") + tg.run("test", tg.path("test_test.go")) +} + +func TestGoBuildOutput(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + + tg.makeTempdir() + tg.cd(tg.path(".")) + + nonExeSuffix := ".exe" + if exeSuffix == ".exe" { + nonExeSuffix = "" + } + + tg.tempFile("x.go", "package main\nfunc main(){}\n") + tg.run("build", "x.go") + tg.wantExecutable("x"+exeSuffix, "go build x.go did not write x"+exeSuffix) + tg.must(os.Remove(tg.path("x" + exeSuffix))) + tg.mustNotExist("x" + nonExeSuffix) + + tg.run("build", "-o", "myprog", "x.go") + tg.mustNotExist("x") + tg.mustNotExist("x.exe") + tg.wantExecutable("myprog", "go build -o myprog x.go did not write myprog") + tg.mustNotExist("myprog.exe") + + tg.tempFile("p.go", "package p\n") + tg.run("build", "p.go") + tg.mustNotExist("p") + tg.mustNotExist("p.a") + tg.mustNotExist("p.o") + tg.mustNotExist("p.exe") + + tg.run("build", "-o", "p.a", "p.go") + tg.wantArchive("p.a") + + tg.run("build", "cmd/gofmt") + tg.wantExecutable("gofmt"+exeSuffix, "go build cmd/gofmt did not write gofmt"+exeSuffix) + tg.must(os.Remove(tg.path("gofmt" + exeSuffix))) + tg.mustNotExist("gofmt" + nonExeSuffix) + + tg.run("build", "-o", "mygofmt", "cmd/gofmt") + tg.wantExecutable("mygofmt", "go build -o mygofmt cmd/gofmt did not write mygofmt") + tg.mustNotExist("mygofmt.exe") + tg.mustNotExist("gofmt") + tg.mustNotExist("gofmt.exe") + + tg.run("build", "sync/atomic") + tg.mustNotExist("atomic") + tg.mustNotExist("atomic.exe") + + tg.run("build", "-o", "myatomic.a", "sync/atomic") + tg.wantArchive("myatomic.a") + tg.mustNotExist("atomic") + tg.mustNotExist("atomic.a") + tg.mustNotExist("atomic.exe") + + tg.runFail("build", "-o", "whatever", "cmd/gofmt", "sync/atomic") + tg.grepStderr("multiple packages", "did not reject -o with multiple packages") +} + +func TestGoBuildARM(t *testing.T) { + if testing.Short() { + t.Skip("skipping cross-compile in short mode") + } + + tg := testgo(t) + defer tg.cleanup() + + tg.makeTempdir() + tg.cd(tg.path(".")) + + tg.setenv("GOARCH", "arm") + tg.setenv("GOOS", "linux") + tg.setenv("GOARM", "5") + tg.tempFile("hello.go", `package main + func main() {}`) + tg.run("build", "hello.go") + tg.grepStderrNot("unable to find math.a", "did not build math.a correctly") +} diff --git a/libgo/go/cmd/go/help.go b/libgo/go/cmd/go/help.go index c590fdb37fe..5dff2670f1b 100644 --- a/libgo/go/cmd/go/help.go +++ b/libgo/go/cmd/go/help.go @@ -11,7 +11,7 @@ var helpC = &Command{ There are two different ways to call between Go and C/C++ code. The first is the cgo tool, which is part of the Go distribution. For -information on how to use it see the cgo documentation (godoc cmd/cgo). +information on how to use it see the cgo documentation (go doc cmd/cgo). The second is the SWIG program, which is a general tool for interfacing between languages. For information on SWIG see @@ -47,7 +47,7 @@ environment variable (see 'go help gopath'). If no import paths are given, the action applies to the package in the current directory. -There are three reserved names for paths that should not be used +There are four reserved names for paths that should not be used for packages to be built with the go tool: - "main" denotes the top-level package in a stand-alone executable. @@ -59,6 +59,9 @@ system. - "std" is like all but expands to just the packages in the standard Go library. +- "cmd" expands to the Go repository's commands and their +internal libraries. + 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 @@ -74,7 +77,7 @@ By convention, this is arranged by starting each path with a unique prefix that belongs to you. For example, paths used internally at Google all begin with 'google', and paths denoting remote repositories begin with the path to the code, -such as 'code.google.com/p/project'. +such as 'github.com/user/repo'. As a special case, if the package list is a list of .go files from a single directory, the command is applied to a single synthesized @@ -192,7 +195,7 @@ example.org/repo or repo.git. 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://. +download tries https://, then git+ssh://. 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 @@ -208,6 +211,10 @@ 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 tags match. +The meta tag should appear as early in the file as possible. +In particular, it should appear before any raw JavaScript or CSS, +to avoid confusing the go command's restricted parser. + The vcs is one of "git", "hg", "svn", etc, The repo-root is the root of the version control system @@ -217,10 +224,10 @@ For example, import "example.org/pkg/foo" -will result in the following request(s): +will result in the following requests: https://example.org/pkg/foo?go-get=1 (preferred) - http://example.org/pkg/foo?go-get=1 (fallback) + http://example.org/pkg/foo?go-get=1 (fallback, only with -insecure) If that page contains the meta tag @@ -254,6 +261,11 @@ unless it is being referred to by that import path. In this way, import comments let package authors make sure the custom import path is used and not a direct path to the underlying code hosting site. +If the vendoring experiment is enabled (see 'go help gopath'), +then import path checking is disabled for code found within vendor trees. +This makes it possible to copy code into alternate locations in vendor trees +without needing to update import comments. + See https://golang.org/s/go14customimport for details. `, } @@ -275,10 +287,10 @@ standard Go tree. Each directory listed in GOPATH must have a prescribed structure: -The src/ directory holds source code. The path below 'src' +The src directory holds source code. The path below src determines the import path or executable name. -The pkg/ directory holds installed package objects. +The pkg directory holds installed package objects. As in the Go tree, each target operating system and architecture pair has its own subdirectory of pkg (pkg/GOOS_GOARCH). @@ -287,11 +299,11 @@ If DIR is a directory listed in the GOPATH, a package with source in DIR/src/foo/bar can be imported as "foo/bar" and has its compiled form installed to "DIR/pkg/GOOS_GOARCH/foo/bar.a". -The bin/ directory holds compiled commands. +The bin directory holds compiled commands. Each command is named for its source directory, but only the final element, not the entire path. That is, the command with source in DIR/src/foo/quux is installed into -DIR/bin/quux, not DIR/bin/foo/quux. The foo/ is stripped +DIR/bin/quux, not DIR/bin/foo/quux. The "foo/" prefix is stripped so that you can add DIR/bin to your PATH to get at the installed commands. If the GOBIN environment variable is set, commands are installed to the directory it names instead @@ -318,6 +330,168 @@ Here's an example directory layout: Go searches each directory listed in GOPATH to find source code, but new packages are always downloaded into the first directory in the list. + +See https://golang.org/doc/code.html for an example. + +Internal Directories + +Code in or below a directory named "internal" is importable only +by code in the directory tree rooted at the parent of "internal". +Here's an extended version of the directory layout above: + + /home/user/gocode/ + src/ + crash/ + bang/ (go code in package bang) + b.go + foo/ (go code in package foo) + f.go + bar/ (go code in package bar) + x.go + internal/ + baz/ (go code in package baz) + z.go + quux/ (go code in package main) + y.go + + +The code in z.go is imported as "foo/internal/baz", but that +import statement can only appear in source files in the subtree +rooted at foo. The source files foo/f.go, foo/bar/x.go, and +foo/quux/y.go can all import "foo/internal/baz", but the source file +crash/bang/b.go cannot. + +See https://golang.org/s/go14internal for details. + +Vendor Directories + +Go 1.5 includes experimental support for using local copies +of external dependencies to satisfy imports of those dependencies, +often referred to as vendoring. Setting the environment variable +GO15VENDOREXPERIMENT=1 enables that experimental support. + +When the vendor experiment is enabled, +code below a directory named "vendor" is importable only +by code in the directory tree rooted at the parent of "vendor", +and only using an import path that omits the prefix up to and +including the vendor element. + +Here's the example from the previous section, +but with the "internal" directory renamed to "vendor" +and a new foo/vendor/crash/bang directory added: + + /home/user/gocode/ + src/ + crash/ + bang/ (go code in package bang) + b.go + foo/ (go code in package foo) + f.go + bar/ (go code in package bar) + x.go + vendor/ + crash/ + bang/ (go code in package bang) + b.go + baz/ (go code in package baz) + z.go + quux/ (go code in package main) + y.go + +The same visibility rules apply as for internal, but the code +in z.go is imported as "baz", not as "foo/vendor/baz". + +Code in vendor directories deeper in the source tree shadows +code in higher directories. Within the subtree rooted at foo, an import +of "crash/bang" resolves to "foo/vendor/crash/bang", not the +top-level "crash/bang". + +Code in vendor directories is not subject to import path +checking (see 'go help importpath'). + +When the vendor experiment is enabled, 'go get' checks out +submodules when checking out or updating a git repository +(see 'go help get'). + +The vendoring semantics are an experiment, and they may change +in future releases. Once settled, they will be on by default. + +See https://golang.org/s/go15vendor for details. + `, +} + +var helpEnvironment = &Command{ + UsageLine: "environment", + Short: "environment variables", + Long: ` + +The go command, and the tools it invokes, examine a few different +environment variables. For many of these, you can see the default +value of on your system by running 'go env NAME', where NAME is the +name of the variable. + +General-purpose environment variables: + + GCCGO + The gccgo command to run for 'go build -compiler=gccgo'. + GOARCH + The architecture, or processor, for which to compile code. + Examples are amd64, 386, arm, ppc64. + GOBIN + The directory where 'go install' will install a command. + GOOS + The operating system for which to compile code. + Examples are linux, darwin, windows, netbsd. + GOPATH + See 'go help gopath'. + GORACE + Options for the race detector. + See https://golang.org/doc/articles/race_detector.html. + GOROOT + The root of the go tree. + +Environment variables for use with cgo: + + CC + The command to use to compile C code. + CGO_ENABLED + Whether the cgo command is supported. Either 0 or 1. + CGO_CFLAGS + Flags that cgo will pass to the compiler when compiling + C code. + CGO_CPPFLAGS + Flags that cgo will pass to the compiler when compiling + C or C++ code. + CGO_CXXFLAGS + Flags that cgo will pass to the compiler when compiling + C++ code. + CGO_LDFLAGS + Flags that cgo will pass to the compiler when linking. + CXX + The command to use to compile C++ code. + +Architecture-specific environment variables: + + GOARM + For GOARCH=arm, the ARM architecture for which to compile. + Valid values are 5, 6, 7. + GO386 + For GOARCH=386, the floating point instruction set. + Valid values are 387, sse2. + +Special-purpose environment variables: + + GOROOT_FINAL + The root of the installed Go tree, when it is + installed in a location other than where it is built. + File names in stack traces are rewritten from GOROOT to + GOROOT_FINAL. + GO15VENDOREXPERIMENT + Set to 1 to enable the Go 1.5 vendoring experiment. + GO_EXTLINK_ENABLED + Whether the linker should use external linking mode + when using -linkmode=auto with code that uses cgo. + Set to 0 to disable external linking mode, 1 to enable it. `, } @@ -333,10 +507,9 @@ the extension of the file name. These extensions are: Go source files. .c, .h C source files. - If the package uses cgo, these will be compiled with the - OS-native compiler (typically gcc); otherwise they will be - compiled with the Go-specific support compiler, - 5c, 6c, or 8c, etc. as appropriate. + If the package uses cgo or SWIG, these will be compiled with the + OS-native compiler (typically gcc); otherwise they will + trigger an error. .cc, .cpp, .cxx, .hh, .hpp, .hxx C++ source files. Only useful with cgo or SWIG, and always compiled with the OS-native compiler. @@ -345,10 +518,9 @@ the extension of the file name. These extensions are: compiled with the OS-native compiler. .s, .S Assembler source files. - If the package uses cgo, these will be assembled with the + If the package uses cgo or SWIG, these will be assembled with the OS-native assembler (typically gcc (sic)); otherwise they - will be assembled with the Go-specific support assembler, - 5a, 6a, or 8a, etc., as appropriate. + will be assembled with the Go assembler. .swig, .swigcxx SWIG definition files. .syso @@ -360,3 +532,43 @@ at the first item in the file that is not a blank line or //-style line comment. `, } + +var helpBuildmode = &Command{ + UsageLine: "buildmode", + Short: "description of build modes", + Long: ` +The 'go build' and 'go install' commands take a -buildmode argument which +indicates which kind of object file is to be built. Currently supported values +are: + + -buildmode=archive + Build the listed non-main packages into .a files. Packages named + main are ignored. + + -buildmode=c-archive + Build the listed main package, plus all packages it imports, + into a C archive file. The only callable symbols will be those + functions exported using a cgo //export comment. Requires + exactly one main package to be listed. + + -buildmode=c-shared + Build the listed main packages, plus all packages that they + import, into C shared libraries. The only callable symbols will + be those functions exported using a cgo //export comment. + Non-main packages are ignored. + + -buildmode=default + Listed main packages are built into executables and listed + non-main packages are built into .a files (the default + behavior). + + -buildmode=shared + Combine all the listed non-main packages into a single shared + library that will be used when building with the -linkshared + option. Packages named main are ignored. + + -buildmode=exe + Build the listed main packages and everything they import into + executables. Packages not named main are ignored. +`, +} diff --git a/libgo/go/cmd/go/http.go b/libgo/go/cmd/go/http.go index 107b820f28c..7979c41b11b 100644 --- a/libgo/go/cmd/go/http.go +++ b/libgo/go/cmd/go/http.go @@ -18,11 +18,25 @@ import ( "log" "net/http" "net/url" + "time" ) // httpClient is the default HTTP client, but a variable so it can be // changed by tests, without modifying http.DefaultClient. var httpClient = http.DefaultClient +var impatientHTTPClient = &http.Client{ + Timeout: time.Duration(5 * time.Second), +} + +type httpError struct { + status string + statusCode int + url string +} + +func (e *httpError) Error() string { + return fmt.Sprintf("%s: %s", e.url, e.status) +} // httpGET returns the data from an HTTP GET request for the given URL. func httpGET(url string) ([]byte, error) { @@ -32,7 +46,9 @@ func httpGET(url string) ([]byte, error) { } defer resp.Body.Close() if resp.StatusCode != 200 { - return nil, fmt.Errorf("%s: %s", url, resp.Status) + err := &httpError{status: resp.Status, statusCode: resp.StatusCode, url: url} + + return nil, err } b, err := ioutil.ReadAll(resp.Body) if err != nil { @@ -43,7 +59,7 @@ func httpGET(url string) ([]byte, error) { // 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) { +func httpsOrHTTP(importPath string, security securityMode) (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 { @@ -54,7 +70,11 @@ func httpsOrHTTP(importPath string) (urlStr string, body io.ReadCloser, err erro if buildV { log.Printf("Fetching %s", urlStr) } - res, err = httpClient.Get(urlStr) + if security == insecure && scheme == "https" { // fail earlier + res, err = impatientHTTPClient.Get(urlStr) + } else { + res, err = httpClient.Get(urlStr) + } return } closeBody := func(res *http.Response) { @@ -72,7 +92,9 @@ func httpsOrHTTP(importPath string) (urlStr string, body io.ReadCloser, err erro } } closeBody(res) - urlStr, res, err = fetch("http") + if security == insecure { + urlStr, res, err = fetch("http") + } } if err != nil { closeBody(res) diff --git a/libgo/go/cmd/go/list.go b/libgo/go/cmd/go/list.go index fbf96167feb..35c7cc4f2a7 100644 --- a/libgo/go/cmd/go/list.go +++ b/libgo/go/cmd/go/list.go @@ -21,9 +21,10 @@ List lists the packages named by the import paths, one per line. The default output shows the package import path: - code.google.com/p/google-api-go-client/books/v1 - code.google.com/p/goauth2/oauth - code.google.com/p/sqlite + bytes + encoding/json + github.com/gorilla/mux + golang.org/x/net/html The -f flag specifies an alternate format for the list, using the syntax of package template. The default output is equivalent to -f @@ -36,6 +37,7 @@ syntax of package template. The default output is equivalent to -f Name string // package name Doc string // package documentation string Target string // install path + Shlib string // the shared library that contains this package (only set when -linkshared) 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? @@ -126,6 +128,7 @@ var listJson = cmdList.Flag.Bool("json", false, "") var nl = []byte{'\n'} func runList(cmd *Command, args []string) { + buildModeInit() out := newTrackingWriter(os.Stdout) defer out.w.Flush() @@ -173,6 +176,10 @@ func runList(cmd *Command, args []string) { } for _, pkg := range load(args) { + // Show vendor-expanded paths in listing + pkg.TestImports = pkg.vendored(pkg.TestImports) + pkg.XTestImports = pkg.vendored(pkg.XTestImports) + do(pkg) } } diff --git a/libgo/go/cmd/go/main.go b/libgo/go/cmd/go/main.go index 9691f39c763..8ebde892599 100644 --- a/libgo/go/cmd/go/main.go +++ b/libgo/go/cmd/go/main.go @@ -5,6 +5,7 @@ package main import ( + "bufio" "bytes" "flag" "fmt" @@ -76,6 +77,7 @@ func (c *Command) Runnable() bool { var commands = []*Command{ cmdBuild, cmdClean, + cmdDoc, cmdEnv, cmdFix, cmdFmt, @@ -90,8 +92,10 @@ var commands = []*Command{ cmdVet, helpC, + helpBuildmode, helpFileType, helpGopath, + helpEnvironment, helpImportPath, helpPackages, helpTestflag, @@ -109,6 +113,8 @@ func setExitStatus(n int) { exitMu.Unlock() } +var origEnv []string + func main() { _ = go11tag flag.Usage = usage @@ -139,7 +145,7 @@ func main() { fmt.Fprintf(os.Stderr, "go: GOPATH entry cannot start with shell metacharacter '~': %q\n", p) os.Exit(2) } - if build.IsLocalImport(p) { + if !filepath.IsAbs(p) { fmt.Fprintf(os.Stderr, "go: GOPATH entry is relative; must be absolute path: %q.\nRun 'go help gopath' for usage.\n", p) os.Exit(2) } @@ -151,8 +157,20 @@ func main() { os.Exit(2) } + // Set environment (GOOS, GOARCH, etc) explicitly. + // In theory all the commands we invoke should have + // the same default computation of these as we do, + // but in practice there might be skew + // This makes sure we all agree. + origEnv = os.Environ() + for _, env := range mkEnv() { + if os.Getenv(env.name) != env.value { + os.Setenv(env.name, env.value) + } + } + for _, cmd := range commands { - if cmd.Name() == args[0] && cmd.Run != nil { + if cmd.Name() == args[0] && cmd.Runnable() { cmd.Flag.Usage = func() { cmd.Usage() } if cmd.CustomFlags { args = args[1:] @@ -179,13 +197,13 @@ Usage: The commands are: {{range .}}{{if .Runnable}} - {{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}} + {{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}} Use "go help [command]" for more information about a command. Additional help topics: {{range .}}{{if not .Runnable}} - {{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}} + {{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}} Use "go help [topic]" for more information about that topic. @@ -200,8 +218,8 @@ var documentationTemplate = `// Copyright 2011 The Go Authors. All rights reser // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// DO NOT EDIT THIS FILE. GENERATED BY mkdoc.sh. -// Edit the documentation in other files and rerun mkdoc.sh to generate this one. +// DO NOT EDIT THIS FILE. GENERATED BY mkalldocs.sh. +// Edit the documentation in other files and rerun mkalldocs.sh to generate this one. /* {{range .}}{{if .Short}}{{.Short | capitalize}} @@ -217,12 +235,35 @@ var documentationTemplate = `// Copyright 2011 The Go Authors. All rights reser package main ` +// An errWriter wraps a writer, recording whether a write error occurred. +type errWriter struct { + w io.Writer + err error +} + +func (w *errWriter) Write(b []byte) (int, error) { + n, err := w.w.Write(b) + if err != nil { + w.err = err + } + return n, err +} + // tmpl executes the given template text on data, writing the result to w. func tmpl(w io.Writer, text string, data interface{}) { t := template.New("top") t.Funcs(template.FuncMap{"trim": strings.TrimSpace, "capitalize": capitalize}) template.Must(t.Parse(text)) - if err := t.Execute(w, data); err != nil { + ew := &errWriter{w: w} + err := t.Execute(ew, data) + if ew.err != nil { + // I/O error writing. Ignore write on closed pipe. + if strings.Contains(ew.err.Error(), "pipe") { + os.Exit(1) + } + fatalf("writing output: %v", ew.err) + } + if err != nil { panic(err) } } @@ -236,13 +277,17 @@ func capitalize(s string) string { } func printUsage(w io.Writer) { - tmpl(w, usageTemplate, commands) + bw := bufio.NewWriter(w) + tmpl(bw, usageTemplate, commands) + bw.Flush() } func usage() { // special case "go test -h" if len(os.Args) > 1 && os.Args[1] == "test" { - help([]string{"testflag"}) + os.Stdout.WriteString(testUsage + "\n\n" + + strings.TrimSpace(testFlag1) + "\n\n" + + strings.TrimSpace(testFlag2) + "\n") os.Exit(2) } printUsage(os.Stderr) @@ -308,7 +353,7 @@ func importPathsNoDotExpansion(args []string) []string { } else { a = path.Clean(a) } - if a == "all" || a == "std" { + if a == "all" || a == "std" || a == "cmd" { out = append(out, allPackages(a)...) continue } @@ -401,11 +446,10 @@ func runOut(dir string, cmdargs ...interface{}) []byte { // The environment is the current process's environment // but with an updated $PWD, so that an os.Getwd in the // child will be faster. -func envForDir(dir string) []string { - env := os.Environ() +func envForDir(dir string, base []string) []string { // Internally we only use rooted paths, so dir is rooted. // Even if dir is not rooted, no harm done. - return mergeEnvLists([]string{"PWD=" + dir}, env) + return mergeEnvLists([]string{"PWD=" + dir}, base) } // mergeEnvLists merges the two environment lists such that @@ -458,6 +502,28 @@ func hasPathPrefix(s, prefix string) bool { } } +// hasFilePathPrefix reports whether the filesystem path s begins with the +// elements in prefix. +func hasFilePathPrefix(s, prefix string) bool { + sv := strings.ToUpper(filepath.VolumeName(s)) + pv := strings.ToUpper(filepath.VolumeName(prefix)) + s = s[len(sv):] + prefix = prefix[len(pv):] + switch { + default: + return false + case sv != pv: + return false + case len(s) == len(prefix): + return s == prefix + case len(s) > len(prefix): + if prefix != "" && prefix[len(prefix)-1] == filepath.Separator { + return strings.HasPrefix(s, prefix) + } + return s[len(prefix)] == filepath.Separator && s[:len(prefix)] == prefix + } +} + // treeCanMatchPattern(pattern)(name) reports whether // name or children of name can possibly match pattern. // Pattern is the same limited glob accepted by matchPattern. @@ -475,8 +541,8 @@ func treeCanMatchPattern(pattern string) func(name string) bool { // allPackages returns all the packages that can be found // under the $GOPATH directories and $GOROOT matching pattern. -// The pattern is either "all" (all packages), "std" (standard packages) -// or a path including "...". +// The pattern is either "all" (all packages), "std" (standard packages), +// "cmd" (standard commands), or a path including "...". func allPackages(pattern string) []string { pkgs := matchPackages(pattern) if len(pkgs) == 0 { @@ -488,7 +554,7 @@ func allPackages(pattern string) []string { func matchPackages(pattern string) []string { match := func(string) bool { return true } treeCanMatch := func(string) bool { return true } - if pattern != "all" && pattern != "std" { + if pattern != "all" && pattern != "std" && pattern != "cmd" { match = matchPattern(pattern) treeCanMatch = treeCanMatchPattern(pattern) } @@ -501,47 +567,16 @@ func matchPackages(pattern string) []string { } var pkgs []string - // Commands - cmd := filepath.Join(goroot, "src/cmd") + string(filepath.Separator) - filepath.Walk(cmd, func(path string, fi os.FileInfo, err error) error { - if err != nil || !fi.IsDir() || path == cmd { - return nil - } - name := path[len(cmd):] - if !treeCanMatch(name) { - return filepath.SkipDir - } - // Commands are all in cmd/, not in subdirectories. - if strings.Contains(name, string(filepath.Separator)) { - return filepath.SkipDir - } - - // We use, e.g., cmd/gofmt as the pseudo import path for gofmt. - name = "cmd/" + name - if have[name] { - return nil - } - have[name] = true - if !match(name) { - return nil - } - _, err = buildContext.ImportDir(path, 0) - if err != nil { - if _, noGo := err.(*build.NoGoError); !noGo { - log.Print(err) - } - return nil - } - pkgs = append(pkgs, name) - return nil - }) - for _, src := range buildContext.SrcDirs() { - if pattern == "std" && src != gorootSrc { + if (pattern == "std" || pattern == "cmd") && src != gorootSrc { continue } src = filepath.Clean(src) + string(filepath.Separator) - filepath.Walk(src, func(path string, fi os.FileInfo, err error) error { + root := src + if pattern == "cmd" { + root += "cmd" + string(filepath.Separator) + } + filepath.Walk(root, func(path string, fi os.FileInfo, err error) error { if err != nil || !fi.IsDir() || path == src { return nil } @@ -553,7 +588,10 @@ func matchPackages(pattern string) []string { } name := filepath.ToSlash(path[len(src):]) - if pattern == "std" && strings.Contains(name, ".") { + if pattern == "std" && (strings.Contains(name, ".") || name == "cmd") { + // The name "std" is only the standard library. + // If the name has a dot, assume it's a domain name for go get, + // and if the name is cmd, it's the root of the command tree. return filepath.SkipDir } if !treeCanMatch(name) { @@ -659,7 +697,7 @@ func stringList(args ...interface{}) []string { case string: x = append(x, arg) default: - panic("stringList: invalid argument") + panic("stringList: invalid argument of type " + fmt.Sprintf("%T", arg)) } } return x diff --git a/libgo/go/cmd/go/note.go b/libgo/go/cmd/go/note.go new file mode 100644 index 00000000000..97e18651e4a --- /dev/null +++ b/libgo/go/cmd/go/note.go @@ -0,0 +1,116 @@ +// Copyright 2015 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 ( + "bytes" + "debug/elf" + "encoding/binary" + "fmt" + "io" + "os" +) + +func readAligned4(r io.Reader, sz int32) ([]byte, error) { + full := (sz + 3) &^ 3 + data := make([]byte, full) + _, err := io.ReadFull(r, data) + if err != nil { + return nil, err + } + data = data[:sz] + return data, nil +} + +func readELFNote(filename, name string, typ int32) ([]byte, error) { + f, err := elf.Open(filename) + if err != nil { + return nil, err + } + for _, sect := range f.Sections { + if sect.Type != elf.SHT_NOTE { + continue + } + r := sect.Open() + for { + var namesize, descsize, noteType int32 + err = binary.Read(r, f.ByteOrder, &namesize) + if err != nil { + if err == io.EOF { + break + } + return nil, fmt.Errorf("read namesize failed: %v", err) + } + err = binary.Read(r, f.ByteOrder, &descsize) + if err != nil { + return nil, fmt.Errorf("read descsize failed: %v", err) + } + err = binary.Read(r, f.ByteOrder, ¬eType) + if err != nil { + return nil, fmt.Errorf("read type failed: %v", err) + } + noteName, err := readAligned4(r, namesize) + if err != nil { + return nil, fmt.Errorf("read name failed: %v", err) + } + desc, err := readAligned4(r, descsize) + if err != nil { + return nil, fmt.Errorf("read desc failed: %v", err) + } + if name == string(noteName) && typ == noteType { + return desc, nil + } + } + } + return nil, nil +} + +var elfGoNote = []byte("Go\x00\x00") + +// readELFGoBuildID the Go build ID string from an ELF binary. +// The Go build ID is stored in a note described by an ELF PT_NOTE prog header. +// The caller has already opened filename, to get f, and read the first 4 kB out, in data. +func readELFGoBuildID(filename string, f *os.File, data []byte) (buildid string, err error) { + // Assume the note content is in the first 4 kB, already read. + // Rewrite the ELF header to set shnum to 0, so that we can pass + // the data to elf.NewFile and it will decode the Prog list but not + // try to read the section headers and the string table from disk. + // That's a waste of I/O when all we care about is the Prog list + // and the one ELF note. + switch elf.Class(data[elf.EI_CLASS]) { + case elf.ELFCLASS32: + data[48] = 0 + data[49] = 0 + case elf.ELFCLASS64: + data[60] = 0 + data[61] = 0 + } + + const elfGoBuildIDTag = 4 + + ef, err := elf.NewFile(bytes.NewReader(data)) + if err != nil { + return "", &os.PathError{Path: filename, Op: "parse", Err: err} + } + for _, p := range ef.Progs { + if p.Type != elf.PT_NOTE || p.Off >= uint64(len(data)) || p.Off+p.Filesz >= uint64(len(data)) || p.Filesz < 16 { + continue + } + + note := data[p.Off : p.Off+p.Filesz] + nameSize := ef.ByteOrder.Uint32(note) + valSize := ef.ByteOrder.Uint32(note[4:]) + tag := ef.ByteOrder.Uint32(note[8:]) + name := note[12:16] + if nameSize != 4 || 16+valSize > uint32(len(note)) || tag != elfGoBuildIDTag || !bytes.Equal(name, elfGoNote) { + continue + } + + return string(note[16 : 16+valSize]), nil + } + + // No note. Treat as successful but build ID empty. + return "", nil +} diff --git a/libgo/go/cmd/go/note_test.go b/libgo/go/cmd/go/note_test.go new file mode 100644 index 00000000000..3d644518c68 --- /dev/null +++ b/libgo/go/cmd/go/note_test.go @@ -0,0 +1,49 @@ +// Copyright 2015 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_test + +import ( + main "cmd/go" + "runtime" + "testing" +) + +func TestNoteReading(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.tempFile("hello.go", `package main; func main() { print("hello, world\n") }`) + const buildID = "TestNoteReading-Build-ID" + tg.run("build", "-ldflags", "-buildid="+buildID, "-o", tg.path("hello.exe"), tg.path("hello.go")) + id, err := main.ReadBuildIDFromBinary(tg.path("hello.exe")) + if err != nil { + t.Fatalf("reading build ID from hello binary: %v", err) + } + if id != buildID { + t.Fatalf("buildID in hello binary = %q, want %q", id, buildID) + } + + if runtime.GOOS == "linux" && runtime.GOARCH == "ppc64le" { + t.Skipf("skipping - golang.org/issue/11184") + } + + switch runtime.GOOS { + case "plan9": + // no external linking + t.Logf("no external linking - skipping linkmode=external test") + + case "solaris": + t.Logf("skipping - golang.org/issue/12178") + + default: + tg.run("build", "-ldflags", "-buildid="+buildID+" -linkmode=external", "-o", tg.path("hello.exe"), tg.path("hello.go")) + id, err := main.ReadBuildIDFromBinary(tg.path("hello.exe")) + if err != nil { + t.Fatalf("reading build ID from hello binary (linkmode=external): %v", err) + } + if id != buildID { + t.Fatalf("buildID in hello binary = %q, want %q (linkmode=external)", id, buildID) + } + } +} diff --git a/libgo/go/cmd/go/pkg.go b/libgo/go/cmd/go/pkg.go index ef440dd3b74..1af59b3760a 100644 --- a/libgo/go/cmd/go/pkg.go +++ b/libgo/go/cmd/go/pkg.go @@ -6,18 +6,21 @@ package main import ( "bytes" + "crypto/sha1" "errors" "fmt" "go/build" "go/scanner" "go/token" + "io" + "io/ioutil" "os" pathpkg "path" "path/filepath" "runtime" "sort" + "strconv" "strings" - "time" "unicode" ) @@ -32,6 +35,7 @@ type Package struct { Name string `json:",omitempty"` // package name Doc string `json:",omitempty"` // package documentation string Target string `json:",omitempty"` // install path + Shlib string `json:",omitempty"` // the shared library that contains this package (only set when -linkshared) 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? @@ -93,6 +97,35 @@ type Package struct { coverMode string // preprocess Go source files with the coverage tool in this mode coverVars map[string]*CoverVar // variables created by coverage analysis omitDWARF bool // tell linker not to write DWARF information + buildID string // expected build ID for generated package + gobinSubdir bool // install target would be subdir of GOBIN +} + +// vendored returns the vendor-resolved version of imports, +// which should be p.TestImports or p.XTestImports, NOT p.Imports. +// The imports in p.TestImports and p.XTestImports are not recursively +// loaded during the initial load of p, so they list the imports found in +// the source file, but most processing should be over the vendor-resolved +// import paths. We do this resolution lazily both to avoid file system work +// and because the eventual real load of the test imports (during 'go test') +// can produce better error messages if it starts with the original paths. +// The initial load of p loads all the non-test imports and rewrites +// the vendored paths, so nothing should ever call p.vendored(p.Imports). +func (p *Package) vendored(imports []string) []string { + if len(imports) > 0 && len(p.Imports) > 0 && &imports[0] == &p.Imports[0] { + panic("internal error: p.vendored(p.Imports) called") + } + seen := make(map[string]bool) + var all []string + for _, path := range imports { + path, _ = vendoredImportPath(p, path) + if !seen[path] { + seen[path] = true + all = append(all, path) + } + } + sort.Strings(all) + return all } // CoverVar holds the name of the generated coverage variables targeting the named file. @@ -104,6 +137,13 @@ type CoverVar struct { func (p *Package) copyBuild(pp *build.Package) { p.build = pp + if pp.PkgTargetRoot != "" && buildPkgdir != "" { + old := pp.PkgTargetRoot + pp.PkgRoot = buildPkgdir + pp.PkgTargetRoot = buildPkgdir + pp.PkgObj = filepath.Join(buildPkgdir, strings.TrimPrefix(pp.PkgObj, old)) + } + p.Dir = pp.Dir p.ImportPath = pp.ImportPath p.ImportComment = pp.ImportComment @@ -181,7 +221,7 @@ func (s *importStack) copy() []string { return append([]string{}, *s...) } -// shorterThan returns true if sp is shorter than t. +// shorterThan reports whether sp is shorter than t. // We use this to record the shortest import sequence // that leads to a particular package. func (sp *importStack) shorterThan(t []string) bool { @@ -214,6 +254,12 @@ func reloadPackage(arg string, stk *importStack) *Package { return loadPackage(arg, stk) } +// The Go 1.5 vendoring experiment is enabled by setting GO15VENDOREXPERIMENT=1. +// The variable is obnoxiously long so that years from now when people find it in +// their profiles and wonder what it does, there is some chance that a web search +// might answer the question. +var go15VendorExperiment = os.Getenv("GO15VENDOREXPERIMENT") == "1" + // dirToImportPath returns the pseudo-import path we use for a package // outside the Go path. It begins with _/ and then contains the full path // to the directory. If the package lives in c:\home\gopher\my\pkg then @@ -234,11 +280,29 @@ func makeImportValid(r rune) rune { return r } +// Mode flags for loadImport and download (in get.go). +const ( + // useVendor means that loadImport should do vendor expansion + // (provided the vendoring experiment is enabled). + // That is, useVendor means that the import path came from + // a source file and has not been vendor-expanded yet. + // Every import path should be loaded initially with useVendor, + // and then the expanded version (with the /vendor/ in it) gets + // recorded as the canonical import path. At that point, future loads + // of that package must not pass useVendor, because + // disallowVendor will reject direct use of paths containing /vendor/. + useVendor = 1 << iota + + // getTestDeps is for download (part of "go get") and indicates + // that test dependencies should be fetched too. + getTestDeps +) + // loadImport scans the directory named by path, which must be an import path, // but possibly a local import path (an absolute file system path or one beginning // with ./ or ../). A local relative path is interpreted relative to srcDir. // It returns a *Package describing the package found in that directory. -func loadImport(path string, srcDir string, stk *importStack, importPos []token.Position) *Package { +func loadImport(path, srcDir string, parent *Package, stk *importStack, importPos []token.Position, mode int) *Package { stk.push(path) defer stk.pop() @@ -246,15 +310,27 @@ func loadImport(path string, srcDir string, stk *importStack, importPos []token. // For a local import the identifier is the pseudo-import path // we create from the full directory to the package. // Otherwise it is the usual import path. + // For vendored imports, it is the expanded form. importPath := path + origPath := path isLocal := build.IsLocalImport(path) + var vendorSearch []string if isLocal { importPath = dirToImportPath(filepath.Join(srcDir, path)) + } else if mode&useVendor != 0 { + path, vendorSearch = vendoredImportPath(parent, path) + importPath = path } + if p := packageCache[importPath]; p != nil { if perr := disallowInternal(srcDir, p, stk); perr != p { return perr } + if mode&useVendor != 0 { + if perr := disallowVendor(srcDir, origPath, p, stk); perr != p { + return perr + } + } return reusePackage(p, stk) } @@ -270,11 +346,33 @@ func loadImport(path string, srcDir string, stk *importStack, importPos []token. // TODO: After Go 1, decide when to pass build.AllowBinary here. // See issue 3268 for mistakes to avoid. bp, err := buildContext.Import(path, srcDir, build.ImportComment) + + // If we got an error from go/build about package not found, + // it contains the directories from $GOROOT and $GOPATH that + // were searched. Add to that message the vendor directories + // that were searched. + if err != nil && len(vendorSearch) > 0 { + // NOTE(rsc): The direct text manipulation here is fairly awful, + // but it avoids defining new go/build API (an exported error type) + // late in the Go 1.5 release cycle. If this turns out to be a more general + // problem we could define a real error type when the decision can be + // considered more carefully. + text := err.Error() + if strings.Contains(text, "cannot find package \"") && strings.Contains(text, "\" in any of:\n\t") { + old := strings.SplitAfter(text, "\n") + lines := []string{old[0]} + for _, dir := range vendorSearch { + lines = append(lines, "\t"+dir+" (vendor tree)\n") + } + lines = append(lines, old[1:]...) + err = errors.New(strings.Join(lines, "")) + } + } bp.ImportPath = importPath if gobin != "" { bp.BinDir = gobin } - if err == nil && !isLocal && bp.ImportComment != "" && bp.ImportComment != path { + if err == nil && !isLocal && bp.ImportComment != "" && bp.ImportComment != path && (!go15VendorExperiment || !strings.Contains(path, "/vendor/")) { err = fmt.Errorf("code in directory %s expects import %q", bp.Dir, bp.ImportComment) } p.load(stk, bp, err) @@ -287,10 +385,83 @@ func loadImport(path string, srcDir string, stk *importStack, importPos []token. if perr := disallowInternal(srcDir, p, stk); perr != p { return perr } + if mode&useVendor != 0 { + if perr := disallowVendor(srcDir, origPath, p, stk); perr != p { + return perr + } + } return p } +var isDirCache = map[string]bool{} + +func isDir(path string) bool { + result, ok := isDirCache[path] + if ok { + return result + } + + fi, err := os.Stat(path) + result = err == nil && fi.IsDir() + isDirCache[path] = result + return result +} + +// vendoredImportPath returns the expansion of path when it appears in parent. +// If parent is x/y/z, then path might expand to x/y/z/vendor/path, x/y/vendor/path, +// x/vendor/path, vendor/path, or else stay x/y/z if none of those exist. +// vendoredImportPath returns the expanded path or, if no expansion is found, the original. +// If no expansion is found, vendoredImportPath also returns a list of vendor directories +// it searched along the way, to help prepare a useful error message should path turn +// out not to exist. +func vendoredImportPath(parent *Package, path string) (found string, searched []string) { + if parent == nil || parent.Root == "" || !go15VendorExperiment { + return path, nil + } + dir := filepath.Clean(parent.Dir) + root := filepath.Join(parent.Root, "src") + if !hasFilePathPrefix(dir, root) || len(dir) <= len(root) || dir[len(root)] != filepath.Separator { + fatalf("invalid vendoredImportPath: dir=%q root=%q separator=%q", dir, root, string(filepath.Separator)) + } + vpath := "vendor/" + path + for i := len(dir); i >= len(root); i-- { + if i < len(dir) && dir[i] != filepath.Separator { + continue + } + // Note: checking for the vendor directory before checking + // for the vendor/path directory helps us hit the + // isDir cache more often. It also helps us prepare a more useful + // list of places we looked, to report when an import is not found. + if !isDir(filepath.Join(dir[:i], "vendor")) { + continue + } + targ := filepath.Join(dir[:i], vpath) + if isDir(targ) { + // We started with parent's dir c:\gopath\src\foo\bar\baz\quux\xyzzy. + // We know the import path for parent's dir. + // We chopped off some number of path elements and + // added vendor\path to produce c:\gopath\src\foo\bar\baz\vendor\path. + // Now we want to know the import path for that directory. + // Construct it by chopping the same number of path elements + // (actually the same number of bytes) from parent's import path + // and then append /vendor/path. + chopped := len(dir) - i + if chopped == len(parent.ImportPath)+1 { + // We walked up from c:\gopath\src\foo\bar + // and found c:\gopath\src\vendor\path. + // We chopped \foo\bar (length 8) but the import path is "foo/bar" (length 7). + // Use "vendor/path" without any prefix. + return vpath, nil + } + return parent.ImportPath[:len(parent.ImportPath)-chopped] + "/" + vpath, nil + } + // Note the existence of a vendor directory in case path is not found anywhere. + searched = append(searched, targ) + } + return path, searched +} + // reusePackage reuses package p to satisfy the import at the top // of the import stack stk. If this use causes an import loop, // reusePackage updates p's error information to record the loop. @@ -324,11 +495,9 @@ func disallowInternal(srcDir string, p *Package, stk *importStack) *Package { // An import of a path containing the element “internal” // is disallowed if the importing code is outside the tree // rooted at the parent of the “internal” directory. - // - // ... For Go 1.4, we will implement the rule first for $GOROOT, but not $GOPATH. - // Only applies to $GOROOT. - if !p.Standard { + // There was an error loading the package; stop here. + if p.Error != nil { return p } @@ -385,6 +554,105 @@ func findInternal(path string) (index int, ok bool) { return 0, false } +// disallowVendor checks that srcDir is allowed to import p as path. +// If the import is allowed, disallowVendor returns the original package p. +// If not, it returns a new package containing just an appropriate error. +func disallowVendor(srcDir, path string, p *Package, stk *importStack) *Package { + if !go15VendorExperiment { + return p + } + + // The stack includes p.ImportPath. + // If that's the only thing on the stack, we started + // with a name given on the command line, not an + // import. Anything listed on the command line is fine. + if len(*stk) == 1 { + return p + } + + if perr := disallowVendorVisibility(srcDir, p, stk); perr != p { + return perr + } + + // Paths like x/vendor/y must be imported as y, never as x/vendor/y. + if i, ok := findVendor(path); ok { + perr := *p + perr.Error = &PackageError{ + ImportStack: stk.copy(), + Err: "must be imported as " + path[i+len("vendor/"):], + } + perr.Incomplete = true + return &perr + } + + return p +} + +// disallowVendorVisibility checks that srcDir is allowed to import p. +// The rules are the same as for /internal/ except that a path ending in /vendor +// is not subject to the rules, only subdirectories of vendor. +// This allows people to have packages and commands named vendor, +// for maximal compatibility with existing source trees. +func disallowVendorVisibility(srcDir string, p *Package, stk *importStack) *Package { + // The stack includes p.ImportPath. + // If that's the only thing on the stack, we started + // with a name given on the command line, not an + // import. Anything listed on the command line is fine. + if len(*stk) == 1 { + return p + } + + // Check for "vendor" element. + i, ok := findVendor(p.ImportPath) + if !ok { + return p + } + + // Vendor is present. + // Map import path back to directory corresponding to parent of vendor. + if i > 0 { + i-- // rewind over slash in ".../vendor" + } + truncateTo := i + len(p.Dir) - len(p.ImportPath) + if truncateTo < 0 || len(p.Dir) < truncateTo { + return p + } + parent := p.Dir[:truncateTo] + if hasPathPrefix(filepath.ToSlash(srcDir), filepath.ToSlash(parent)) { + return p + } + + // Vendor is present, and srcDir is outside parent's tree. Not allowed. + perr := *p + perr.Error = &PackageError{ + ImportStack: stk.copy(), + Err: "use of vendored package not allowed", + } + perr.Incomplete = true + return &perr +} + +// findVendor looks for the last non-terminating "vendor" path element in the given import path. +// If there isn't one, findVendor returns ok=false. +// Otherwise, findInternal returns ok=true and the index of the "vendor". +// +// Note that terminating "vendor" elements don't count: "x/vendor" is its own package, +// not the vendored copy of an import "" (the empty import path). +// This will allow people to have packages or commands named vendor. +// This may help reduce breakage, or it may just be confusing. We'll see. +func findVendor(path string) (index int, ok bool) { + // Two cases, depending on internal at start of string or not. + // The order matters: we must return the index of the final element, + // because the final one is where the effective import path starts. + switch { + case strings.Contains(path, "/vendor/"): + return strings.LastIndex(path, "/vendor/") + 1, true + case strings.HasPrefix(path, "vendor/"): + return 0, true + } + return 0, false +} + type targetDir int const ( @@ -398,17 +666,23 @@ const ( var goTools = map[string]targetDir{ "cmd/addr2line": toTool, "cmd/api": toTool, + "cmd/asm": toTool, + "cmd/compile": toTool, "cmd/cgo": toTool, + "cmd/cover": toTool, + "cmd/dist": toTool, + "cmd/doc": toTool, "cmd/fix": toTool, "cmd/link": toTool, + "cmd/newlink": toTool, "cmd/nm": toTool, "cmd/objdump": toTool, "cmd/pack": toTool, "cmd/pprof": toTool, + "cmd/trace": toTool, + "cmd/vet": toTool, "cmd/yacc": toTool, - "golang.org/x/tools/cmd/cover": toTool, "golang.org/x/tools/cmd/godoc": toBin, - "golang.org/x/tools/cmd/vet": toTool, "code.google.com/p/go.tools/cmd/cover": stalePath, "code.google.com/p/go.tools/cmd/godoc": stalePath, "code.google.com/p/go.tools/cmd/vet": stalePath, @@ -471,7 +745,15 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package return p } - if p.Name == "main" { + useBindir := p.Name == "main" + if !p.Standard { + switch buildBuildmode { + case "c-archive", "c-shared": + useBindir = false + } + } + + if useBindir { // Report an error when the old code.google.com/p/go.tools paths are used. if goTools[p.ImportPath] == stalePath { newPath := strings.Replace(p.ImportPath, "code.google.com/p/go.", "golang.org/x/", 1) @@ -493,6 +775,11 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package } else if p.build.BinDir != "" { // Install to GOBIN or bin of GOPATH entry. p.target = filepath.Join(p.build.BinDir, elem) + if !p.Goroot && strings.Contains(elem, "/") && gobin != "" { + // Do not create $GOBIN/goos_goarch/elem. + p.target = "" + p.gobinSubdir = true + } } if goTools[p.ImportPath] == toTool { // This is for 'go tool'. @@ -508,6 +795,21 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package p.target = "" } else { p.target = p.build.PkgObj + if buildLinkshared { + shlibnamefile := p.target[:len(p.target)-2] + ".shlibname" + shlib, err := ioutil.ReadFile(shlibnamefile) + if err == nil { + libname := strings.TrimSpace(string(shlib)) + if buildContext.Compiler == "gccgo" { + p.Shlib = filepath.Join(p.build.PkgTargetRoot, "shlibs", libname) + } else { + p.Shlib = filepath.Join(p.build.PkgTargetRoot, libname) + + } + } else if !os.IsNotExist(err) { + fatalf("unexpected error reading %s: %v", shlibnamefile, err) + } + } } importPaths := p.Imports @@ -521,6 +823,14 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package if len(p.CgoFiles) > 0 && (!p.Standard || !cgoSyscallExclude[p.ImportPath]) { importPaths = append(importPaths, "syscall") } + + // Currently build mode c-shared, or -linkshared, forces + // external linking mode, and external linking mode forces an + // import of runtime/cgo. + if p.Name == "main" && !p.Goroot && (buildBuildmode == "c-shared" || buildLinkshared) { + importPaths = append(importPaths, "runtime/cgo") + } + // Everything depends on runtime, except runtime and unsafe. if !p.Standard || (p.ImportPath != "runtime" && p.ImportPath != "unsafe") { importPaths = append(importPaths, "runtime") @@ -529,6 +839,10 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package if buildRace && (!p.Standard || !raceExclude[p.ImportPath]) { importPaths = append(importPaths, "runtime/race") } + // On ARM with GOARM=5, everything depends on math for the link. + if p.Name == "main" && goarch == "arm" { + importPaths = append(importPaths, "math") + } } // Build list of full paths to all Go files in the package, @@ -586,10 +900,20 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package if path == "C" { continue } - p1 := loadImport(path, p.Dir, stk, p.build.ImportPos[path]) + p1 := loadImport(path, p.Dir, p, stk, p.build.ImportPos[path], useVendor) if !reqStdPkgSrc && p1.Standard { continue } + if p1.Name == "main" { + p.Error = &PackageError{ + ImportStack: stk.copy(), + Err: fmt.Sprintf("import %q is a program, not an importable package", path), + } + pos := p.build.ImportPos[path] + if len(pos) > 0 { + p.Error.Pos = pos[0].String() + } + } if p1.local { if !p.local && p.Error == nil { p.Error = &PackageError{ @@ -601,13 +925,21 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package p.Error.Pos = pos[0].String() } } - path = p1.ImportPath - importPaths[i] = path + } + path = p1.ImportPath + importPaths[i] = path + if i < len(p.Imports) { + p.Imports[i] = path } deps[path] = p1 imports = append(imports, p1) for _, dep := range p1.deps { - deps[dep.ImportPath] = dep + // The same import path could produce an error or not, + // depending on what tries to import it. + // Prefer to record entries with errors, so we can report them. + if deps[dep.ImportPath] == nil || dep.Error != nil { + deps[dep.ImportPath] = dep + } } if p1.Incomplete { p.Incomplete = true @@ -637,12 +969,11 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package } p.Target = p.target - // Check for C code compiled with Plan 9 C compiler. - // No longer allowed except in runtime and runtime/cgo, for now. - if len(p.CFiles) > 0 && !p.usesCgo() && (!p.Standard || p.ImportPath != "runtime") { + // The gc toolchain only permits C source files with cgo. + if len(p.CFiles) > 0 && !p.usesCgo() && !p.usesSwig() && buildContext.Compiler == "gc" { p.Error = &PackageError{ ImportStack: stk.copy(), - Err: fmt.Sprintf("C source files not allowed when not using cgo: %s", strings.Join(p.CFiles, " ")), + Err: fmt.Sprintf("C source files not allowed when not using cgo or SWIG: %s", strings.Join(p.CFiles, " ")), } return p } @@ -660,6 +991,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package } } + computeBuildID(p) return p } @@ -698,13 +1030,8 @@ func packageList(roots []*Package) []*Package { // computeStale computes the Stale flag in the package dag that starts // at the named pkgs (command-line arguments). func computeStale(pkgs ...*Package) { - topRoot := map[string]bool{} - for _, p := range pkgs { - topRoot[p.Root] = true - } - for _, p := range packageList(pkgs) { - p.Stale = isStale(p, topRoot) + p.Stale = isStale(p) } } @@ -714,8 +1041,269 @@ func computeStale(pkgs ...*Package) { // inspecting the version. var isGoRelease = strings.HasPrefix(runtime.Version(), "go1") +// isStale and computeBuildID +// +// Theory of Operation +// +// There is an installed copy of the package (or binary). +// Can we reuse the installed copy, or do we need to build a new one? +// +// We can use the installed copy if it matches what we'd get +// by building a new one. The hard part is predicting that without +// actually running a build. +// +// To start, we must know the set of inputs to the build process that can +// affect the generated output. At a minimum, that includes the source +// files for the package and also any compiled packages imported by those +// source files. The *Package has these, and we use them. One might also +// argue for including in the input set: the build tags, whether the race +// detector is in use, the target operating system and architecture, the +// compiler and linker binaries being used, the additional flags being +// passed to those, the cgo binary being used, the additional flags cgo +// passes to the host C compiler, the host C compiler being used, the set +// of host C include files and installed C libraries, and so on. +// We include some but not all of this information. +// +// Once we have decided on a set of inputs, we must next decide how to +// tell whether the content of that set has changed since the last build +// of p. If there have been no changes, then we assume a new build would +// produce the same result and reuse the installed package or binary. +// But if there have been changes, then we assume a new build might not +// produce the same result, so we rebuild. +// +// There are two common ways to decide whether the content of the set has +// changed: modification times and content hashes. We use a mixture of both. +// +// The use of modification times (mtimes) was pioneered by make: +// assuming that a file's mtime is an accurate record of when that file was last written, +// and assuming that the modification time of an installed package or +// binary is the time that it was built, if the mtimes of the inputs +// predate the mtime of the installed object, then the build of that +// object saw those versions of the files, and therefore a rebuild using +// those same versions would produce the same object. In contrast, if any +// mtime of an input is newer than the mtime of the installed object, a +// change has occurred since the build, and the build should be redone. +// +// Modification times are attractive because the logic is easy to +// understand and the file system maintains the mtimes automatically +// (less work for us). Unfortunately, there are a variety of ways in +// which the mtime approach fails to detect a change and reuses a stale +// object file incorrectly. (Making the opposite mistake, rebuilding +// unnecessarily, is only a performance problem and not a correctness +// problem, so we ignore that one.) +// +// As a warmup, one problem is that to be perfectly precise, we need to +// compare the input mtimes against the time at the beginning of the +// build, but the object file time is the time at the end of the build. +// If an input file changes after being read but before the object is +// written, the next build will see an object newer than the input and +// will incorrectly decide that the object is up to date. We make no +// attempt to detect or solve this problem. +// +// Another problem is that due to file system imprecision, an input and +// output that are actually ordered in time have the same mtime. +// This typically happens on file systems with 1-second (or, worse, +// 2-second) mtime granularity and with automated scripts that write an +// input and then immediately run a build, or vice versa. If an input and +// an output have the same mtime, the conservative behavior is to treat +// the output as out-of-date and rebuild. This can cause one or more +// spurious rebuilds, but only for 1 second, until the object finally has +// an mtime later than the input. +// +// Another problem is that binary distributions often set the mtime on +// all files to the same time. If the distribution includes both inputs +// and cached build outputs, the conservative solution to the previous +// problem will cause unnecessary rebuilds. Worse, in such a binary +// distribution, those rebuilds might not even have permission to update +// the cached build output. To avoid these write errors, if an input and +// output have the same mtime, we assume the output is up-to-date. +// This is the opposite of what the previous problem would have us do, +// but binary distributions are more common than instances of the +// previous problem. +// +// A variant of the last problem is that some binary distributions do not +// set the mtime on all files to the same time. Instead they let the file +// system record mtimes as the distribution is unpacked. If the outputs +// are unpacked before the inputs, they'll be older and a build will try +// to rebuild them. That rebuild might hit the same write errors as in +// the last scenario. We don't make any attempt to solve this, and we +// haven't had many reports of it. Perhaps the only time this happens is +// when people manually unpack the distribution, and most of the time +// that's done as the same user who will be using it, so an initial +// rebuild on first use succeeds quietly. +// +// More generally, people and programs change mtimes on files. The last +// few problems were specific examples of this, but it's a general problem. +// For example, instead of a binary distribution, copying a home +// directory from one directory or machine to another might copy files +// but not preserve mtimes. If the inputs are new than the outputs on the +// first machine but copied first, they end up older than the outputs on +// the second machine. +// +// Because many other build systems have the same sensitivity to mtimes, +// most programs manipulating source code take pains not to break the +// mtime assumptions. For example, Git does not set the mtime of files +// during a checkout operation, even when checking out an old version of +// the code. This decision was made specifically to work well with +// mtime-based build systems. +// +// The killer problem, though, for mtime-based build systems is that the +// build only has access to the mtimes of the inputs that still exist. +// If it is possible to remove an input without changing any other inputs, +// a later build will think the object is up-to-date when it is not. +// This happens for Go because a package is made up of all source +// files in a directory. If a source file is removed, there is no newer +// mtime available recording that fact. The mtime on the directory could +// be used, but it also changes when unrelated files are added to or +// removed from the directory, so including the directory mtime would +// cause unnecessary rebuilds, possibly many. It would also exacerbate +// the problems mentioned earlier, since even programs that are careful +// to maintain mtimes on files rarely maintain mtimes on directories. +// +// A variant of the last problem is when the inputs change for other +// reasons. For example, Go 1.4 and Go 1.5 both install $GOPATH/src/mypkg +// into the same target, $GOPATH/pkg/$GOOS_$GOARCH/mypkg.a. +// If Go 1.4 has built mypkg into mypkg.a, a build using Go 1.5 must +// rebuild mypkg.a, but from mtimes alone mypkg.a looks up-to-date. +// If Go 1.5 has just been installed, perhaps the compiler will have a +// newer mtime; since the compiler is considered an input, that would +// trigger a rebuild. But only once, and only the last Go 1.4 build of +// mypkg.a happened before Go 1.5 was installed. If a user has the two +// versions installed in different locations and flips back and forth, +// mtimes alone cannot tell what to do. Changing the toolchain is +// changing the set of inputs, without affecting any mtimes. +// +// To detect the set of inputs changing, we turn away from mtimes and to +// an explicit data comparison. Specifically, we build a list of the +// inputs to the build, compute its SHA1 hash, and record that as the +// ``build ID'' in the generated object. At the next build, we can +// recompute the buid ID and compare it to the one in the generated +// object. If they differ, the list of inputs has changed, so the object +// is out of date and must be rebuilt. +// +// Because this build ID is computed before the build begins, the +// comparison does not have the race that mtime comparison does. +// +// Making the build sensitive to changes in other state is +// straightforward: include the state in the build ID hash, and if it +// changes, so does the build ID, triggering a rebuild. +// +// To detect changes in toolchain, we include the toolchain version in +// the build ID hash for package runtime, and then we include the build +// IDs of all imported packages in the build ID for p. +// +// It is natural to think about including build tags in the build ID, but +// the naive approach of just dumping the tags into the hash would cause +// spurious rebuilds. For example, 'go install' and 'go install -tags neverusedtag' +// produce the same binaries (assuming neverusedtag is never used). +// A more precise approach would be to include only tags that have an +// effect on the build. But the effect of a tag on the build is to +// include or exclude a file from the compilation, and that file list is +// already in the build ID hash. So the build ID is already tag-sensitive +// in a perfectly precise way. So we do NOT explicitly add build tags to +// the build ID hash. +// +// We do not include as part of the build ID the operating system, +// architecture, or whether the race detector is enabled, even though all +// three have an effect on the output, because that information is used +// to decide the install location. Binaries for linux and binaries for +// darwin are written to different directory trees; including that +// information in the build ID is unnecessary (although it would be +// harmless). +// +// TODO(rsc): Investigate the cost of putting source file content into +// the build ID hash as a replacement for the use of mtimes. Using the +// file content would avoid all the mtime problems, but it does require +// reading all the source files, something we avoid today (we read the +// beginning to find the build tags and the imports, but we stop as soon +// as we see the import block is over). If the package is stale, the compiler +// is going to read the files anyway. But if the package is up-to-date, the +// read is overhead. +// +// TODO(rsc): Investigate the complexity of making the build more +// precise about when individual results are needed. To be fully precise, +// there are two results of a compilation: the entire .a file used by the link +// and the subpiece used by later compilations (__.PKGDEF only). +// If a rebuild is needed but produces the previous __.PKGDEF, then +// no more recompilation due to the rebuilt package is needed, only +// relinking. To date, there is nothing in the Go command to express this. +// +// Special Cases +// +// When the go command makes the wrong build decision and does not +// rebuild something it should, users fall back to adding the -a flag. +// Any common use of the -a flag should be considered prima facie evidence +// that isStale is returning an incorrect false result in some important case. +// Bugs reported in the behavior of -a itself should prompt the question +// ``Why is -a being used at all? What bug does that indicate?'' +// +// There is a long history of changes to isStale to try to make -a into a +// suitable workaround for bugs in the mtime-based decisions. +// It is worth recording that history to inform (and, as much as possible, deter) future changes. +// +// (1) Before the build IDs were introduced, building with alternate tags +// would happily reuse installed objects built without those tags. +// For example, "go build -tags netgo myprog.go" would use the installed +// copy of package net, even if that copy had been built without netgo. +// (The netgo tag controls whether package net uses cgo or pure Go for +// functionality such as name resolution.) +// Using the installed non-netgo package defeats the purpose. +// +// Users worked around this with "go build -tags netgo -a myprog.go". +// +// Build IDs have made that workaround unnecessary: +// "go build -tags netgo myprog.go" +// cannot use a non-netgo copy of package net. +// +// (2) Before the build IDs were introduced, building with different toolchains, +// especially changing between toolchains, tried to reuse objects stored in +// $GOPATH/pkg, resulting in link-time errors about object file mismatches. +// +// Users worked around this with "go install -a ./...". +// +// Build IDs have made that workaround unnecessary: +// "go install ./..." will rebuild any objects it finds that were built against +// a different toolchain. +// +// (3) The common use of "go install -a ./..." led to reports of problems +// when the -a forced the rebuild of the standard library, which for some +// users was not writable. Because we didn't understand that the real +// problem was the bug -a was working around, we changed -a not to +// apply to the standard library. +// +// (4) The common use of "go build -tags netgo -a myprog.go" broke +// when we changed -a not to apply to the standard library, because +// if go build doesn't rebuild package net, it uses the non-netgo version. +// +// Users worked around this with "go build -tags netgo -installsuffix barf myprog.go". +// The -installsuffix here is making the go command look for packages +// in pkg/$GOOS_$GOARCH_barf instead of pkg/$GOOS_$GOARCH. +// Since the former presumably doesn't exist, go build decides to rebuild +// everything, including the standard library. Since go build doesn't +// install anything it builds, nothing is ever written to pkg/$GOOS_$GOARCH_barf, +// so repeated invocations continue to work. +// +// If the use of -a wasn't a red flag, the use of -installsuffix to point to +// a non-existent directory in a command that installs nothing should +// have been. +// +// (5) Now that (1) and (2) no longer need -a, we have removed the kludge +// introduced in (3): once again, -a means ``rebuild everything,'' not +// ``rebuild everything except the standard library.'' Only Go 1.4 had +// the restricted meaning. +// +// In addition to these cases trying to trigger rebuilds, there are +// special cases trying NOT to trigger rebuilds. The main one is that for +// a variety of reasons (see above), the install process for a Go release +// cannot be relied upon to set the mtimes such that the go command will +// think the standard library is up to date. So the mtime evidence is +// ignored for the standard library if we find ourselves in a release +// version of Go. Build ID-based staleness checks still apply to the +// standard library, even in release versions. This makes +// 'go build -tags netgo' work, among other things. + // isStale reports whether package p needs to be rebuilt. -func isStale(p *Package, topRoot map[string]bool) bool { +func isStale(p *Package) bool { if p.Standard && (p.ImportPath == "unsafe" || buildContext.Compiler == "gccgo") { // fake, builtin package return false @@ -734,28 +1322,68 @@ func isStale(p *Package, topRoot map[string]bool) bool { return false } - // If we are running a release copy of Go, do not rebuild the standard packages. - // They may not be writable anyway, but they are certainly not changing. - // This makes 'go build -a' skip the standard packages when using an official release. - // See issue 4106 and issue 8290. - pkgBuildA := buildA - if p.Standard && isGoRelease { - pkgBuildA = false + // If the -a flag is given, rebuild everything. + if buildA { + return true } - if pkgBuildA || p.target == "" || p.Stale { + // If there's no install target or it's already marked stale, we have to rebuild. + if p.target == "" || p.Stale { return true } // Package is stale if completely unbuilt. - var built time.Time - if fi, err := os.Stat(p.target); err == nil { - built = fi.ModTime() + fi, err := os.Stat(p.target) + if err != nil { + return true } - if built.IsZero() { + + // Package is stale if the expected build ID differs from the + // recorded build ID. This catches changes like a source file + // being removed from a package directory. See issue 3895. + // It also catches changes in build tags that affect the set of + // files being compiled. See issue 9369. + // It also catches changes in toolchain, like when flipping between + // two versions of Go compiling a single GOPATH. + // See issue 8290 and issue 10702. + targetBuildID, err := readBuildID(p) + if err == nil && targetBuildID != p.buildID { return true } + // Package is stale if a dependency is. + for _, p1 := range p.deps { + if p1.Stale { + return true + } + } + + // The checks above are content-based staleness. + // We assume they are always accurate. + // + // The checks below are mtime-based staleness. + // We hope they are accurate, but we know that they fail in the case of + // prebuilt Go installations that don't preserve the build mtimes + // (for example, if the pkg/ mtimes are before the src/ mtimes). + // See the large comment above isStale for details. + + // If we are running a release copy of Go and didn't find a content-based + // reason to rebuild the standard packages, do not rebuild them. + // They may not be writable anyway, but they are certainly not changing. + // This makes 'go build' skip the standard packages when + // using an official release, even when the mtimes have been changed. + // See issue 3036, issue 3149, issue 4106, issue 8290. + // (If a change to a release tree must be made by hand, the way to force the + // install is to run make.bash, which will remove the old package archives + // before rebuilding.) + if p.Standard && isGoRelease { + return false + } + + // Time-based staleness. + + built := fi.ModTime() + olderThan := func(file string) bool { fi, err := os.Stat(file) return err != nil || fi.ModTime().After(built) @@ -763,7 +1391,7 @@ func isStale(p *Package, topRoot map[string]bool) bool { // Package is stale if a dependency is, or if a dependency is newer. for _, p1 := range p.deps { - if p1.Stale || p1.target != "" && olderThan(p1.target) { + if p1.target != "" && olderThan(p1.target) { return true } } @@ -775,8 +1403,12 @@ func isStale(p *Package, topRoot map[string]bool) bool { // back-dated, as some binary distributions may do, but it does handle // a very common case. // See issue 3036. - // Assume code in $GOROOT is up to date, since it may not be writeable. - // See issue 4106. + // Exclude $GOROOT, under the assumption that people working on + // the compiler may want to control when everything gets rebuilt, + // and people updating the Go repository will run make.bash or all.bash + // and get a full rebuild anyway. + // Excluding $GOROOT used to also fix issue 4106, but that's now + // taken care of above (at least when the installed Go is a released version). if p.Root != goroot { if olderThan(buildToolchain.compiler()) { return true @@ -786,19 +1418,43 @@ func isStale(p *Package, topRoot map[string]bool) bool { } } - // Have installed copy, probably built using current compilers, - // and built after its imported packages. The only reason now - // that we'd have to rebuild it is if the sources were newer than - // the package. If a package p is not in the same tree as any - // package named on the command-line, assume it is up-to-date - // no matter what the modification times on the source files indicate. - // This avoids rebuilding $GOROOT packages when people are - // working outside the Go root, and it effectively makes each tree - // listed in $GOPATH a separate compilation world. - // See issue 3149. - if p.Root != "" && !topRoot[p.Root] { - return false - } + // Note: Until Go 1.5, we had an additional shortcut here. + // We built a list of the workspace roots ($GOROOT, each $GOPATH) + // containing targets directly named on the command line, + // and if p were not in any of those, it would be treated as up-to-date + // as long as it is built. The goal was to avoid rebuilding a system-installed + // $GOROOT, unless something from $GOROOT were explicitly named + // on the command line (like go install math). + // That's now handled by the isGoRelease clause above. + // The other effect of the shortcut was to isolate different entries in + // $GOPATH from each other. This had the unfortunate effect that + // if you had (say), GOPATH listing two entries, one for commands + // and one for libraries, and you did a 'git pull' in the library one + // and then tried 'go install commands/...', it would build the new libraries + // during the first build (because they wouldn't have been installed at all) + // but then subsequent builds would not rebuild the libraries, even if the + // mtimes indicate they are stale, because the different GOPATH entries + // were treated differently. This behavior was confusing when using + // non-trivial GOPATHs, which were particularly common with some + // code management conventions, like the original godep. + // Since the $GOROOT case (the original motivation) is handled separately, + // we no longer put a barrier between the different $GOPATH entries. + // + // One implication of this is that if there is a system directory for + // non-standard Go packages that is included in $GOPATH, the mtimes + // on those compiled packages must be no earlier than the mtimes + // on the source files. Since most distributions use the same mtime + // for all files in a tree, they will be unaffected. People using plain + // tar x to extract system-installed packages will need to adjust mtimes, + // but it's better to force them to get the mtimes right than to ignore + // the mtimes and thereby do the wrong thing in common use cases. + // + // So there is no GOPATH vs GOPATH shortcut here anymore. + // + // If something needs to come back here, we could try writing a dummy + // file with a random name to the $GOPATH/pkg directory (and removing it) + // to test for write access, and then skip GOPATH roots we don't have write + // access to. But hopefully we can just use the mtimes always. srcs := stringList(p.GoFiles, p.CFiles, p.CXXFiles, p.MFiles, p.HFiles, p.SFiles, p.CgoFiles, p.SysoFiles, p.SwigFiles, p.SwigCXXFiles) for _, src := range srcs { @@ -810,6 +1466,53 @@ func isStale(p *Package, topRoot map[string]bool) bool { return false } +// computeBuildID computes the build ID for p, leaving it in p.buildID. +// Build ID is a hash of the information we want to detect changes in. +// See the long comment in isStale for details. +func computeBuildID(p *Package) { + h := sha1.New() + + // Include the list of files compiled as part of the package. + // This lets us detect removed files. See issue 3895. + inputFiles := stringList( + p.GoFiles, + p.CgoFiles, + p.CFiles, + p.CXXFiles, + p.MFiles, + p.HFiles, + p.SFiles, + p.SysoFiles, + p.SwigFiles, + p.SwigCXXFiles, + ) + for _, file := range inputFiles { + fmt.Fprintf(h, "file %s\n", file) + } + + // Include the content of runtime/zversion.go in the hash + // for package runtime. This will give package runtime a + // different build ID in each Go release. + if p.Standard && p.ImportPath == "runtime" { + data, _ := ioutil.ReadFile(filepath.Join(p.Dir, "zversion.go")) + fmt.Fprintf(h, "zversion %q\n", string(data)) + } + + // Include the build IDs of any dependencies in the hash. + // This, combined with the runtime/zversion content, + // will cause packages to have different build IDs when + // compiled with different Go releases. + // This helps the go command know to recompile when + // people use the same GOPATH but switch between + // different Go releases. See issue 10702. + // This is also a better fix for issue 8290. + for _, p1 := range p.deps { + fmt.Fprintf(h, "dep %s %s\n", p1.ImportPath, p1.buildID) + } + + p.buildID = fmt.Sprintf("%x", h.Sum(nil)) +} + var cwd, _ = os.Getwd() var cmdCache = map[string]*Package{} @@ -872,7 +1575,7 @@ func loadPackage(arg string, stk *importStack) *Package { } } - return loadImport(arg, cwd, stk, nil) + return loadImport(arg, cwd, nil, stk, nil, 0) } // packages returns the packages named by the @@ -942,6 +1645,23 @@ func packagesForBuild(args []string) []*Package { } } exitIfErrors() + + // Check for duplicate loads of the same package. + // That should be impossible, but if it does happen then + // we end up trying to build the same package twice, + // usually in parallel overwriting the same files, + // which doesn't work very well. + seen := map[string]bool{} + reported := map[string]bool{} + for _, pkg := range packageList(pkgs) { + if seen[pkg.ImportPath] && !reported[pkg.ImportPath] { + reported[pkg.ImportPath] = true + errorf("internal error: duplicate loads of %s", pkg.ImportPath) + } + seen[pkg.ImportPath] = true + } + exitIfErrors() + return pkgs } @@ -967,3 +1687,170 @@ func hasSubdir(root, dir string) (rel string, ok bool) { } return filepath.ToSlash(dir[len(root):]), true } + +var ( + errBuildIDToolchain = fmt.Errorf("build ID only supported in gc toolchain") + errBuildIDMalformed = fmt.Errorf("malformed object file") + errBuildIDUnknown = fmt.Errorf("lost build ID") +) + +var ( + bangArch = []byte("!") + pkgdef = []byte("__.PKGDEF") + goobject = []byte("go object ") + buildid = []byte("build id ") +) + +// readBuildID reads the build ID from an archive or binary. +// It only supports the gc toolchain. +// Other toolchain maintainers should adjust this function. +func readBuildID(p *Package) (id string, err error) { + if buildToolchain != (gcToolchain{}) { + return "", errBuildIDToolchain + } + + // For commands, read build ID directly from binary. + if p.Name == "main" { + return ReadBuildIDFromBinary(p.Target) + } + + // Otherwise, we expect to have an archive (.a) file, + // and we can read the build ID from the Go export data. + if !strings.HasSuffix(p.Target, ".a") { + return "", &os.PathError{Op: "parse", Path: p.Target, Err: errBuildIDUnknown} + } + + // Read just enough of the target to fetch the build ID. + // The archive is expected to look like: + // + // ! + // __.PKGDEF 0 0 0 644 7955 ` + // go object darwin amd64 devel X:none + // build id "b41e5c45250e25c9fd5e9f9a1de7857ea0d41224" + // + // The variable-sized strings are GOOS, GOARCH, and the experiment list (X:none). + // Reading the first 1024 bytes should be plenty. + f, err := os.Open(p.Target) + if err != nil { + return "", err + } + data := make([]byte, 1024) + n, err := io.ReadFull(f, data) + f.Close() + + if err != nil && n == 0 { + return "", err + } + + bad := func() (string, error) { + return "", &os.PathError{Op: "parse", Path: p.Target, Err: errBuildIDMalformed} + } + + // Archive header. + for i := 0; ; i++ { // returns during i==3 + j := bytes.IndexByte(data, '\n') + if j < 0 { + return bad() + } + line := data[:j] + data = data[j+1:] + switch i { + case 0: + if !bytes.Equal(line, bangArch) { + return bad() + } + case 1: + if !bytes.HasPrefix(line, pkgdef) { + return bad() + } + case 2: + if !bytes.HasPrefix(line, goobject) { + return bad() + } + case 3: + if !bytes.HasPrefix(line, buildid) { + // Found the object header, just doesn't have a build id line. + // Treat as successful, with empty build id. + return "", nil + } + id, err := strconv.Unquote(string(line[len(buildid):])) + if err != nil { + return bad() + } + return id, nil + } + } +} + +var ( + goBuildPrefix = []byte("\xff Go build ID: \"") + goBuildEnd = []byte("\"\n \xff") + + elfPrefix = []byte("\x7fELF") +) + +// ReadBuildIDFromBinary reads the build ID from a binary. +// +// ELF binaries store the build ID in a proper PT_NOTE section. +// +// Other binary formats are not so flexible. For those, the linker +// stores the build ID as non-instruction bytes at the very beginning +// of the text segment, which should appear near the beginning +// of the file. This is clumsy but fairly portable. Custom locations +// can be added for other binary types as needed, like we did for ELF. +func ReadBuildIDFromBinary(filename string) (id string, err error) { + if filename == "" { + return "", &os.PathError{Op: "parse", Path: filename, Err: errBuildIDUnknown} + } + + // Read the first 16 kB of the binary file. + // That should be enough to find the build ID. + // In ELF files, the build ID is in the leading headers, + // which are typically less than 4 kB, not to mention 16 kB. + // On other systems, we're trying to read enough that + // we get the beginning of the text segment in the read. + // The offset where the text segment begins in a hello + // world compiled for each different object format today: + // + // Plan 9: 0x20 + // Windows: 0x600 + // Mach-O: 0x2000 + // + f, err := os.Open(filename) + if err != nil { + return "", err + } + defer f.Close() + + data := make([]byte, 16*1024) + _, err = io.ReadFull(f, data) + if err == io.ErrUnexpectedEOF { + err = nil + } + if err != nil { + return "", err + } + + if bytes.HasPrefix(data, elfPrefix) { + return readELFGoBuildID(filename, f, data) + } + + i := bytes.Index(data, goBuildPrefix) + if i < 0 { + // Missing. Treat as successful but build ID empty. + return "", nil + } + + j := bytes.Index(data[i+len(goBuildPrefix):], goBuildEnd) + if j < 0 { + return "", &os.PathError{Op: "parse", Path: filename, Err: errBuildIDMalformed} + } + + quoted := data[i+len(goBuildPrefix)-1 : i+len(goBuildPrefix)+j+1] + id, err = strconv.Unquote(string(quoted)) + if err != nil { + return "", &os.PathError{Op: "parse", Path: filename, Err: errBuildIDMalformed} + } + + return id, nil +} diff --git a/libgo/go/cmd/go/run.go b/libgo/go/cmd/go/run.go index ef8aa95a351..f6da373e252 100644 --- a/libgo/go/cmd/go/run.go +++ b/libgo/go/cmd/go/run.go @@ -37,7 +37,8 @@ Run compiles and runs the main package comprising the named Go source files. A Go source file is defined to be a file ending in a literal ".go" suffix. By default, 'go run' runs the compiled binary directly: 'a.out arguments...'. -If the -exec flag is given, 'go run' invokes the binary using xprog: 'xprog a.out arguments...'. +If the -exec flag is given, 'go run' invokes the binary using xprog: + 'xprog a.out arguments...'. If the -exec flag is not given, GOOS or GOARCH is different from the system default, and a program named go_$GOOS_$GOARCH_exec can be found on the current search path, 'go run' invokes the binary using that program, @@ -64,6 +65,7 @@ func printStderr(args ...interface{}) (int, error) { func runRun(cmd *Command, args []string) { raceInit() + buildModeInit() var b builder b.init() b.print = printStderr @@ -136,6 +138,7 @@ func runStdin(cmdline []string) { cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr + cmd.Env = origEnv startSigHandlers() if err := cmd.Run(); err != nil { errorf("%v", err) diff --git a/libgo/go/cmd/go/test.go b/libgo/go/cmd/go/test.go index 5cf7aaf0716..aadfdf67cce 100644 --- a/libgo/go/cmd/go/test.go +++ b/libgo/go/cmd/go/test.go @@ -33,9 +33,11 @@ func init() { cmdTest.Run = runTest } +const testUsage = "test [-c] [-i] [build and test flags] [packages] [flags for test binary]" + var cmdTest = &Command{ CustomFlags: true, - UsageLine: "test [-c] [-i] [build and test flags] [packages] [flags for test binary]", + UsageLine: testUsage, Short: "test packages", Long: ` 'Go test' automates testing the packages named by the import paths. @@ -64,6 +66,21 @@ with source in the current directory, including tests, and runs the tests. The package is built in a temporary directory so it does not interfere with the non-test installation. +` + strings.TrimSpace(testFlag1) + ` See 'go help testflag' for details. + +If the test binary needs any other flags, they should be presented after the +package names. The go tool treats as a flag the first argument that begins with +a minus sign that it does not recognize itself; that argument and all subsequent +arguments are passed as arguments to the test binary. + +For more about build flags, see 'go help build'. +For more about specifying packages, see 'go help packages'. + +See also: go build, go vet. +`, +} + +const testFlag1 = ` In addition to the build flags, the flags handled by 'go test' itself are: -c @@ -83,21 +100,9 @@ In addition to the build flags, the flags handled by 'go test' itself are: Compile the test binary to the named file. The test still runs (unless -c or -i is specified). - The test binary also accepts flags that control execution of the test; these -flags are also accessible by 'go test'. See 'go help testflag' for details. - -If the test binary needs any other flags, they should be presented after the -package names. The go tool treats as a flag the first argument that begins with -a minus sign that it does not recognize itself; that argument and all subsequent -arguments are passed as arguments to the test binary. - -For more about build flags, see 'go help build'. -For more about specifying packages, see 'go help packages'. - -See also: go build, go vet. -`, -} +flags are also accessible by 'go test'. +` var helpTestflag = &Command{ UsageLine: "testflag", @@ -107,13 +112,18 @@ The 'go test' command takes both flags that apply to 'go test' itself and flags that apply to the resulting test binary. Several of the flags control profiling and write an execution profile -suitable for "go tool pprof"; run "go tool pprof help" for more +suitable for "go tool pprof"; run "go tool pprof -h" for more information. The --alloc_space, --alloc_objects, and --show_bytes options of pprof control how the information is presented. The following flags are recognized by the 'go test' command and control the execution of any test: + ` + strings.TrimSpace(testFlag2) + ` +`, +} + +const testFlag2 = ` -bench regexp Run benchmarks matching the regular expression. By default, no benchmarks run. To run all benchmarks, @@ -135,12 +145,17 @@ control the execution of any test: -blockprofilerate n Control the detail provided in goroutine blocking profiles by calling runtime.SetBlockProfileRate with n. - See 'godoc runtime SetBlockProfileRate'. + See 'go doc runtime.SetBlockProfileRate'. The profiler aims to sample, on average, one blocking event every n nanoseconds the program spends blocked. By default, if -test.blockprofile is set without this flag, all blocking events are recorded, equivalent to -test.blockprofilerate=1. + -count n + Run each test and benchmark n times (default 1). + If -cpu is set, run n times for each GOMAXPROCS value. + Examples are always run once. + -cover Enable coverage analysis. @@ -180,7 +195,7 @@ control the execution of any test: -memprofilerate n Enable more precise (and expensive) memory profiles by setting - runtime.MemProfileRate. See 'godoc runtime MemProfileRate'. + runtime.MemProfileRate. See 'go doc runtime.MemProfileRate'. To profile all memory allocations, use -test.memprofilerate=1 and pass --alloc_space flag to the pprof tool. @@ -205,6 +220,11 @@ control the execution of any test: -timeout t If a test runs longer than t, panic. + The default is 10 minutes (10m). + + -trace trace.out + Write an execution trace to the specified file before exiting. + Writes test binary as -c would. -v Verbose output: log all tests as they are run. Also print all @@ -229,8 +249,7 @@ The test flags that generate profiles (other than for coverage) also leave the test binary in pkg.test for use when analyzing the profiles. Flags not recognized by 'go test' must be placed after any specified packages. -`, -} +` var helpTestfunc = &Command{ UsageLine: "testfunc", @@ -310,6 +329,7 @@ func runTest(cmd *Command, args []string) { findExecCmd() // initialize cached result raceInit() + buildModeInit() pkgs := packagesForBuild(pkgArgs) if len(pkgs) == 0 { fatalf("no packages to test") @@ -342,11 +362,11 @@ func runTest(cmd *Command, args []string) { // been given on the command line (implicit current directory) // or when benchmarking. // Also stream if we're showing output anyway with a - // single package under test. In that case, streaming the - // output produces the same result as not streaming, - // just more immediately. + // single package under test or if parallelism is set to 1. + // In these cases, streaming the output produces the same result + // as not streaming, just more immediately. testStreamOutput = len(pkgArgs) == 0 || testBench || - (len(pkgs) <= 1 && testShowPass) + (testShowPass && (len(pkgs) == 1 || buildP == 1)) var b builder b.init() @@ -364,10 +384,10 @@ func runTest(cmd *Command, args []string) { for _, path := range p.Imports { deps[path] = true } - for _, path := range p.TestImports { + for _, path := range p.vendored(p.TestImports) { deps[path] = true } - for _, path := range p.XTestImports { + for _, path := range p.vendored(p.XTestImports) { deps[path] = true } } @@ -376,7 +396,7 @@ func runTest(cmd *Command, args []string) { if deps["C"] { delete(deps, "C") deps["runtime/cgo"] = true - if buildContext.GOOS == runtime.GOOS && buildContext.GOARCH == runtime.GOARCH { + if goos == runtime.GOOS && goarch == runtime.GOARCH && !buildRace { deps["cmd/cgo"] = true } } @@ -428,6 +448,10 @@ func runTest(cmd *Command, args []string) { // Mark all the coverage packages for rebuilding with coverage. for _, p := range testCoverPkgs { + // There is nothing to cover in package unsafe; it comes from the compiler. + if p.ImportPath == "unsafe" { + continue + } p.Stale = true // rebuild p.fake = true // do not warn about rebuild p.coverMode = testCoverMode @@ -562,15 +586,20 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, var imports, ximports []*Package var stk importStack stk.push(p.ImportPath + " (test)") - for _, path := range p.TestImports { - p1 := loadImport(path, p.Dir, &stk, p.build.TestImportPos[path]) + for i, path := range p.TestImports { + p1 := loadImport(path, p.Dir, p, &stk, p.build.TestImportPos[path], useVendor) if !reqStdPkgSrc && p1.Standard { continue } if p1.Error != nil { return nil, nil, nil, p1.Error } - if contains(p1.Deps, p.ImportPath) { + if len(p1.DepsErrors) > 0 { + err := p1.DepsErrors[0] + err.Pos = "" // show full import stack + return nil, nil, nil, err + } + if contains(p1.Deps, p.ImportPath) || p1.ImportPath == p.ImportPath { // Same error that loadPackage returns (via reusePackage) in pkg.go. // Can't change that code, because that code is only for loading the // non-test copy of a package. @@ -581,24 +610,31 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, } return nil, nil, nil, err } + p.TestImports[i] = p1.ImportPath imports = append(imports, p1) } stk.pop() stk.push(p.ImportPath + "_test") pxtestNeedsPtest := false - for _, path := range p.XTestImports { - if path == p.ImportPath { - pxtestNeedsPtest = true - continue - } - p1 := loadImport(path, p.Dir, &stk, p.build.XTestImportPos[path]) + for i, path := range p.XTestImports { + p1 := loadImport(path, p.Dir, p, &stk, p.build.XTestImportPos[path], useVendor) if !reqStdPkgSrc && p1.Standard { continue } if p1.Error != nil { return nil, nil, nil, p1.Error } - ximports = append(ximports, p1) + if len(p1.DepsErrors) > 0 { + err := p1.DepsErrors[0] + err.Pos = "" // show full import stack + return nil, nil, nil, err + } + if p1.ImportPath == p.ImportPath { + pxtestNeedsPtest = true + } else { + ximports = append(ximports, p1) + } + p.XTestImports[i] = p1.ImportPath } stk.pop() @@ -723,7 +759,7 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, if dep == ptest.ImportPath { pmain.imports = append(pmain.imports, ptest) } else { - p1 := loadImport(dep, "", &stk, nil) + p1 := loadImport(dep, "", nil, &stk, nil, 0) if !reqStdPkgSrc && p1.Standard { continue } @@ -781,6 +817,12 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action, recompileForTest(pmain, p, ptest, testDir) } + if buildContext.GOOS == "darwin" { + if buildContext.GOARCH == "arm" || buildContext.GOARCH == "arm64" { + t.NeedCgo = true + } + } + for _, cp := range pmain.imports { if len(cp.coverVars) > 0 { t.Cover = append(t.Cover, coverInfo{cp, cp.coverVars}) @@ -997,7 +1039,7 @@ func (b *builder) runTest(a *action) error { cmd := exec.Command(args[0], args[1:]...) cmd.Dir = a.p.Dir - cmd.Env = envForDir(cmd.Dir) + cmd.Env = envForDir(cmd.Dir, origEnv) var buf bytes.Buffer if testStreamOutput { cmd.Stdout = os.Stdout @@ -1216,6 +1258,7 @@ type testFuncs struct { NeedTest bool ImportXtest bool NeedXtest bool + NeedCgo bool Cover []coverInfo } @@ -1319,6 +1362,10 @@ import ( {{range $i, $p := .Cover}} _cover{{$i}} {{$p.Package.ImportPath | printf "%q"}} {{end}} + +{{if .NeedCgo}} + _ "runtime/cgo" +{{end}} ) var tests = []testing.InternalTest{ diff --git a/libgo/go/cmd/go/testdata/generate/test3.go b/libgo/go/cmd/go/testdata/generate/test3.go index 41ffb7ea87f..3d6a8a5c742 100644 --- a/libgo/go/cmd/go/testdata/generate/test3.go +++ b/libgo/go/cmd/go/testdata/generate/test3.go @@ -4,6 +4,6 @@ // Test go generate variable substitution. -//go:generate echo $GOARCH $GOFILE $GOPACKAGE xyz$GOPACKAGE/$GOFILE/123 +//go:generate echo $GOARCH $GOFILE:$GOLINE ${GOPACKAGE}abc xyz$GOPACKAGE/$GOFILE/123 package p diff --git a/libgo/go/cmd/go/testdata/generate/test4.go b/libgo/go/cmd/go/testdata/generate/test4.go new file mode 100644 index 00000000000..a7631c4a456 --- /dev/null +++ b/libgo/go/cmd/go/testdata/generate/test4.go @@ -0,0 +1,10 @@ +// Copyright 2015 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 -run flag + +//go:generate echo oh yes my man +//go:generate echo no, no, a thousand times no + +package p diff --git a/libgo/go/cmd/go/testdata/rundir/sub/sub.go b/libgo/go/cmd/go/testdata/rundir/sub/sub.go new file mode 100644 index 00000000000..06ab7d0f9a3 --- /dev/null +++ b/libgo/go/cmd/go/testdata/rundir/sub/sub.go @@ -0,0 +1 @@ +package main diff --git a/libgo/go/cmd/go/testdata/rundir/x.go b/libgo/go/cmd/go/testdata/rundir/x.go new file mode 100644 index 00000000000..06ab7d0f9a3 --- /dev/null +++ b/libgo/go/cmd/go/testdata/rundir/x.go @@ -0,0 +1 @@ +package main diff --git a/libgo/go/cmd/go/testdata/src/testcycle/q1/q1.go b/libgo/go/cmd/go/testdata/src/testcycle/q1/q1.go new file mode 100644 index 00000000000..7a471f0cc05 --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/testcycle/q1/q1.go @@ -0,0 +1 @@ +package q1 diff --git a/libgo/go/cmd/go/testdata/src/testcycle/q1/q1_test.go b/libgo/go/cmd/go/testdata/src/testcycle/q1/q1_test.go new file mode 100644 index 00000000000..ca81bd2bf80 --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/testcycle/q1/q1_test.go @@ -0,0 +1,6 @@ +package q1 + +import "testing" +import _ "testcycle/q1" + +func Test(t *testing.T) {} diff --git a/libgo/go/cmd/go/testdata/src/testdep/p1/p1.go b/libgo/go/cmd/go/testdata/src/testdep/p1/p1.go new file mode 100644 index 00000000000..a457035a430 --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/testdep/p1/p1.go @@ -0,0 +1 @@ +package p1 diff --git a/libgo/go/cmd/go/testdata/src/testdep/p1/p1_test.go b/libgo/go/cmd/go/testdata/src/testdep/p1/p1_test.go new file mode 100644 index 00000000000..8be75334425 --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/testdep/p1/p1_test.go @@ -0,0 +1,3 @@ +package p1 + +import _ "testdep/p2" diff --git a/libgo/go/cmd/go/testdata/src/testdep/p2/p2.go b/libgo/go/cmd/go/testdata/src/testdep/p2/p2.go new file mode 100644 index 00000000000..15ba2eacea5 --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/testdep/p2/p2.go @@ -0,0 +1,3 @@ +package p2 + +import _ "testdep/p3" diff --git a/libgo/go/cmd/go/testdata/src/testdep/p3/p3.go b/libgo/go/cmd/go/testdata/src/testdep/p3/p3.go new file mode 100644 index 00000000000..0219e7fae50 --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/testdep/p3/p3.go @@ -0,0 +1,3 @@ +// +build ignore + +package ignored diff --git a/libgo/go/cmd/go/testdata/src/vend/bad.go b/libgo/go/cmd/go/testdata/src/vend/bad.go new file mode 100644 index 00000000000..57cc595220c --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/vend/bad.go @@ -0,0 +1,3 @@ +package vend + +import _ "r" diff --git a/libgo/go/cmd/go/testdata/src/vend/good.go b/libgo/go/cmd/go/testdata/src/vend/good.go new file mode 100644 index 00000000000..952ada3108d --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/vend/good.go @@ -0,0 +1,3 @@ +package vend + +import _ "p" diff --git a/libgo/go/cmd/go/testdata/src/vend/hello/hello.go b/libgo/go/cmd/go/testdata/src/vend/hello/hello.go new file mode 100644 index 00000000000..41dc03e0ce4 --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/vend/hello/hello.go @@ -0,0 +1,10 @@ +package main + +import ( + "fmt" + "strings" // really ../vendor/strings +) + +func main() { + fmt.Printf("%s\n", strings.Msg) +} diff --git a/libgo/go/cmd/go/testdata/src/vend/hello/hello_test.go b/libgo/go/cmd/go/testdata/src/vend/hello/hello_test.go new file mode 100644 index 00000000000..5e72ada9387 --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/vend/hello/hello_test.go @@ -0,0 +1,12 @@ +package main + +import ( + "strings" // really ../vendor/strings + "testing" +) + +func TestMsgInternal(t *testing.T) { + if strings.Msg != "hello, world" { + t.Fatal("unexpected msg: %v", strings.Msg) + } +} diff --git a/libgo/go/cmd/go/testdata/src/vend/hello/hellox_test.go b/libgo/go/cmd/go/testdata/src/vend/hello/hellox_test.go new file mode 100644 index 00000000000..96e6049dad0 --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/vend/hello/hellox_test.go @@ -0,0 +1,12 @@ +package main_test + +import ( + "strings" // really ../vendor/strings + "testing" +) + +func TestMsgExternal(t *testing.T) { + if strings.Msg != "hello, world" { + t.Fatal("unexpected msg: %v", strings.Msg) + } +} diff --git a/libgo/go/cmd/go/testdata/src/vend/subdir/bad.go b/libgo/go/cmd/go/testdata/src/vend/subdir/bad.go new file mode 100644 index 00000000000..d0ddaacfea5 --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/vend/subdir/bad.go @@ -0,0 +1,3 @@ +package subdir + +import _ "r" diff --git a/libgo/go/cmd/go/testdata/src/vend/subdir/good.go b/libgo/go/cmd/go/testdata/src/vend/subdir/good.go new file mode 100644 index 00000000000..edd04543a2b --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/vend/subdir/good.go @@ -0,0 +1,3 @@ +package subdir + +import _ "p" diff --git a/libgo/go/cmd/go/testdata/src/vend/vendor/p/p.go b/libgo/go/cmd/go/testdata/src/vend/vendor/p/p.go new file mode 100644 index 00000000000..c89cd18d0fe --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/vend/vendor/p/p.go @@ -0,0 +1 @@ +package p diff --git a/libgo/go/cmd/go/testdata/src/vend/vendor/q/q.go b/libgo/go/cmd/go/testdata/src/vend/vendor/q/q.go new file mode 100644 index 00000000000..946e6d99109 --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/vend/vendor/q/q.go @@ -0,0 +1 @@ +package q diff --git a/libgo/go/cmd/go/testdata/src/vend/vendor/strings/msg.go b/libgo/go/cmd/go/testdata/src/vend/vendor/strings/msg.go new file mode 100644 index 00000000000..438126ba2be --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/vend/vendor/strings/msg.go @@ -0,0 +1,3 @@ +package strings + +var Msg = "hello, world" diff --git a/libgo/go/cmd/go/testdata/src/vend/x/invalid/invalid.go b/libgo/go/cmd/go/testdata/src/vend/x/invalid/invalid.go new file mode 100644 index 00000000000..e250d5bb31b --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/vend/x/invalid/invalid.go @@ -0,0 +1,3 @@ +package invalid + +import "vend/x/invalid/vendor/foo" diff --git a/libgo/go/cmd/go/testdata/src/vend/x/vendor/p/p.go b/libgo/go/cmd/go/testdata/src/vend/x/vendor/p/p.go new file mode 100644 index 00000000000..c89cd18d0fe --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/vend/x/vendor/p/p.go @@ -0,0 +1 @@ +package p diff --git a/libgo/go/cmd/go/testdata/src/vend/x/vendor/p/p/p.go b/libgo/go/cmd/go/testdata/src/vend/x/vendor/p/p/p.go new file mode 100644 index 00000000000..e12e12c2f4c --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/vend/x/vendor/p/p/p.go @@ -0,0 +1,3 @@ +package p + +import _ "notfound" diff --git a/libgo/go/cmd/go/testdata/src/vend/x/vendor/r/r.go b/libgo/go/cmd/go/testdata/src/vend/x/vendor/r/r.go new file mode 100644 index 00000000000..838c177a570 --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/vend/x/vendor/r/r.go @@ -0,0 +1 @@ +package r diff --git a/libgo/go/cmd/go/testdata/src/vend/x/x.go b/libgo/go/cmd/go/testdata/src/vend/x/x.go new file mode 100644 index 00000000000..ae526ebdda2 --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/vend/x/x.go @@ -0,0 +1,5 @@ +package x + +import _ "p" +import _ "q" +import _ "r" diff --git a/libgo/go/cmd/go/testdata/src/vetpkg/c.go b/libgo/go/cmd/go/testdata/src/vetpkg/c.go new file mode 100644 index 00000000000..ef5648f0590 --- /dev/null +++ b/libgo/go/cmd/go/testdata/src/vetpkg/c.go @@ -0,0 +1,9 @@ +// +build tagtest + +package p + +import "fmt" + +func g() { + fmt.Printf("%d", 3, 4) +} diff --git a/libgo/go/cmd/go/testdata/testinternal3/t.go b/libgo/go/cmd/go/testdata/testinternal3/t.go new file mode 100644 index 00000000000..8576a4b4d76 --- /dev/null +++ b/libgo/go/cmd/go/testdata/testinternal3/t.go @@ -0,0 +1,3 @@ +package t + +import _ "internal/does-not-exist" diff --git a/libgo/go/cmd/go/testdata/testinternal4/src/p/p.go b/libgo/go/cmd/go/testdata/testinternal4/src/p/p.go new file mode 100644 index 00000000000..6bdee27be2f --- /dev/null +++ b/libgo/go/cmd/go/testdata/testinternal4/src/p/p.go @@ -0,0 +1,6 @@ +package p + +import ( + _ "q/internal/x" + _ "q/j" +) diff --git a/libgo/go/cmd/go/testdata/testinternal4/src/q/internal/x/x.go b/libgo/go/cmd/go/testdata/testinternal4/src/q/internal/x/x.go new file mode 100644 index 00000000000..823aafd0712 --- /dev/null +++ b/libgo/go/cmd/go/testdata/testinternal4/src/q/internal/x/x.go @@ -0,0 +1 @@ +package x diff --git a/libgo/go/cmd/go/testdata/testinternal4/src/q/j/j.go b/libgo/go/cmd/go/testdata/testinternal4/src/q/j/j.go new file mode 100644 index 00000000000..9f075438940 --- /dev/null +++ b/libgo/go/cmd/go/testdata/testinternal4/src/q/j/j.go @@ -0,0 +1,3 @@ +package j + +import _ "q/internal/x" diff --git a/libgo/go/cmd/go/testdata/testvendor/src/p/p.go b/libgo/go/cmd/go/testdata/testvendor/src/p/p.go new file mode 100644 index 00000000000..e740715186e --- /dev/null +++ b/libgo/go/cmd/go/testdata/testvendor/src/p/p.go @@ -0,0 +1,6 @@ +package p + +import ( + _ "q/y" + _ "q/z" +) diff --git a/libgo/go/cmd/go/testdata/testvendor/src/q/vendor/x/x.go b/libgo/go/cmd/go/testdata/testvendor/src/q/vendor/x/x.go new file mode 100644 index 00000000000..823aafd0712 --- /dev/null +++ b/libgo/go/cmd/go/testdata/testvendor/src/q/vendor/x/x.go @@ -0,0 +1 @@ +package x diff --git a/libgo/go/cmd/go/testdata/testvendor/src/q/y/y.go b/libgo/go/cmd/go/testdata/testvendor/src/q/y/y.go new file mode 100644 index 00000000000..4f842237675 --- /dev/null +++ b/libgo/go/cmd/go/testdata/testvendor/src/q/y/y.go @@ -0,0 +1,3 @@ +package y + +import _ "x" diff --git a/libgo/go/cmd/go/testdata/testvendor/src/q/z/z.go b/libgo/go/cmd/go/testdata/testvendor/src/q/z/z.go new file mode 100644 index 00000000000..a8d4924936a --- /dev/null +++ b/libgo/go/cmd/go/testdata/testvendor/src/q/z/z.go @@ -0,0 +1,3 @@ +package z + +import _ "q/vendor/x" diff --git a/libgo/go/cmd/go/testdata/testvendor2/src/p/p.go b/libgo/go/cmd/go/testdata/testvendor2/src/p/p.go new file mode 100644 index 00000000000..220b2b2a071 --- /dev/null +++ b/libgo/go/cmd/go/testdata/testvendor2/src/p/p.go @@ -0,0 +1,3 @@ +package p + +import "x" diff --git a/libgo/go/cmd/go/testdata/testvendor2/vendor/x/x.go b/libgo/go/cmd/go/testdata/testvendor2/vendor/x/x.go new file mode 100644 index 00000000000..823aafd0712 --- /dev/null +++ b/libgo/go/cmd/go/testdata/testvendor2/vendor/x/x.go @@ -0,0 +1 @@ +package x diff --git a/libgo/go/cmd/go/testflag.go b/libgo/go/cmd/go/testflag.go index 6da74b99677..1f3e3d316af 100644 --- a/libgo/go/cmd/go/testflag.go +++ b/libgo/go/cmd/go/testflag.go @@ -5,6 +5,7 @@ package main import ( + "flag" "fmt" "os" "strconv" @@ -16,46 +17,11 @@ import ( // our command line are for us, and some are for 6.out, and // some are for both. -var usageMessage = `Usage of go test: - -c=false: compile but do not run the test binary - -file=file_test.go: specify file to use for tests; - use multiple times for multiple files - -p=n: build and test up to n packages in parallel - -x=false: print command lines as they are executed - - // These flags can be passed with or without a "test." prefix: -v or -test.v. - -bench="": passes -test.bench to test - -benchmem=false: print memory allocation statistics for benchmarks - -benchtime=1s: passes -test.benchtime to test - -cover=false: enable coverage analysis - -covermode="set": specifies mode for coverage analysis - -coverpkg="": comma-separated list of packages for coverage analysis - -coverprofile="": passes -test.coverprofile to test if -cover - -cpu="": passes -test.cpu to test - -cpuprofile="": passes -test.cpuprofile to test - -memprofile="": passes -test.memprofile to test - -memprofilerate=0: passes -test.memprofilerate to test - -blockprofile="": pases -test.blockprofile to test - -blockprofilerate=0: passes -test.blockprofilerate to test - -outputdir=$PWD: passes -test.outputdir to test - -parallel=0: passes -test.parallel to test - -run="": passes -test.run to test - -short=false: passes -test.short to test - -timeout=0: passes -test.timeout to test - -v=false: passes -test.v to test -` - -// usage prints a usage message and exits. -func testUsage() { - fmt.Fprint(os.Stderr, usageMessage) - setExitStatus(2) - exit() -} - // testFlagSpec defines a flag we know about. type testFlagSpec struct { name string boolVar *bool + flagValue flag.Value passToTest bool // pass to Test multiOK bool // OK to have multiple instances present bool // flag has been seen @@ -65,32 +31,18 @@ type testFlagSpec struct { var testFlagDefn = []*testFlagSpec{ // local. {name: "c", boolVar: &testC}, + {name: "i", boolVar: &buildI}, + {name: "o"}, {name: "cover", boolVar: &testCover}, + {name: "covermode"}, {name: "coverpkg"}, - {name: "o"}, - - // build flags. - {name: "a", boolVar: &buildA}, - {name: "n", boolVar: &buildN}, - {name: "p"}, - {name: "x", boolVar: &buildX}, - {name: "i", boolVar: &buildI}, - {name: "work", boolVar: &buildWork}, - {name: "ccflags"}, - {name: "gcflags"}, {name: "exec"}, - {name: "ldflags"}, - {name: "gccgoflags"}, - {name: "tags"}, - {name: "compiler"}, - {name: "race", boolVar: &buildRace}, - {name: "installsuffix"}, // passed to 6.out, adding a "test." prefix to the name if necessary: -v becomes -test.v. {name: "bench", passToTest: true}, {name: "benchmem", boolVar: new(bool), passToTest: true}, {name: "benchtime", passToTest: true}, - {name: "covermode"}, + {name: "count", passToTest: true}, {name: "coverprofile", passToTest: true}, {name: "cpu", passToTest: true}, {name: "cpuprofile", passToTest: true}, @@ -103,9 +55,26 @@ var testFlagDefn = []*testFlagSpec{ {name: "run", passToTest: true}, {name: "short", boolVar: new(bool), passToTest: true}, {name: "timeout", passToTest: true}, + {name: "trace", passToTest: true}, {name: "v", boolVar: &testV, passToTest: true}, } +// add build flags to testFlagDefn +func init() { + var cmd Command + addBuildFlags(&cmd) + cmd.Flag.VisitAll(func(f *flag.Flag) { + if f.Name == "v" { + // test overrides the build -v flag + return + } + testFlagDefn = append(testFlagDefn, &testFlagSpec{ + name: f.Name, + flagValue: f.Value, + }) + }) +} + // testFlags processes the command line, grabbing -x and -c, rewriting known flags // to have "test" before them, and reading the command line for the 6.out. // Unfortunately for us, we need to do our own flag processing because go test @@ -148,73 +117,55 @@ func testFlags(args []string) (packageNames, passToTest []string) { passToTest = append(passToTest, args[i]) continue } - var err error - switch f.name { - // bool flags. - case "a", "c", "i", "n", "x", "v", "race", "cover", "work": - setBoolFlag(f.boolVar, value) - case "o": - testO = value - testNeedBinary = true - case "p": - setIntFlag(&buildP, value) - case "exec": - execCmd, err = splitQuotedFields(value) - if err != nil { + if f.flagValue != nil { + if err := f.flagValue.Set(value); err != nil { fatalf("invalid flag argument for -%s: %v", f.name, err) } - case "ccflags": - buildCcflags, err = splitQuotedFields(value) - if err != nil { - fatalf("invalid flag argument for -%s: %v", f.name, err) - } - case "gcflags": - buildGcflags, err = splitQuotedFields(value) - if err != nil { - fatalf("invalid flag argument for -%s: %v", f.name, err) - } - case "ldflags": - buildLdflags, err = splitQuotedFields(value) - if err != nil { - fatalf("invalid flag argument for -%s: %v", f.name, err) - } - case "gccgoflags": - buildGccgoflags, err = splitQuotedFields(value) - if err != nil { - fatalf("invalid flag argument for -%s: %v", f.name, err) - } - case "tags": - buildContext.BuildTags = strings.Fields(value) - case "compiler": - buildCompiler{}.Set(value) - case "bench": - // record that we saw the flag; don't care about the value - testBench = true - case "timeout": - testTimeout = value - case "blockprofile", "cpuprofile", "memprofile": - testProfile = true - testNeedBinary = true - case "coverpkg": - testCover = true - if value == "" { - testCoverPaths = nil - } else { - testCoverPaths = strings.Split(value, ",") - } - case "coverprofile": - testCover = true - testProfile = true - case "covermode": - switch value { - case "set", "count", "atomic": - testCoverMode = value - default: - fatalf("invalid flag argument for -cover: %q", value) + } else { + // Test-only flags. + // Arguably should be handled by f.flagValue, but aren't. + var err error + switch f.name { + // bool flags. + case "c", "i", "v", "cover": + setBoolFlag(f.boolVar, value) + case "o": + testO = value + testNeedBinary = true + case "exec": + execCmd, err = splitQuotedFields(value) + if err != nil { + fatalf("invalid flag argument for -%s: %v", f.name, err) + } + case "bench": + // record that we saw the flag; don't care about the value + testBench = true + case "timeout": + testTimeout = value + case "blockprofile", "cpuprofile", "memprofile", "trace": + testProfile = true + testNeedBinary = true + case "coverpkg": + testCover = true + if value == "" { + testCoverPaths = nil + } else { + testCoverPaths = strings.Split(value, ",") + } + case "coverprofile": + testCover = true + testProfile = true + case "covermode": + switch value { + case "set", "count", "atomic": + testCoverMode = value + default: + fatalf("invalid flag argument for -covermode: %q", value) + } + testCover = true + case "outputdir": + outputDir = value } - testCover = true - case "outputdir": - outputDir = value } if extraWord { i++ @@ -267,7 +218,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.boolVar != nil { + if f.boolVar != nil || isBoolFlag(f.flagValue) { if equals < 0 { // otherwise, it's been set and will be verified in setBoolFlag value = "true" } else { @@ -294,6 +245,17 @@ func testFlag(args []string, i int) (f *testFlagSpec, value string, extra bool) return } +// isBoolFlag reports whether v is a bool flag. +func isBoolFlag(v flag.Value) bool { + vv, ok := v.(interface { + IsBoolFlag() bool + }) + if ok { + return vv.IsBoolFlag() + } + return false +} + // setBoolFlag sets the addressed boolean to the value. func setBoolFlag(flag *bool, value string) { x, err := strconv.ParseBool(value) diff --git a/libgo/go/cmd/go/tool.go b/libgo/go/cmd/go/tool.go index 3f11c3e3d44..937ca1f306c 100644 --- a/libgo/go/cmd/go/tool.go +++ b/libgo/go/cmd/go/tool.go @@ -50,6 +50,9 @@ func tool(toolName string) string { if toolIsWindows { toolPath += toolWindowsExtension } + if len(buildToolExec) > 0 { + return toolPath + } // Give a nice message if there is no tool with that name. if _, err := os.Stat(toolPath); err != nil { if isInGoToolsRepo(toolName) { @@ -64,10 +67,6 @@ func tool(toolName string) string { } func isInGoToolsRepo(toolName string) bool { - switch toolName { - case "cover", "vet": - return true - } return false } @@ -92,7 +91,11 @@ func runTool(cmd *Command, args []string) { return } if toolN { - fmt.Printf("%s %s\n", toolPath, strings.Join(args[1:], " ")) + cmd := toolPath + if len(args) > 1 { + cmd += " " + strings.Join(args[1:], " ") + } + fmt.Printf("%s\n", cmd) return } toolCmd := &exec.Cmd{ @@ -101,6 +104,8 @@ func runTool(cmd *Command, args []string) { Stdin: os.Stdin, Stdout: os.Stdout, Stderr: os.Stderr, + // Set $GOROOT, mainly for go tool dist. + Env: mergeEnvLists([]string{"GOROOT=" + goroot}, os.Environ()), } err := toolCmd.Run() if err != nil { diff --git a/libgo/go/cmd/go/vcs.go b/libgo/go/cmd/go/vcs.go index 1cac6133889..28a7540dfe4 100644 --- a/libgo/go/cmd/go/vcs.go +++ b/libgo/go/cmd/go/vcs.go @@ -9,12 +9,15 @@ import ( "encoding/json" "errors" "fmt" + "internal/singleflight" "log" + "net/url" "os" "os/exec" "path/filepath" "regexp" "strings" + "sync" ) // A vcsCmd describes how to use a version control system @@ -23,13 +26,13 @@ type vcsCmd struct { name string cmd string // name of binary to invoke command - createCmd string // command to download a fresh copy of a repository - downloadCmd string // command to download updates into an existing repository + createCmd []string // commands to download a fresh copy of a repository + downloadCmd []string // commands to download updates into an existing repository tagCmd []tagCmd // commands to list tags tagLookupCmd []tagCmd // commands to lookup tags before running tagSyncCmd - tagSyncCmd string // command to sync to specific tag - tagSyncDefault string // command to sync to default tag + tagSyncCmd []string // commands to sync to specific tag + tagSyncDefault []string // commands to sync to default tag scheme []string pingCmd string @@ -38,6 +41,23 @@ type vcsCmd struct { resolveRepo func(v *vcsCmd, rootDir, remoteRepo string) (realRepo string, err error) } +var isSecureScheme = map[string]bool{ + "https": true, + "git+ssh": true, + "bzr+ssh": true, + "svn+ssh": true, + "ssh": true, +} + +func (v *vcsCmd) isSecure(repo string) bool { + u, err := url.Parse(repo) + if err != nil { + // If repo is not a URL, it's not secure. + return false + } + return isSecureScheme[u.Scheme] +} + // A tagCmd describes a command to list available tags // that can be passed to tagSyncCmd. type tagCmd struct { @@ -69,8 +89,8 @@ var vcsHg = &vcsCmd{ name: "Mercurial", cmd: "hg", - createCmd: "clone -U {repo} {dir}", - downloadCmd: "pull", + createCmd: []string{"clone -U {repo} {dir}"}, + downloadCmd: []string{"pull"}, // We allow both tag and branch names as 'tags' // for selecting a version. This lets people have @@ -81,8 +101,8 @@ var vcsHg = &vcsCmd{ {"tags", `^(\S+)`}, {"branches", `^(\S+)`}, }, - tagSyncCmd: "update -r {tag}", - tagSyncDefault: "update default", + tagSyncCmd: []string{"update -r {tag}"}, + tagSyncDefault: []string{"update default"}, scheme: []string{"https", "http", "ssh"}, pingCmd: "identify {scheme}://{repo}", @@ -102,8 +122,8 @@ var vcsGit = &vcsCmd{ name: "Git", cmd: "git", - createCmd: "clone {repo} {dir}", - downloadCmd: "pull --ff-only", + createCmd: []string{"clone {repo} {dir}", "--git-dir={dir}/.git submodule update --init --recursive"}, + downloadCmd: []string{"pull --ff-only", "submodule update --init --recursive"}, tagCmd: []tagCmd{ // tags/xxx matches a git tag named xxx @@ -113,41 +133,64 @@ var vcsGit = &vcsCmd{ tagLookupCmd: []tagCmd{ {"show-ref tags/{tag} origin/{tag}", `((?:tags|origin)/\S+)$`}, }, - tagSyncCmd: "checkout {tag}", - tagSyncDefault: "checkout master", - - scheme: []string{"git", "https", "http", "git+ssh"}, + tagSyncCmd: []string{"checkout {tag}", "submodule update --init --recursive"}, + // both createCmd and downloadCmd update the working dir. + // No need to do more here. We used to 'checkout master' + // but that doesn't work if the default branch is not named master. + // See golang.org/issue/9032. + tagSyncDefault: []string{"checkout master", "submodule update --init --recursive"}, + + scheme: []string{"git", "https", "http", "git+ssh", "ssh"}, pingCmd: "ls-remote {scheme}://{repo}", remoteRepo: gitRemoteRepo, } +// scpSyntaxRe matches the SCP-like addresses used by Git to access +// repositories by SSH. +var scpSyntaxRe = regexp.MustCompile(`^([a-zA-Z0-9_]+)@([a-zA-Z0-9._-]+):(.*)$`) + func gitRemoteRepo(vcsGit *vcsCmd, rootDir string) (remoteRepo string, err error) { - outb, err := vcsGit.runOutput(rootDir, "remote -v") + cmd := "config remote.origin.url" + errParse := errors.New("unable to parse output of git " + cmd) + errRemoteOriginNotFound := errors.New("remote origin not found") + outb, err := vcsGit.run1(rootDir, cmd, nil, false) if err != nil { + // if it doesn't output any message, it means the config argument is correct, + // but the config value itself doesn't exist + if outb != nil && len(outb) == 0 { + return "", errRemoteOriginNotFound + } return "", err } - out := string(outb) - - // Expect: - // origin https://github.com/rsc/pdf (fetch) - // origin https://github.com/rsc/pdf (push) - // use first line only. - - if !strings.HasPrefix(out, "origin\t") { - return "", fmt.Errorf("unable to parse output of git remote -v") - } - out = strings.TrimPrefix(out, "origin\t") - i := strings.Index(out, "\n") - if i < 0 { - return "", fmt.Errorf("unable to parse output of git remote -v") + out := strings.TrimSpace(string(outb)) + + var repoURL *url.URL + if m := scpSyntaxRe.FindStringSubmatch(out); m != nil { + // Match SCP-like syntax and convert it to a URL. + // Eg, "git@github.com:user/repo" becomes + // "ssh://git@github.com/user/repo". + repoURL = &url.URL{ + Scheme: "ssh", + User: url.User(m[1]), + Host: m[2], + RawPath: m[3], + } + } else { + repoURL, err = url.Parse(out) + if err != nil { + return "", err + } } - out = out[:i] - i = strings.LastIndex(out, " ") - if i < 0 { - return "", fmt.Errorf("unable to parse output of git remote -v") + + // Iterate over insecure schemes too, because this function simply + // reports the state of the repo. If we can't see insecure schemes then + // we can't report the actual repo URL. + for _, s := range vcsGit.scheme { + if repoURL.Scheme == s { + return repoURL.String(), nil + } } - out = out[:i] - return strings.TrimSpace(string(out)), nil + return "", errParse } // vcsBzr describes how to use Bazaar. @@ -155,15 +198,15 @@ var vcsBzr = &vcsCmd{ name: "Bazaar", cmd: "bzr", - createCmd: "branch {repo} {dir}", + createCmd: []string{"branch {repo} {dir}"}, // Without --overwrite bzr will not pull tags that changed. // Replace by --overwrite-tags after http://pad.lv/681792 goes in. - downloadCmd: "pull --overwrite", + downloadCmd: []string{"pull --overwrite"}, tagCmd: []tagCmd{{"tags", `^(\S+)`}}, - tagSyncCmd: "update -r {tag}", - tagSyncDefault: "update -r revno:-1", + tagSyncCmd: []string{"update -r {tag}"}, + tagSyncDefault: []string{"update -r revno:-1"}, scheme: []string{"https", "http", "bzr", "bzr+ssh"}, pingCmd: "info {scheme}://{repo}", @@ -217,8 +260,8 @@ var vcsSvn = &vcsCmd{ name: "Subversion", cmd: "svn", - createCmd: "checkout {repo} {dir}", - downloadCmd: "update", + createCmd: []string{"checkout {repo} {dir}"}, + downloadCmd: []string{"update"}, // There is no tag command in subversion. // The branch information is all in the path names. @@ -294,14 +337,14 @@ func (v *vcsCmd) run1(dir string, cmdline string, keyval []string, verbose bool) _, err := exec.LookPath(v.cmd) if err != nil { fmt.Fprintf(os.Stderr, - "go: missing %s command. See http://golang.org/s/gogetcmd\n", + "go: missing %s command. See https://golang.org/s/gogetcmd\n", v.name) return nil, err } cmd := exec.Command(v.cmd, args...) cmd.Dir = dir - cmd.Env = envForDir(cmd.Dir) + cmd.Env = envForDir(cmd.Dir, os.Environ()) if buildX { fmt.Printf("cd %s\n", dir) fmt.Printf("%s %s\n", v.cmd, strings.Join(args, " ")) @@ -316,7 +359,7 @@ func (v *vcsCmd) run1(dir string, cmdline string, keyval []string, verbose bool) fmt.Fprintf(os.Stderr, "# cd %s; %s %s\n", dir, v.cmd, strings.Join(args, " ")) os.Stderr.Write(out) } - return nil, err + return out, err } return out, nil } @@ -329,7 +372,15 @@ func (v *vcsCmd) ping(scheme, repo string) error { // create creates a new copy of repo in dir. // The parent of dir must exist; dir must not. func (v *vcsCmd) create(dir, repo string) error { - return v.run(".", v.createCmd, "dir", dir, "repo", repo) + for _, cmd := range v.createCmd { + if !go15VendorExperiment && strings.Contains(cmd, "submodule") { + continue + } + if err := v.run(".", cmd, "dir", dir, "repo", repo); err != nil { + return err + } + } + return nil } // download downloads any new changes for the repo in dir. @@ -337,7 +388,15 @@ func (v *vcsCmd) download(dir string) error { if err := v.fixDetachedHead(dir); err != nil { return err } - return v.run(dir, v.downloadCmd) + for _, cmd := range v.downloadCmd { + if !go15VendorExperiment && strings.Contains(cmd, "submodule") { + continue + } + if err := v.run(dir, cmd); err != nil { + return err + } + } + return nil } // fixDetachedHead switches a Git repository in dir from a detached head to the master branch. @@ -383,7 +442,7 @@ func (v *vcsCmd) tags(dir string) ([]string, error) { // tagSync syncs the repo in dir to the named tag, // which either is a tag returned by tags or is v.tagDefault. func (v *vcsCmd) tagSync(dir, tag string) error { - if v.tagSyncCmd == "" { + if v.tagSyncCmd == nil { return nil } if tag != "" { @@ -400,10 +459,28 @@ func (v *vcsCmd) tagSync(dir, tag string) error { } } } - if tag == "" && v.tagSyncDefault != "" { - return v.run(dir, v.tagSyncDefault) + + if tag == "" && v.tagSyncDefault != nil { + for _, cmd := range v.tagSyncDefault { + if !go15VendorExperiment && strings.Contains(cmd, "submodule") { + continue + } + if err := v.run(dir, cmd); err != nil { + return err + } + } + return nil + } + + for _, cmd := range v.tagSyncCmd { + if !go15VendorExperiment && strings.Contains(cmd, "submodule") { + continue + } + if err := v.run(dir, cmd, "tag", tag); err != nil { + return err + } } - return v.run(dir, v.tagSyncCmd, "tag", tag) + return nil } // A vcsPath describes how to convert an import path into a @@ -467,10 +544,20 @@ type repoRoot struct { var httpPrefixRE = regexp.MustCompile(`^https?:`) +// securityMode specifies whether a function should make network +// calls using insecure transports (eg, plain text HTTP). +// The zero value is "secure". +type securityMode int + +const ( + secure securityMode = iota + insecure +) + // repoRootForImportPath analyzes importPath to determine the // version control system, and code repository to use. -func repoRootForImportPath(importPath string) (*repoRoot, error) { - rr, err := repoRootForImportPathStatic(importPath, "") +func repoRootForImportPath(importPath string, security securityMode) (*repoRoot, error) { + rr, err := repoRootFromVCSPaths(importPath, "", security, vcsPaths) if err == errUnknownSite { // If there are wildcards, look up the thing before the wildcard, // hoping it applies to the wildcarded parts too. @@ -479,7 +566,7 @@ func repoRootForImportPath(importPath string) (*repoRoot, error) { if i := strings.Index(lookup, "/.../"); i >= 0 { lookup = lookup[:i] } - rr, err = repoRootForImportDynamic(lookup) + rr, err = repoRootForImportDynamic(lookup, security) // repoRootForImportDynamic returns error detail // that is irrelevant if the user didn't intend to use a @@ -492,6 +579,13 @@ func repoRootForImportPath(importPath string) (*repoRoot, error) { err = fmt.Errorf("unrecognized import path %q", importPath) } } + if err != nil { + rr1, err1 := repoRootFromVCSPaths(importPath, "", security, vcsPathsAfterDynamic) + if err1 == nil { + rr = rr1 + err = nil + } + } if err == nil && strings.Contains(importPath, "...") && strings.Contains(rr.root, "...") { // Do not allow wildcards in the repo root. @@ -503,13 +597,10 @@ func repoRootForImportPath(importPath string) (*repoRoot, error) { 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) -// +// repoRootFromVCSPaths attempts to map importPath to a repoRoot +// using the mappings defined in vcsPaths. // If scheme is non-empty, that scheme is forced. -func repoRootForImportPathStatic(importPath, scheme string) (*repoRoot, error) { +func repoRootFromVCSPaths(importPath, scheme string, security securityMode, vcsPaths []*vcsPath) (*repoRoot, error) { // A common error is to use https://packagepath because that's what // hg and git require. Diagnose this helpfully. if loc := httpPrefixRE.FindStringIndex(importPath); loc != nil { @@ -559,6 +650,9 @@ func repoRootForImportPathStatic(importPath, scheme string) (*repoRoot, error) { match["repo"] = scheme + "://" + match["repo"] } else { for _, scheme := range vcs.scheme { + if security == secure && !isSecureScheme[scheme] { + continue + } if vcs.ping(scheme, match["repo"]) == nil { match["repo"] = scheme + "://" + match["repo"] break @@ -579,26 +673,31 @@ func repoRootForImportPathStatic(importPath, scheme string) (*repoRoot, error) { // 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) { +// This handles custom import paths like "name.tld/pkg/foo" or just "name.tld". +func repoRootForImportDynamic(importPath string, security securityMode) (*repoRoot, error) { slash := strings.Index(importPath, "/") if slash < 0 { - return nil, errors.New("import path does not contain a slash") + slash = len(importPath) } host := importPath[:slash] if !strings.Contains(host, ".") { return nil, errors.New("import path does not begin with hostname") } - urlStr, body, err := httpsOrHTTP(importPath) + urlStr, body, err := httpsOrHTTP(importPath, security) if err != nil { - return nil, fmt.Errorf("http/https fetch: %v", err) + msg := "https fetch: %v" + if security == insecure { + msg = "http/" + msg + } + return nil, fmt.Errorf(msg, err) } defer body.Close() imports, err := parseMetaGoImports(body) if err != nil { return nil, fmt.Errorf("parsing %s: %v", importPath, err) } - metaImport, err := matchGoImport(imports, importPath) + // Find the matched meta import. + mmi, err := matchGoImport(imports, importPath) if err != nil { if err != errNoMatch { return nil, fmt.Errorf("parse %s: %v", urlStr, err) @@ -606,7 +705,7 @@ func repoRootForImportDynamic(importPath string) (*repoRoot, error) { 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) + log.Printf("get %q: found meta tag %#v at %s", importPath, mmi, urlStr) } // If the import was "uni.edu/bob/project", which said the // prefix was "uni.edu" and the RepoRoot was "evilroot.com", @@ -614,42 +713,89 @@ func repoRootForImportDynamic(importPath string) (*repoRoot, error) { // "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 mmi.Prefix != importPath { if buildV { log.Printf("get %q: verifying non-authoritative meta tag", importPath) } urlStr0 := urlStr - urlStr, body, err = httpsOrHTTP(metaImport.Prefix) + var imports []metaImport + urlStr, imports, err = metaImportsForPrefix(mmi.Prefix, security) if err != nil { - return nil, fmt.Errorf("fetch %s: %v", urlStr, err) - } - imports, err := parseMetaGoImports(body) - if err != nil { - return nil, fmt.Errorf("parsing %s: %v", importPath, err) - } - if len(imports) == 0 { - return nil, fmt.Errorf("fetch %s: no go-import meta tag", urlStr) + return nil, err } 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 err != nil || mmi != metaImport2 { + return nil, fmt.Errorf("%s and %s disagree about go-import for %s", urlStr0, urlStr, mmi.Prefix) } } - if !strings.Contains(metaImport.RepoRoot, "://") { - return nil, fmt.Errorf("%s: invalid repo root %q; no scheme", urlStr, metaImport.RepoRoot) + if !strings.Contains(mmi.RepoRoot, "://") { + return nil, fmt.Errorf("%s: invalid repo root %q; no scheme", urlStr, mmi.RepoRoot) } rr := &repoRoot{ - vcs: vcsByCmd(metaImport.VCS), - repo: metaImport.RepoRoot, - root: metaImport.Prefix, + vcs: vcsByCmd(mmi.VCS), + repo: mmi.RepoRoot, + root: mmi.Prefix, } if rr.vcs == nil { - return nil, fmt.Errorf("%s: unknown vcs %q", urlStr, metaImport.VCS) + return nil, fmt.Errorf("%s: unknown vcs %q", urlStr, mmi.VCS) } return rr, nil } +var fetchGroup singleflight.Group +var ( + fetchCacheMu sync.Mutex + fetchCache = map[string]fetchResult{} // key is metaImportsForPrefix's importPrefix +) + +// metaImportsForPrefix takes a package's root import path as declared in a tag +// and returns its HTML discovery URL and the parsed metaImport lines +// found on the page. +// +// The importPath is of the form "golang.org/x/tools". +// It is an error if no imports are found. +// urlStr will still be valid if err != nil. +// The returned urlStr will be of the form "https://golang.org/x/tools?go-get=1" +func metaImportsForPrefix(importPrefix string, security securityMode) (urlStr string, imports []metaImport, err error) { + setCache := func(res fetchResult) (fetchResult, error) { + fetchCacheMu.Lock() + defer fetchCacheMu.Unlock() + fetchCache[importPrefix] = res + return res, nil + } + + resi, _, _ := fetchGroup.Do(importPrefix, func() (resi interface{}, err error) { + fetchCacheMu.Lock() + if res, ok := fetchCache[importPrefix]; ok { + fetchCacheMu.Unlock() + return res, nil + } + fetchCacheMu.Unlock() + + urlStr, body, err := httpsOrHTTP(importPrefix, security) + if err != nil { + return setCache(fetchResult{urlStr: urlStr, err: fmt.Errorf("fetch %s: %v", urlStr, err)}) + } + imports, err := parseMetaGoImports(body) + if err != nil { + return setCache(fetchResult{urlStr: urlStr, err: fmt.Errorf("parsing %s: %v", urlStr, err)}) + } + if len(imports) == 0 { + err = fmt.Errorf("fetch %s: no go-import meta tag", urlStr) + } + return setCache(fetchResult{urlStr: urlStr, imports: imports, err: err}) + }) + res := resi.(fetchResult) + return res.urlStr, res.imports, res.err +} + +type fetchResult struct { + urlStr string // e.g. "https://foo.com/x/bar?go-get=1" + imports []metaImport + err error +} + // metaImport represents the parsed tags from HTML files. type metaImport struct { @@ -689,7 +835,10 @@ func expand(match map[string]string, s string) string { return s } -// vcsPaths lists the known vcs paths. +// vcsPaths defines the meaning of import paths referring to +// commonly-used VCS hosting sites (github.com/user/dir) +// and import paths referring to a fully-qualified importPath +// containing a VCS type (foo.com/repo.git/dir) var vcsPaths = []*vcsPath{ // Google Code - new syntax { @@ -722,15 +871,6 @@ var vcsPaths = []*vcsPath{ check: bitbucketVCS, }, - // Launchpad - { - prefix: "launchpad.net/", - re: `^(?Plaunchpad\.net/((?P[A-Za-z0-9_.\-]+)(?P/[A-Za-z0-9_.\-]+)?|~[A-Za-z0-9_.\-]+/(\+junk|[A-Za-z0-9_.\-]+)/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`, - vcs: "bzr", - repo: "https://{root}", - check: launchpadVCS, - }, - // IBM DevOps Services (JazzHub) { prefix: "hub.jazz.net/git", @@ -740,13 +880,37 @@ var vcsPaths = []*vcsPath{ check: noVCSSuffix, }, + // Git at Apache + { + prefix: "git.apache.org", + re: `^(?Pgit.apache.org/[a-z0-9_.\-]+\.git)(/[A-Za-z0-9_.\-]+)*$`, + vcs: "git", + repo: "https://{root}", + }, + // General syntax for any server. + // Must be last. { re: `^(?P(?P([a-z0-9.\-]+\.)+[a-z0-9.\-]+(:[0-9]+)?/[A-Za-z0-9_.\-/]*?)\.(?Pbzr|git|hg|svn))(/[A-Za-z0-9_.\-]+)*$`, ping: true, }, } +// vcsPathsAfterDynamic gives additional vcsPaths entries +// to try after the dynamic HTML check. +// This gives those sites a chance to introduce tags +// as part of a graceful transition away from the hard-coded logic. +var vcsPathsAfterDynamic = []*vcsPath{ + // Launchpad. See golang.org/issue/11436. + { + prefix: "launchpad.net/", + re: `^(?Plaunchpad\.net/((?P[A-Za-z0-9_.\-]+)(?P/[A-Za-z0-9_.\-]+)?|~[A-Za-z0-9_.\-]+/(\+junk|[A-Za-z0-9_.\-]+)/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`, + vcs: "bzr", + repo: "https://{root}", + check: launchpadVCS, + }, +} + func init() { // fill in cached regexps. // Doing this eagerly discovers invalid regexp syntax @@ -754,6 +918,9 @@ func init() { for _, srv := range vcsPaths { srv.regexp = regexp.MustCompile(srv.re) } + for _, srv := range vcsPathsAfterDynamic { + srv.regexp = regexp.MustCompile(srv.re) + } } // noVCSSuffix checks that the repository name does not @@ -821,10 +988,25 @@ func bitbucketVCS(match map[string]string) error { url := expand(match, "https://api.bitbucket.org/1.0/repositories/{bitname}") data, err := httpGET(url) if err != nil { - return err - } - if err := json.Unmarshal(data, &resp); err != nil { - return fmt.Errorf("decoding %s: %v", url, err) + if httpErr, ok := err.(*httpError); ok && httpErr.statusCode == 403 { + // this may be a private repository. If so, attempt to determine which + // VCS it uses. See issue 5375. + root := match["root"] + for _, vcs := range []string{"git", "hg"} { + if vcsByCmd(vcs).ping("https", root) == nil { + resp.SCM = vcs + break + } + } + } + + if resp.SCM == "" { + return err + } + } else { + if err := json.Unmarshal(data, &resp); err != nil { + return fmt.Errorf("decoding %s: %v", url, err) + } } if vcsByCmd(resp.SCM) != nil { diff --git a/libgo/go/cmd/go/vcs_test.go b/libgo/go/cmd/go/vcs_test.go index 14d681ba6af..f5d5e4f4f0b 100644 --- a/libgo/go/cmd/go/vcs_test.go +++ b/libgo/go/cmd/go/vcs_test.go @@ -5,20 +5,15 @@ package main import ( - "runtime" + "internal/testenv" "testing" ) // Test that RepoRootForImportPath creates the correct RepoRoot for a given importPath. // TODO(cmang): Add tests for SVN and BZR. func TestRepoRootForImportPath(t *testing.T) { - if testing.Short() { - t.Skip("skipping test to avoid external network") - } - switch runtime.GOOS { - case "nacl", "android": - t.Skipf("no networking available on %s", runtime.GOOS) - } + testenv.MustHaveExternalNetwork(t) + tests := []struct { path string want *repoRoot @@ -101,10 +96,34 @@ func TestRepoRootForImportPath(t *testing.T) { "hub.jazz.net/git/USER/pkgname", nil, }, + // Spaces are not valid in package name + { + "git.apache.org/package name/path/to/lib", + nil, + }, + // Should have ".git" suffix + { + "git.apache.org/package-name/path/to/lib", + nil, + }, + { + "git.apache.org/package-name.git", + &repoRoot{ + vcs: vcsGit, + repo: "https://git.apache.org/package-name.git", + }, + }, + { + "git.apache.org/package-name_2.x.git/path/to/lib", + &repoRoot{ + vcs: vcsGit, + repo: "https://git.apache.org/package-name_2.x.git", + }, + }, } for _, test := range tests { - got, err := repoRootForImportPath(test.path) + got, err := repoRootForImportPath(test.path, secure) want := test.want if want == nil { @@ -122,3 +141,35 @@ func TestRepoRootForImportPath(t *testing.T) { } } } + +func TestIsSecure(t *testing.T) { + tests := []struct { + vcs *vcsCmd + url string + secure bool + }{ + {vcsGit, "http://example.com/foo.git", false}, + {vcsGit, "https://example.com/foo.git", true}, + {vcsBzr, "http://example.com/foo.bzr", false}, + {vcsBzr, "https://example.com/foo.bzr", true}, + {vcsSvn, "http://example.com/svn", false}, + {vcsSvn, "https://example.com/svn", true}, + {vcsHg, "http://example.com/foo.hg", false}, + {vcsHg, "https://example.com/foo.hg", true}, + {vcsGit, "ssh://user@example.com/foo.git", true}, + {vcsGit, "user@server:path/to/repo.git", false}, + {vcsGit, "user@server:", false}, + {vcsGit, "server:repo.git", false}, + {vcsGit, "server:path/to/repo.git", false}, + {vcsGit, "example.com:path/to/repo.git", false}, + {vcsGit, "path/that/contains/a:colon/repo.git", false}, + {vcsHg, "ssh://user@example.com/path/to/repo.hg", true}, + } + + for _, test := range tests { + secure := test.vcs.isSecure(test.url) + if secure != test.secure { + t.Errorf("%s isSecure(%q) = %t; want %t", test.vcs, test.url, secure, test.secure) + } + } +} diff --git a/libgo/go/cmd/go/vendor_test.go b/libgo/go/cmd/go/vendor_test.go new file mode 100644 index 00000000000..1e8cf9c8d26 --- /dev/null +++ b/libgo/go/cmd/go/vendor_test.go @@ -0,0 +1,258 @@ +// Copyright 2015 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. + +// Tests for vendoring semantics. + +package main_test + +import ( + "bytes" + "fmt" + "internal/testenv" + "path/filepath" + "regexp" + "strings" + "testing" +) + +func TestVendorImports(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) + tg.setenv("GO15VENDOREXPERIMENT", "1") + tg.run("list", "-f", "{{.ImportPath}} {{.Imports}}", "vend/...") + want := ` + vend [vend/vendor/p r] + vend/hello [fmt vend/vendor/strings] + vend/subdir [vend/vendor/p r] + vend/vendor/p [] + vend/vendor/q [] + vend/vendor/strings [] + vend/x [vend/x/vendor/p vend/vendor/q vend/x/vendor/r] + vend/x/invalid [vend/x/invalid/vendor/foo] + vend/x/vendor/p [] + vend/x/vendor/p/p [notfound] + vend/x/vendor/r [] + ` + want = strings.Replace(want+"\t", "\n\t\t", "\n", -1) + want = strings.TrimPrefix(want, "\n") + + have := tg.stdout.String() + + if have != want { + t.Errorf("incorrect go list output:\n%s", diffSortedOutputs(have, want)) + } +} + +func TestVendorRun(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) + tg.setenv("GO15VENDOREXPERIMENT", "1") + tg.cd(filepath.Join(tg.pwd(), "testdata/src/vend/hello")) + tg.run("run", "hello.go") + tg.grepStdout("hello, world", "missing hello world output") +} + +func TestVendorGOPATH(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + changeVolume := func(s string, f func(s string) string) string { + vol := filepath.VolumeName(s) + return f(vol) + s[len(vol):] + } + gopath := changeVolume(filepath.Join(tg.pwd(), "testdata"), strings.ToLower) + tg.setenv("GOPATH", gopath) + tg.setenv("GO15VENDOREXPERIMENT", "1") + cd := changeVolume(filepath.Join(tg.pwd(), "testdata/src/vend/hello"), strings.ToUpper) + tg.cd(cd) + tg.run("run", "hello.go") + tg.grepStdout("hello, world", "missing hello world output") +} + +func TestVendorTest(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) + tg.setenv("GO15VENDOREXPERIMENT", "1") + tg.cd(filepath.Join(tg.pwd(), "testdata/src/vend/hello")) + tg.run("test", "-v") + tg.grepStdout("TestMsgInternal", "missing use in internal test") + tg.grepStdout("TestMsgExternal", "missing use in external test") +} + +func TestVendorInvalid(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) + tg.setenv("GO15VENDOREXPERIMENT", "1") + + tg.runFail("build", "vend/x/invalid") + tg.grepStderr("must be imported as foo", "missing vendor import error") +} + +func TestVendorImportError(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata")) + tg.setenv("GO15VENDOREXPERIMENT", "1") + + tg.runFail("build", "vend/x/vendor/p/p") + + re := regexp.MustCompile(`cannot find package "notfound" in any of: + .*[\\/]testdata[\\/]src[\\/]vend[\\/]x[\\/]vendor[\\/]notfound \(vendor tree\) + .*[\\/]testdata[\\/]src[\\/]vend[\\/]vendor[\\/]notfound \(vendor tree\) + .*[\\/]src[\\/]notfound \(from \$GOROOT\) + .*[\\/]testdata[\\/]src[\\/]notfound \(from \$GOPATH\)`) + + if !re.MatchString(tg.stderr.String()) { + t.Errorf("did not find expected search list in error text") + } +} + +// diffSortedOutput prepares a diff of the already sorted outputs haveText and wantText. +// The diff shows common lines prefixed by a tab, lines present only in haveText +// prefixed by "unexpected: ", and lines present only in wantText prefixed by "missing: ". +func diffSortedOutputs(haveText, wantText string) string { + var diff bytes.Buffer + have := splitLines(haveText) + want := splitLines(wantText) + for len(have) > 0 || len(want) > 0 { + if len(want) == 0 || len(have) > 0 && have[0] < want[0] { + fmt.Fprintf(&diff, "unexpected: %s\n", have[0]) + have = have[1:] + continue + } + if len(have) == 0 || len(want) > 0 && want[0] < have[0] { + fmt.Fprintf(&diff, "missing: %s\n", want[0]) + want = want[1:] + continue + } + fmt.Fprintf(&diff, "\t%s\n", want[0]) + want = want[1:] + have = have[1:] + } + return diff.String() +} + +func splitLines(s string) []string { + x := strings.Split(s, "\n") + if x[len(x)-1] == "" { + x = x[:len(x)-1] + } + return x +} + +func TestVendorGet(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.tempFile("src/v/m.go", ` + package main + import ("fmt"; "vendor.org/p") + func main() { + fmt.Println(p.C) + }`) + tg.tempFile("src/v/m_test.go", ` + package main + import ("fmt"; "testing"; "vendor.org/p") + func TestNothing(t *testing.T) { + fmt.Println(p.C) + }`) + tg.tempFile("src/v/vendor/vendor.org/p/p.go", ` + package p + const C = 1`) + tg.setenv("GOPATH", tg.path(".")) + tg.setenv("GO15VENDOREXPERIMENT", "1") + tg.cd(tg.path("src/v")) + tg.run("run", "m.go") + tg.run("test") + tg.run("list", "-f", "{{.Imports}}") + tg.grepStdout("v/vendor/vendor.org/p", "import not in vendor directory") + tg.run("list", "-f", "{{.TestImports}}") + tg.grepStdout("v/vendor/vendor.org/p", "test import not in vendor directory") + tg.run("get") + tg.run("get", "-t") +} + +func TestVendorGetUpdate(t *testing.T) { + testenv.MustHaveExternalNetwork(t) + + tg := testgo(t) + defer tg.cleanup() + tg.makeTempdir() + tg.setenv("GOPATH", tg.path(".")) + tg.setenv("GO15VENDOREXPERIMENT", "1") + tg.run("get", "github.com/rsc/go-get-issue-11864") + tg.run("get", "-u", "github.com/rsc/go-get-issue-11864") +} + +func TestVendorCache(t *testing.T) { + tg := testgo(t) + defer tg.cleanup() + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata/testvendor")) + tg.setenv("GO15VENDOREXPERIMENT", "1") + tg.runFail("build", "p") + tg.grepStderr("must be imported as x", "did not fail to build p") +} + +func TestVendorTest2(t *testing.T) { + testenv.MustHaveExternalNetwork(t) + + tg := testgo(t) + defer tg.cleanup() + tg.makeTempdir() + tg.setenv("GOPATH", tg.path(".")) + tg.setenv("GO15VENDOREXPERIMENT", "1") + tg.run("get", "github.com/rsc/go-get-issue-11864") + + // build -i should work + tg.run("build", "-i", "github.com/rsc/go-get-issue-11864") + tg.run("build", "-i", "github.com/rsc/go-get-issue-11864/t") + + // test -i should work like build -i (golang.org/issue/11988) + tg.run("test", "-i", "github.com/rsc/go-get-issue-11864") + tg.run("test", "-i", "github.com/rsc/go-get-issue-11864/t") + + // test should work too + tg.run("test", "github.com/rsc/go-get-issue-11864") + tg.run("test", "github.com/rsc/go-get-issue-11864/t") + + // external tests should observe internal test exports (golang.org/issue/11977) + tg.run("test", "github.com/rsc/go-get-issue-11864/vendor/vendor.org/tx2") +} + +func TestVendorList(t *testing.T) { + testenv.MustHaveExternalNetwork(t) + + tg := testgo(t) + defer tg.cleanup() + tg.makeTempdir() + tg.setenv("GOPATH", tg.path(".")) + tg.setenv("GO15VENDOREXPERIMENT", "1") + tg.run("get", "github.com/rsc/go-get-issue-11864") + + tg.run("list", "-f", `{{join .TestImports "\n"}}`, "github.com/rsc/go-get-issue-11864/t") + tg.grepStdout("go-get-issue-11864/vendor/vendor.org/p", "did not find vendor-expanded p") + + tg.run("list", "-f", `{{join .XTestImports "\n"}}`, "github.com/rsc/go-get-issue-11864/tx") + tg.grepStdout("go-get-issue-11864/vendor/vendor.org/p", "did not find vendor-expanded p") + + tg.run("list", "-f", `{{join .XTestImports "\n"}}`, "github.com/rsc/go-get-issue-11864/vendor/vendor.org/tx2") + tg.grepStdout("go-get-issue-11864/vendor/vendor.org/tx2", "did not find vendor-expanded tx2") + + tg.run("list", "-f", `{{join .XTestImports "\n"}}`, "github.com/rsc/go-get-issue-11864/vendor/vendor.org/tx3") + tg.grepStdout("go-get-issue-11864/vendor/vendor.org/tx3", "did not find vendor-expanded tx3") +} + +func TestVendor12156(t *testing.T) { + // Former index out of range panic. + tg := testgo(t) + defer tg.cleanup() + tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata/testvendor2")) + tg.setenv("GO15VENDOREXPERIMENT", "1") + tg.cd(filepath.Join(tg.pwd(), "testdata/testvendor2/src/p")) + tg.runFail("build", "p.go") + tg.grepStderrNot("panic", "panicked") + tg.grepStderr(`cannot find package "x"`, "wrong error") +} diff --git a/libgo/go/cmd/go/vet.go b/libgo/go/cmd/go/vet.go index 02ff54b2ac8..81b978e8dab 100644 --- a/libgo/go/cmd/go/vet.go +++ b/libgo/go/cmd/go/vet.go @@ -7,17 +7,17 @@ package main import "path/filepath" func init() { - addBuildFlagsNX(cmdVet) + addBuildFlags(cmdVet) } var cmdVet = &Command{ Run: runVet, - UsageLine: "vet [-n] [-x] [packages]", + UsageLine: "vet [-n] [-x] [build flags] [packages]", Short: "run go tool vet on packages", Long: ` Vet runs the Go vet command on the packages named by the import paths. -For more about vet, see 'godoc golang.org/x/tools/cmd/vet'. +For more about vet, see 'go doc cmd/vet'. For more about specifying packages, see 'go help packages'. To run the vet tool with specific options, run 'go tool vet'. @@ -25,6 +25,8 @@ To run the vet tool with specific options, run 'go tool vet'. The -n flag prints commands that would be executed. The -x flag prints commands as they are executed. +For more about build flags, see 'go help build'. + See also: go fmt, go fix. `, } @@ -46,5 +48,5 @@ func runVetFiles(p *Package, files []string) { for i := range files { files[i] = filepath.Join(p.Dir, files[i]) } - run(tool("vet"), relPaths(files)) + run(buildToolExec, tool("vet"), relPaths(files)) } diff --git a/libgo/go/cmd/gofmt/doc.go b/libgo/go/cmd/gofmt/doc.go index 3fc0439548f..9d0cd328623 100644 --- a/libgo/go/cmd/gofmt/doc.go +++ b/libgo/go/cmd/gofmt/doc.go @@ -87,6 +87,13 @@ When invoked with -s gofmt will make the following source transformations where for x, _ = range v {...} will be simplified to: for x = range v {...} + + A range of the form: + for _ = range v {...} + will be simplified to: + for range v {...} + +This may result in changes that are incompatible with earlier versions of Go. */ package main diff --git a/libgo/go/cmd/gofmt/gofmt.go b/libgo/go/cmd/gofmt/gofmt.go index 81da21ff109..b2805ac05fb 100644 --- a/libgo/go/cmd/gofmt/gofmt.go +++ b/libgo/go/cmd/gofmt/gofmt.go @@ -13,6 +13,7 @@ import ( "go/printer" "go/scanner" "go/token" + "internal/format" "io" "io/ioutil" "os" @@ -87,7 +88,7 @@ func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error return err } - file, sourceAdj, indentAdj, err := parse(fileSet, filename, src, stdin) + file, sourceAdj, indentAdj, err := format.Parse(fileSet, filename, src, stdin) if err != nil { return err } @@ -106,7 +107,7 @@ func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error simplify(file) } - res, err := format(fileSet, file, sourceAdj, indentAdj, src, printer.Config{Mode: printerMode, Tabwidth: tabWidth}) + res, err := format.Format(fileSet, file, sourceAdj, indentAdj, src, printer.Config{Mode: printerMode, Tabwidth: tabWidth}) if err != nil { return err } @@ -234,154 +235,3 @@ func diff(b1, b2 []byte) (data []byte, err error) { return } - -// ---------------------------------------------------------------------------- -// Support functions -// -// The functions parse, format, and isSpace below are identical to the -// respective functions in src/go/format/format.go - keep them in sync! -// -// TODO(gri) Factor out this functionality, eventually. - -// parse parses src, which was read from the named file, -// as a Go source file, declaration, or statement list. -func parse(fset *token.FileSet, filename string, src []byte, fragmentOk bool) ( - file *ast.File, - sourceAdj func(src []byte, indent int) []byte, - indentAdj int, - err error, -) { - // Try as whole source file. - file, err = parser.ParseFile(fset, filename, src, parserMode) - // If there's no error, return. If the error is that the source file didn't begin with a - // package line and source fragments are ok, fall through to - // try as a source fragment. Stop and return on any other error. - if err == nil || !fragmentOk || !strings.Contains(err.Error(), "expected 'package'") { - return - } - - // If this is a declaration list, make it a source file - // by inserting a package clause. - // Insert using a ;, not a newline, so that the line numbers - // in psrc match the ones in src. - psrc := append([]byte("package p;"), src...) - file, err = parser.ParseFile(fset, filename, psrc, parserMode) - if err == nil { - sourceAdj = func(src []byte, indent int) []byte { - // Remove the package clause. - // Gofmt has turned the ; into a \n. - src = src[indent+len("package p\n"):] - return bytes.TrimSpace(src) - } - return - } - // If the error is that the source file didn't begin with a - // declaration, fall through to try as a statement list. - // Stop and return on any other error. - if !strings.Contains(err.Error(), "expected declaration") { - return - } - - // If this is a statement list, make it a source file - // by inserting a package clause and turning the list - // into a function body. This handles expressions too. - // Insert using a ;, not a newline, so that the line numbers - // in fsrc match the ones in src. - fsrc := append(append([]byte("package p; func _() {"), src...), '\n', '}') - file, err = parser.ParseFile(fset, filename, fsrc, parserMode) - if err == nil { - sourceAdj = func(src []byte, indent int) []byte { - // Cap adjusted indent to zero. - if indent < 0 { - indent = 0 - } - // Remove the wrapping. - // Gofmt has turned the ; into a \n\n. - // There will be two non-blank lines with indent, hence 2*indent. - src = src[2*indent+len("package p\n\nfunc _() {"):] - src = src[:len(src)-(indent+len("\n}\n"))] - return bytes.TrimSpace(src) - } - // Gofmt has also indented the function body one level. - // Adjust that with indentAdj. - indentAdj = -1 - } - - // Succeeded, or out of options. - return -} - -// format formats the given package file originally obtained from src -// and adjusts the result based on the original source via sourceAdj -// and indentAdj. -func format( - fset *token.FileSet, - file *ast.File, - sourceAdj func(src []byte, indent int) []byte, - indentAdj int, - src []byte, - cfg printer.Config, -) ([]byte, error) { - if sourceAdj == nil { - // Complete source file. - var buf bytes.Buffer - err := cfg.Fprint(&buf, fset, file) - if err != nil { - return nil, err - } - return buf.Bytes(), nil - } - - // Partial source file. - // Determine and prepend leading space. - i, j := 0, 0 - for j < len(src) && isSpace(src[j]) { - if src[j] == '\n' { - i = j + 1 // byte offset of last line in leading space - } - j++ - } - var res []byte - res = append(res, src[:i]...) - - // Determine and prepend indentation of first code line. - // Spaces are ignored unless there are no tabs, - // in which case spaces count as one tab. - indent := 0 - hasSpace := false - for _, b := range src[i:j] { - switch b { - case ' ': - hasSpace = true - case '\t': - indent++ - } - } - if indent == 0 && hasSpace { - indent = 1 - } - for i := 0; i < indent; i++ { - res = append(res, '\t') - } - - // Format the source. - // Write it without any leading and trailing space. - cfg.Indent = indent + indentAdj - var buf bytes.Buffer - err := cfg.Fprint(&buf, fset, file) - if err != nil { - return nil, err - } - res = append(res, sourceAdj(buf.Bytes(), cfg.Indent)...) - - // Determine and append trailing space. - i = len(src) - for i > 0 && isSpace(src[i-1]) { - i-- - } - return append(res, src[i:]...), nil -} - -func isSpace(b byte) bool { - return b == ' ' || b == '\t' || b == '\n' || b == '\r' -} diff --git a/libgo/go/cmd/gofmt/long_test.go b/libgo/go/cmd/gofmt/long_test.go index 237b86021bf..df9a878df44 100644 --- a/libgo/go/cmd/gofmt/long_test.go +++ b/libgo/go/cmd/gofmt/long_test.go @@ -15,6 +15,7 @@ import ( "go/ast" "go/printer" "go/token" + "internal/format" "io" "os" "path/filepath" @@ -32,7 +33,7 @@ var ( ) func gofmt(fset *token.FileSet, filename string, src *bytes.Buffer) error { - f, _, _, err := parse(fset, filename, src.Bytes(), false) + f, _, _, err := format.Parse(fset, filename, src.Bytes(), false) if err != nil { return err } @@ -60,7 +61,7 @@ func testFile(t *testing.T, b1, b2 *bytes.Buffer, filename string) { // exclude files w/ syntax errors (typically test cases) fset := token.NewFileSet() - if _, _, _, err = parse(fset, filename, b1.Bytes(), false); err != nil { + if _, _, _, err = format.Parse(fset, filename, b1.Bytes(), false); err != nil { if *verbose { fmt.Fprintf(os.Stderr, "ignoring %s\n", err) } diff --git a/libgo/go/cmd/gofmt/rewrite.go b/libgo/go/cmd/gofmt/rewrite.go index d267cfcc1dc..069f96622ca 100644 --- a/libgo/go/cmd/gofmt/rewrite.go +++ b/libgo/go/cmd/gofmt/rewrite.go @@ -154,7 +154,7 @@ func isWildcard(s string) bool { return size == len(s) && unicode.IsLower(rune) } -// match returns true if pattern matches val, +// match reports whether pattern matches val, // recording wildcard submatches in m. // If m == nil, match checks whether pattern == val. func match(m map[string]reflect.Value, pattern, val reflect.Value) bool { diff --git a/libgo/go/compress/bzip2/bzip2.go b/libgo/go/compress/bzip2/bzip2.go index 15575d22023..68979572708 100644 --- a/libgo/go/compress/bzip2/bzip2.go +++ b/libgo/go/compress/bzip2/bzip2.go @@ -353,7 +353,7 @@ func (bz2 *reader) readBlock() (err error) { // variables accumulate the repeat count. See the Wikipedia page for // details. repeat := 0 - repeat_power := 0 + repeatPower := 0 // The `C' array (used by the inverse BWT) needs to be zero initialized. for i := range bz2.c { @@ -380,10 +380,10 @@ func (bz2 *reader) readBlock() (err error) { if v < 2 { // This is either the RUNA or RUNB symbol. if repeat == 0 { - repeat_power = 1 + repeatPower = 1 } - repeat += repeat_power << v - repeat_power <<= 1 + repeat += repeatPower << v + repeatPower <<= 1 // This limit of 2 million comes from the bzip2 source // code. It prevents repeat from overflowing. diff --git a/libgo/go/compress/bzip2/bzip2_test.go b/libgo/go/compress/bzip2/bzip2_test.go index fb79d089eb3..77c50dfe948 100644 --- a/libgo/go/compress/bzip2/bzip2_test.go +++ b/libgo/go/compress/bzip2/bzip2_test.go @@ -200,7 +200,7 @@ func BenchmarkDecodeDigits(b *testing.B) { benchmarkDecode(b, digits) } func BenchmarkDecodeTwain(b *testing.B) { benchmarkDecode(b, twain) } func TestBufferOverrun(t *testing.T) { - // Tests https://code.google.com/p/go/issues/detail?id=5747. + // Tests https://golang.org/issue/5747. buffer := bytes.NewReader([]byte(bufferOverrunBase64)) decoder := base64.NewDecoder(base64.StdEncoding, buffer) decompressor := NewReader(decoder) @@ -209,7 +209,7 @@ func TestBufferOverrun(t *testing.T) { } func TestOutOfRangeSelector(t *testing.T) { - // Tests https://code.google.com/p/go/issues/detail?id=8363. + // Tests https://golang.org/issue/8363. buffer := bytes.NewReader(outOfRangeSelector) decompressor := NewReader(buffer) // This shouldn't panic. diff --git a/libgo/go/compress/flate/deflate.go b/libgo/go/compress/flate/deflate.go index 8c79df0c607..169a0c7b2eb 100644 --- a/libgo/go/compress/flate/deflate.go +++ b/libgo/go/compress/flate/deflate.go @@ -24,7 +24,7 @@ const ( maxMatchLength = 258 // The longest match for the compressor minOffsetSize = 1 // The shortest offset that makes any sense - // The maximum number of tokens we put into a single flat block, just too + // The maximum number of tokens we put into a single flat block, just to // stop things from getting too large. maxFlateBlockTokens = 1 << 14 maxStoreBlockSize = 65535 diff --git a/libgo/go/compress/flate/deflate_test.go b/libgo/go/compress/flate/deflate_test.go index 730234c3850..d5d6e732cf1 100644 --- a/libgo/go/compress/flate/deflate_test.go +++ b/libgo/go/compress/flate/deflate_test.go @@ -407,7 +407,7 @@ func TestWriterDict(t *testing.T) { } } -// See http://code.google.com/p/go/issues/detail?id=2508 +// See https://golang.org/issue/2508 func TestRegression2508(t *testing.T) { if testing.Short() { t.Logf("test disabled with -short") diff --git a/libgo/go/compress/flate/flate_test.go b/libgo/go/compress/flate/flate_test.go index 06876632335..3f67025cd76 100644 --- a/libgo/go/compress/flate/flate_test.go +++ b/libgo/go/compress/flate/flate_test.go @@ -10,29 +10,18 @@ package flate import ( "bytes" + "encoding/hex" + "io/ioutil" "testing" ) -func TestUncompressedSource(t *testing.T) { - decoder := NewReader(bytes.NewReader([]byte{0x01, 0x01, 0x00, 0xfe, 0xff, 0x11})) - output := make([]byte, 1) - n, error := decoder.Read(output) - if n != 1 || error != nil { - t.Fatalf("decoder.Read() = %d, %v, want 1, nil", n, error) - } - if output[0] != 0x11 { - t.Errorf("output[0] = %x, want 0x11", output[0]) - } -} - // The following test should not panic. func TestIssue5915(t *testing.T) { bits := []int{4, 0, 0, 6, 4, 3, 2, 3, 3, 4, 4, 5, 0, 0, 0, 0, 5, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 6, 0, 11, 0, 8, 0, 6, 6, 10, 8} - h := new(huffmanDecoder) - ok := h.init(bits) - if ok == true { + var h huffmanDecoder + if h.init(bits) { t.Fatalf("Given sequence of bits is bad, and should not succeed.") } } @@ -41,9 +30,8 @@ func TestIssue5915(t *testing.T) { func TestIssue5962(t *testing.T) { bits := []int{4, 0, 0, 6, 4, 3, 2, 3, 3, 4, 4, 5, 0, 0, 0, 0, 5, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11} - h := new(huffmanDecoder) - ok := h.init(bits) - if ok == true { + var h huffmanDecoder + if h.init(bits) { t.Fatalf("Given sequence of bits is bad, and should not succeed.") } } @@ -52,7 +40,7 @@ func TestIssue5962(t *testing.T) { func TestIssue6255(t *testing.T) { bits1 := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 11} bits2 := []int{11, 13} - h := new(huffmanDecoder) + var h huffmanDecoder if !h.init(bits1) { t.Fatalf("Given sequence of bits is good and should succeed.") } @@ -60,3 +48,213 @@ func TestIssue6255(t *testing.T) { t.Fatalf("Given sequence of bits is bad and should not succeed.") } } + +func TestInvalidEncoding(t *testing.T) { + // Initialize Huffman decoder to recognize "0". + var h huffmanDecoder + if !h.init([]int{1}) { + t.Fatal("Failed to initialize Huffman decoder") + } + + // Initialize decompressor with invalid Huffman coding. + var f decompressor + f.r = bytes.NewReader([]byte{0xff}) + + _, err := f.huffSym(&h) + if err == nil { + t.Fatal("Should have rejected invalid bit sequence") + } +} + +func TestInvalidBits(t *testing.T) { + oversubscribed := []int{1, 2, 3, 4, 4, 5} + incomplete := []int{1, 2, 4, 4} + var h huffmanDecoder + if h.init(oversubscribed) { + t.Fatal("Should reject oversubscribed bit-length set") + } + if h.init(incomplete) { + t.Fatal("Should reject incomplete bit-length set") + } +} + +func TestStreams(t *testing.T) { + // To verify any of these hexstrings as valid or invalid flate streams + // according to the C zlib library, you can use the Python wrapper library: + // >>> hex_string = "010100feff11" + // >>> import zlib + // >>> zlib.decompress(hex_string.decode("hex"), -15) # Negative means raw DEFLATE + // '\x11' + + testCases := []struct { + desc string // Description of the stream + stream string // Hexstring of the input DEFLATE stream + want string // Expected result. Use "fail" to expect failure + }{{ + "degenerate HCLenTree", + "05e0010000000000100000000000000000000000000000000000000000000000" + + "00000000000000000004", + "fail", + }, { + "complete HCLenTree, empty HLitTree, empty HDistTree", + "05e0010400000000000000000000000000000000000000000000000000000000" + + "00000000000000000010", + "fail", + }, { + "empty HCLenTree", + "05e0010000000000000000000000000000000000000000000000000000000000" + + "00000000000000000010", + "fail", + }, { + "complete HCLenTree, complete HLitTree, empty HDistTree, use missing HDist symbol", + "000100feff000de0010400000000100000000000000000000000000000000000" + + "0000000000000000000000000000002c", + "fail", + }, { + "complete HCLenTree, complete HLitTree, degenerate HDistTree, use missing HDist symbol", + "000100feff000de0010000000000000000000000000000000000000000000000" + + "00000000000000000610000000004070", + "fail", + }, { + "complete HCLenTree, empty HLitTree, empty HDistTree", + "05e0010400000000100400000000000000000000000000000000000000000000" + + "0000000000000000000000000008", + "fail", + }, { + "complete HCLenTree, empty HLitTree, degenerate HDistTree", + "05e0010400000000100400000000000000000000000000000000000000000000" + + "0000000000000000000800000008", + "fail", + }, { + "complete HCLenTree, degenerate HLitTree, degenerate HDistTree, use missing HLit symbol", + "05e0010400000000100000000000000000000000000000000000000000000000" + + "0000000000000000001c", + "fail", + }, { + "complete HCLenTree, complete HLitTree, too large HDistTree", + "edff870500000000200400000000000000000000000000000000000000000000" + + "000000000000000000080000000000000004", + "fail", + }, { + "complete HCLenTree, complete HLitTree, empty HDistTree, excessive repeater code", + "edfd870500000000200400000000000000000000000000000000000000000000" + + "000000000000000000e8b100", + "fail", + }, { + "complete HCLenTree, complete HLitTree, empty HDistTree of normal length 30", + "05fd01240000000000f8ffffffffffffffffffffffffffffffffffffffffffff" + + "ffffffffffffffffff07000000fe01", + "", + }, { + "complete HCLenTree, complete HLitTree, empty HDistTree of excessive length 31", + "05fe01240000000000f8ffffffffffffffffffffffffffffffffffffffffffff" + + "ffffffffffffffffff07000000fc03", + "fail", + }, { + "complete HCLenTree, over-subscribed HLitTree, empty HDistTree", + "05e001240000000000fcffffffffffffffffffffffffffffffffffffffffffff" + + "ffffffffffffffffff07f00f", + "fail", + }, { + "complete HCLenTree, under-subscribed HLitTree, empty HDistTree", + "05e001240000000000fcffffffffffffffffffffffffffffffffffffffffffff" + + "fffffffffcffffffff07f00f", + "fail", + }, { + "complete HCLenTree, complete HLitTree with single code, empty HDistTree", + "05e001240000000000f8ffffffffffffffffffffffffffffffffffffffffffff" + + "ffffffffffffffffff07f00f", + "01", + }, { + "complete HCLenTree, complete HLitTree with multiple codes, empty HDistTree", + "05e301240000000000f8ffffffffffffffffffffffffffffffffffffffffffff" + + "ffffffffffffffffff07807f", + "01", + }, { + "complete HCLenTree, complete HLitTree, degenerate HDistTree, use valid HDist symbol", + "000100feff000de0010400000000100000000000000000000000000000000000" + + "0000000000000000000000000000003c", + "00000000", + }, { + "complete HCLenTree, degenerate HLitTree, degenerate HDistTree", + "05e0010400000000100000000000000000000000000000000000000000000000" + + "0000000000000000000c", + "", + }, { + "complete HCLenTree, degenerate HLitTree, empty HDistTree", + "05e0010400000000100000000000000000000000000000000000000000000000" + + "00000000000000000004", + "", + }, { + "complete HCLenTree, complete HLitTree, empty HDistTree, spanning repeater code", + "edfd870500000000200400000000000000000000000000000000000000000000" + + "000000000000000000e8b000", + "", + }, { + "complete HCLenTree with length codes, complete HLitTree, empty HDistTree", + "ede0010400000000100000000000000000000000000000000000000000000000" + + "0000000000000000000400004000", + "", + }, { + "complete HCLenTree, complete HLitTree, degenerate HDistTree, use valid HLit symbol 284 with count 31", + "000100feff00ede0010400000000100000000000000000000000000000000000" + + "000000000000000000000000000000040000407f00", + "0000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "000000", + }, { + "complete HCLenTree, complete HLitTree, degenerate HDistTree, use valid HLit and HDist symbols", + "0cc2010d00000082b0ac4aff0eb07d27060000ffff", + "616263616263", + }, { + "fixed block, use reserved symbol 287", + "33180700", + "fail", + }, { + "raw block", + "010100feff11", + "11", + }, { + "issue 10426 - over-subscribed HCLenTree causes a hang", + "344c4a4e494d4b070000ff2e2eff2e2e2e2e2eff", + "fail", + }, { + "issue 11030 - empty HDistTree unexpectedly leads to error", + "05c0070600000080400fff37a0ca", + "", + }, { + "issue 11033 - empty HDistTree unexpectedly leads to error", + "050fb109c020cca5d017dcbca044881ee1034ec149c8980bbc413c2ab35be9dc" + + "b1473449922449922411202306ee97b0383a521b4ffdcf3217f9f7d3adb701", + "3130303634342068652e706870005d05355f7ed957ff084a90925d19e3ebc6d0" + + "c6d7", + }} + + for i, tc := range testCases { + data, err := hex.DecodeString(tc.stream) + if err != nil { + t.Fatal(err) + } + data, err = ioutil.ReadAll(NewReader(bytes.NewReader(data))) + if tc.want == "fail" { + if err == nil { + t.Errorf("#%d (%s): got nil error, want non-nil", i, tc.desc) + } + } else { + if err != nil { + t.Errorf("#%d (%s): %v", i, tc.desc, err) + continue + } + if got := hex.EncodeToString(data); got != tc.want { + t.Errorf("#%d (%s):\ngot %q\nwant %q", i, tc.desc, got, tc.want) + } + + } + } +} diff --git a/libgo/go/compress/flate/gen.go b/libgo/go/compress/flate/gen.go index 6288ecddd0e..154c89a488e 100644 --- a/libgo/go/compress/flate/gen.go +++ b/libgo/go/compress/flate/gen.go @@ -45,7 +45,20 @@ type huffmanDecoder struct { } // Initialize Huffman decoding tables from array of code lengths. +// Following this function, h is guaranteed to be initialized into a complete +// tree (i.e., neither over-subscribed nor under-subscribed). The exception is a +// degenerate case where the tree has only a single symbol with length 1. Empty +// trees are permitted. func (h *huffmanDecoder) init(bits []int) bool { + // Sanity enables additional runtime tests during Huffman + // table construction. It's intended to be used during + // development to supplement the currently ad-hoc unit tests. + const sanity = false + + if h.min != 0 { + *h = huffmanDecoder{} + } + // Count number of codes of each length, // compute min and max length. var count [maxCodeLen]int @@ -62,37 +75,53 @@ func (h *huffmanDecoder) init(bits []int) bool { } count[n]++ } + + // Empty tree. The decompressor.huffSym function will fail later if the tree + // is used. Technically, an empty tree is only valid for the HDIST tree and + // not the HCLEN and HLIT tree. However, a stream with an empty HCLEN tree + // is guaranteed to fail since it will attempt to use the tree to decode the + // codes for the HLIT and HDIST trees. Similarly, an empty HLIT tree is + // guaranteed to fail later since the compressed data section must be + // composed of at least one symbol (the end-of-block marker). if max == 0 { + return true + } + + code := 0 + var nextcode [maxCodeLen]int + for i := min; i <= max; i++ { + code <<= 1 + nextcode[i] = code + code += count[i] + } + + // Check that the coding is complete (i.e., that we've + // assigned all 2-to-the-max possible bit sequences). + // Exception: To be compatible with zlib, we also need to + // accept degenerate single-code codings. See also + // TestDegenerateHuffmanCoding. + if code != 1< huffmanChunkBits { - linkBits = uint(max) - huffmanChunkBits - numLinks = 1 << linkBits + numLinks := 1 << (uint(max) - huffmanChunkBits) h.linkMask = uint32(numLinks - 1) - } - code := 0 - var nextcode [maxCodeLen]int - for i := min; i <= max; i++ { - if i == huffmanChunkBits+1 { - // create link tables - link := code >> 1 - h.links = make([][]uint32, huffmanNumChunks-link) - for j := uint(link); j < huffmanNumChunks; j++ { - reverse := int(reverseByte[j>>8]) | int(reverseByte[j&0xff])<<8 - reverse >>= uint(16 - huffmanChunkBits) - off := j - uint(link) - h.chunks[reverse] = uint32(off<> 1 + h.links = make([][]uint32, huffmanNumChunks-link) + for j := uint(link); j < huffmanNumChunks; j++ { + reverse := int(reverseByte[j>>8]) | int(reverseByte[j&0xff])<<8 + reverse >>= uint(16 - huffmanChunkBits) + off := j - uint(link) + if sanity && h.chunks[reverse] != 0 { + panic("impossible: overwriting existing chunk") } + h.chunks[reverse] = uint32(off<>8]) | int(reverseByte[code&0xff])<<8 reverse >>= uint(16 - n) if n <= huffmanChunkBits { - for off := reverse; off < huffmanNumChunks; off += 1 << uint(n) { + for off := reverse; off < len(h.chunks); off += 1 << uint(n) { + // We should never need to overwrite + // an existing chunk. Also, 0 is + // never a valid chunk, because the + // lower 4 "count" bits should be + // between 1 and 15. + if sanity && h.chunks[off] != 0 { + panic("impossible: overwriting existing chunk") + } h.chunks[off] = chunk } } else { - linktab := h.links[h.chunks[reverse&(huffmanNumChunks-1)]>>huffmanValueShift] + j := reverse & (huffmanNumChunks - 1) + if sanity && h.chunks[j]&huffmanCountMask != huffmanChunkBits+1 { + // Longer codes should have been + // associated with a link table above. + panic("impossible: not an indirect chunk") + } + value := h.chunks[j] >> huffmanValueShift + linktab := h.links[value] reverse >>= huffmanChunkBits - for off := reverse; off < numLinks; off += 1 << uint(n-huffmanChunkBits) { + for off := reverse; off < len(linktab); off += 1 << uint(n-huffmanChunkBits) { + if sanity && linktab[off] != 0 { + panic("impossible: overwriting existing chunk") + } linktab[off] = chunk } } } + + if sanity { + // Above we've sanity checked that we never overwrote + // an existing entry. Here we additionally check that + // we filled the tables completely. + for i, chunk := range h.chunks { + if chunk == 0 { + // As an exception, in the degenerate + // single-code case, we allow odd + // chunks to be missing. + if code == 1 && i%2 == 1 { + continue + } + panic("impossible: missing chunk") + } + } + for _, linktab := range h.links { + for _, chunk := range linktab { + if chunk == 0 { + panic("impossible: missing chunk") + } + } + } + } + return true } @@ -138,6 +210,9 @@ func main() { bits[i] = 8 } h.init(bits[:]) + if h.links != nil { + log.Fatal("Unexpected links table in fixed Huffman decoder") + } var buf bytes.Buffer diff --git a/libgo/go/compress/flate/huffman_bit_writer.go b/libgo/go/compress/flate/huffman_bit_writer.go index b182a710b9a..616440412e4 100644 --- a/libgo/go/compress/flate/huffman_bit_writer.go +++ b/libgo/go/compress/flate/huffman_bit_writer.go @@ -87,11 +87,11 @@ type huffmanBitWriter struct { func newHuffmanBitWriter(w io.Writer) *huffmanBitWriter { return &huffmanBitWriter{ w: w, - literalFreq: make([]int32, maxLit), + literalFreq: make([]int32, maxNumLit), offsetFreq: make([]int32, offsetCodeCount), - codegen: make([]uint8, maxLit+offsetCodeCount+1), + codegen: make([]uint8, maxNumLit+offsetCodeCount+1), codegenFreq: make([]int32, codegenCodeCount), - literalEncoding: newHuffmanEncoder(maxLit), + literalEncoding: newHuffmanEncoder(maxNumLit), offsetEncoding: newHuffmanEncoder(offsetCodeCount), codegenEncoding: newHuffmanEncoder(codegenCodeCount), } diff --git a/libgo/go/compress/flate/huffman_code.go b/libgo/go/compress/flate/huffman_code.go index 3b9fce466ed..50ec79c9405 100644 --- a/libgo/go/compress/flate/huffman_code.go +++ b/libgo/go/compress/flate/huffman_code.go @@ -47,11 +47,11 @@ func newHuffmanEncoder(size int) *huffmanEncoder { // Generates a HuffmanCode corresponding to the fixed literal table func generateFixedLiteralEncoding() *huffmanEncoder { - h := newHuffmanEncoder(maxLit) + h := newHuffmanEncoder(maxNumLit) codeBits := h.codeBits code := h.code var ch uint16 - for ch = 0; ch < maxLit; ch++ { + for ch = 0; ch < maxNumLit; ch++ { var bits uint16 var size uint8 switch { diff --git a/libgo/go/compress/flate/inflate.go b/libgo/go/compress/flate/inflate.go index 76519bbf427..04372dec241 100644 --- a/libgo/go/compress/flate/inflate.go +++ b/libgo/go/compress/flate/inflate.go @@ -18,10 +18,12 @@ import ( const ( maxCodeLen = 16 // max length of Huffman code maxHist = 32768 // max history required - // The next three numbers come from the RFC, section 3.2.7. - maxLit = 286 - maxDist = 32 - numCodes = 19 // number of codes in Huffman meta-code + // The next three numbers come from the RFC section 3.2.7, with the + // additional proviso in section 3.2.5 which implies that distance codes + // 30 and 31 should never occur in compressed data. + maxNumLit = 286 + maxNumDist = 30 + numCodes = 19 // number of codes in Huffman meta-code ) // A CorruptInputError reports the presence of corrupt input at a given offset. @@ -101,7 +103,16 @@ type huffmanDecoder struct { } // Initialize Huffman decoding tables from array of code lengths. +// Following this function, h is guaranteed to be initialized into a complete +// tree (i.e., neither over-subscribed nor under-subscribed). The exception is a +// degenerate case where the tree has only a single symbol with length 1. Empty +// trees are permitted. func (h *huffmanDecoder) init(bits []int) bool { + // Sanity enables additional runtime tests during Huffman + // table construction. It's intended to be used during + // development to supplement the currently ad-hoc unit tests. + const sanity = false + if h.min != 0 { *h = huffmanDecoder{} } @@ -122,40 +133,53 @@ func (h *huffmanDecoder) init(bits []int) bool { } count[n]++ } + + // Empty tree. The decompressor.huffSym function will fail later if the tree + // is used. Technically, an empty tree is only valid for the HDIST tree and + // not the HCLEN and HLIT tree. However, a stream with an empty HCLEN tree + // is guaranteed to fail since it will attempt to use the tree to decode the + // codes for the HLIT and HDIST trees. Similarly, an empty HLIT tree is + // guaranteed to fail later since the compressed data section must be + // composed of at least one symbol (the end-of-block marker). if max == 0 { + return true + } + + code := 0 + var nextcode [maxCodeLen]int + for i := min; i <= max; i++ { + code <<= 1 + nextcode[i] = code + code += count[i] + } + + // Check that the coding is complete (i.e., that we've + // assigned all 2-to-the-max possible bit sequences). + // Exception: To be compatible with zlib, we also need to + // accept degenerate single-code codings. See also + // TestDegenerateHuffmanCoding. + if code != 1< huffmanChunkBits { - linkBits = uint(max) - huffmanChunkBits - numLinks = 1 << linkBits + numLinks := 1 << (uint(max) - huffmanChunkBits) h.linkMask = uint32(numLinks - 1) - } - code := 0 - var nextcode [maxCodeLen]int - for i := min; i <= max; i++ { - if i == huffmanChunkBits+1 { - // create link tables - link := code >> 1 - if huffmanNumChunks < link { - return false - } - h.links = make([][]uint32, huffmanNumChunks-link) - for j := uint(link); j < huffmanNumChunks; j++ { - reverse := int(reverseByte[j>>8]) | int(reverseByte[j&0xff])<<8 - reverse >>= uint(16 - huffmanChunkBits) - off := j - uint(link) - h.chunks[reverse] = uint32(off<> 1 + h.links = make([][]uint32, huffmanNumChunks-link) + for j := uint(link); j < huffmanNumChunks; j++ { + reverse := int(reverseByte[j>>8]) | int(reverseByte[j&0xff])<<8 + reverse >>= uint(16 - huffmanChunkBits) + off := j - uint(link) + if sanity && h.chunks[reverse] != 0 { + panic("impossible: overwriting existing chunk") } + h.chunks[reverse] = uint32(off<>8]) | int(reverseByte[code&0xff])<<8 reverse >>= uint(16 - n) if n <= huffmanChunkBits { - for off := reverse; off < huffmanNumChunks; off += 1 << uint(n) { + for off := reverse; off < len(h.chunks); off += 1 << uint(n) { + // We should never need to overwrite + // an existing chunk. Also, 0 is + // never a valid chunk, because the + // lower 4 "count" bits should be + // between 1 and 15. + if sanity && h.chunks[off] != 0 { + panic("impossible: overwriting existing chunk") + } h.chunks[off] = chunk } } else { - value := h.chunks[reverse&(huffmanNumChunks-1)] >> huffmanValueShift - if value >= uint32(len(h.links)) { - return false + j := reverse & (huffmanNumChunks - 1) + if sanity && h.chunks[j]&huffmanCountMask != huffmanChunkBits+1 { + // Longer codes should have been + // associated with a link table above. + panic("impossible: not an indirect chunk") } + value := h.chunks[j] >> huffmanValueShift linktab := h.links[value] reverse >>= huffmanChunkBits - for off := reverse; off < numLinks; off += 1 << uint(n-huffmanChunkBits) { + for off := reverse; off < len(linktab); off += 1 << uint(n-huffmanChunkBits) { + if sanity && linktab[off] != 0 { + panic("impossible: overwriting existing chunk") + } linktab[off] = chunk } } } + + if sanity { + // Above we've sanity checked that we never overwrote + // an existing entry. Here we additionally check that + // we filled the tables completely. + for i, chunk := range h.chunks { + if chunk == 0 { + // As an exception, in the degenerate + // single-code case, we allow odd + // chunks to be missing. + if code == 1 && i%2 == 1 { + continue + } + panic("impossible: missing chunk") + } + } + for _, linktab := range h.links { + for _, chunk := range linktab { + if chunk == 0 { + panic("impossible: missing chunk") + } + } + } + } + return true } @@ -209,7 +272,7 @@ type decompressor struct { h1, h2 huffmanDecoder // Length arrays used to define Huffman codes. - bits *[maxLit + maxDist]int + bits *[maxNumLit + maxNumDist]int codebits *[numCodes]int // Output history, buffer. @@ -307,12 +370,14 @@ func (f *decompressor) readHuffman() error { } } nlit := int(f.b&0x1F) + 257 - if nlit > maxLit { + if nlit > maxNumLit { return CorruptInputError(f.roffset) } f.b >>= 5 ndist := int(f.b&0x1F) + 1 - // maxDist is 32, so ndist is always valid. + if ndist > maxNumDist { + return CorruptInputError(f.roffset) + } f.b >>= 5 nclen := int(f.b&0xF) + 4 // numCodes is 19, so nclen is always valid. @@ -443,9 +508,12 @@ func (f *decompressor) huffmanBlock() { case v < 285: length = v*32 - (281*32 - 131) n = 5 - default: + case v < maxNumLit: length = 258 n = 0 + default: + f.err = CorruptInputError(f.roffset) + return } if n > 0 { for f.nb < n { @@ -480,10 +548,7 @@ func (f *decompressor) huffmanBlock() { switch { case dist < 4: dist++ - case dist >= 30: - f.err = CorruptInputError(f.roffset) - return - default: + case dist < maxNumDist: nb := uint(dist-2) >> 1 // have 1 bit in bottom of dist, need nb more. extra := (dist & 1) << nb @@ -497,6 +562,9 @@ func (f *decompressor) huffmanBlock() { f.b >>= nb f.nb -= nb dist = 1<<(nb+1) + 1 + extra + default: + f.err = CorruptInputError(f.roffset) + return } // Copy history[-dist:-dist+length] into output. @@ -643,6 +711,10 @@ func (f *decompressor) moreBits() error { // Read the next Huffman-encoded symbol from f according to h. func (f *decompressor) huffSym(h *huffmanDecoder) (int, error) { + // Since a huffmanDecoder can be empty or be composed of a degenerate tree + // with single element, huffSym must error on these two edge cases. In both + // cases, the chunks slice will be 0 for the invalid sequence, leading it + // satisfy the n == 0 check below. n := uint(h.min) for { for f.nb < n { @@ -655,12 +727,12 @@ func (f *decompressor) huffSym(h *huffmanDecoder) (int, error) { if n > huffmanChunkBits { chunk = h.links[chunk>>huffmanValueShift][(f.b>>huffmanChunkBits)&h.linkMask] n = uint(chunk & huffmanCountMask) + } + if n <= f.nb { if n == 0 { f.err = CorruptInputError(f.roffset) return 0, f.err } - } - if n <= f.nb { f.b >>= n f.nb -= n return int(chunk >> huffmanValueShift), nil @@ -712,7 +784,7 @@ func (f *decompressor) Reset(r io.Reader, dict []byte) error { // The ReadCloser returned by NewReader also implements Resetter. func NewReader(r io.Reader) io.ReadCloser { var f decompressor - f.bits = new([maxLit + maxDist]int) + f.bits = new([maxNumLit + maxNumDist]int) f.codebits = new([numCodes]int) f.r = makeReader(r) f.hist = new([maxHist]byte) @@ -731,7 +803,7 @@ func NewReaderDict(r io.Reader, dict []byte) io.ReadCloser { var f decompressor f.r = makeReader(r) f.hist = new([maxHist]byte) - f.bits = new([maxLit + maxDist]int) + f.bits = new([maxNumLit + maxNumDist]int) f.codebits = new([numCodes]int) f.step = (*decompressor).nextBlock f.setDict(dict) diff --git a/libgo/go/compress/lzw/reader.go b/libgo/go/compress/lzw/reader.go index 526620c8271..1353831eca9 100644 --- a/libgo/go/compress/lzw/reader.go +++ b/libgo/go/compress/lzw/reader.go @@ -139,6 +139,7 @@ func (d *decoder) decode() { err = io.ErrUnexpectedEOF } d.err = err + d.flush() return } switch { @@ -190,6 +191,7 @@ func (d *decoder) decode() { } default: d.err = errors.New("lzw: invalid code") + d.flush() return } d.last, d.hi = code, d.hi+1 @@ -213,7 +215,7 @@ func (d *decoder) flush() { d.o = 0 } -var errClosed = errors.New("compress/lzw: reader/writer is closed") +var errClosed = errors.New("lzw: reader/writer is closed") func (d *decoder) Close() error { d.err = errClosed // in case any Reads come along @@ -227,7 +229,8 @@ func (d *decoder) Close() error { // It is the caller's responsibility to call Close on the ReadCloser when // finished reading. // The number of bits to use for literal codes, litWidth, must be in the -// range [2,8] and is typically 8. +// range [2,8] and is typically 8. It must equal the litWidth +// used during compression. func NewReader(r io.Reader, order Order, litWidth int) io.ReadCloser { d := new(decoder) switch order { diff --git a/libgo/go/compress/lzw/reader_test.go b/libgo/go/compress/lzw/reader_test.go index 9006c91c233..c3a5c3a0aaa 100644 --- a/libgo/go/compress/lzw/reader_test.go +++ b/libgo/go/compress/lzw/reader_test.go @@ -98,13 +98,20 @@ func TestReader(t *testing.T) { defer rc.Close() b.Reset() n, err := io.Copy(&b, rc) + s := b.String() if err != nil { if err != tt.err { t.Errorf("%s: io.Copy: %v want %v", tt.desc, err, tt.err) } + if err == io.ErrUnexpectedEOF { + // Even if the input is truncated, we should still return the + // partial decoded result. + if n == 0 || !strings.HasPrefix(tt.raw, s) { + t.Errorf("got %d bytes (%q), want a non-empty prefix of %q", n, s, tt.raw) + } + } continue } - s := b.String() if s != tt.raw { t.Errorf("%s: got %d-byte %q want %d-byte %q", tt.desc, n, s, len(tt.raw), tt.raw) } diff --git a/libgo/go/compress/lzw/writer.go b/libgo/go/compress/lzw/writer.go index 961b25f94f5..7367c29651d 100644 --- a/libgo/go/compress/lzw/writer.go +++ b/libgo/go/compress/lzw/writer.go @@ -138,16 +138,23 @@ func (e *encoder) Write(p []byte) (n int, err error) { if len(p) == 0 { return 0, nil } + if maxLit := uint8(1< maxLit { + e.err = errors.New("lzw: input byte too large for the litWidth") + return 0, e.err + } + } + } n = len(p) - litMask := uint32(1<= 1<<2: got nil error, want non-nil") + } +} + func benchmarkEncoder(b *testing.B, n int) { b.StopTimer() b.SetBytes(int64(n)) diff --git a/libgo/go/crypto/cipher/cipher.go b/libgo/go/crypto/cipher/cipher.go index 67afdb1e057..7d27fde61d8 100644 --- a/libgo/go/crypto/cipher/cipher.go +++ b/libgo/go/crypto/cipher/cipher.go @@ -29,6 +29,9 @@ type Block interface { type Stream interface { // XORKeyStream XORs each byte in the given slice with a byte from the // cipher's key stream. Dst and src may point to the same memory. + // If len(dst) < len(src), XORKeyStream should panic. It is acceptable + // to pass a dst bigger than src, and in that case, XORKeyStream will + // only update dst[:len(src)] and will not touch the rest of dst. XORKeyStream(dst, src []byte) } diff --git a/libgo/go/crypto/cipher/gcm.go b/libgo/go/crypto/cipher/gcm.go index bdafd85fc30..bbdf9f5d3df 100644 --- a/libgo/go/crypto/cipher/gcm.go +++ b/libgo/go/crypto/cipher/gcm.go @@ -52,14 +52,26 @@ type gcmFieldElement struct { // gcm represents a Galois Counter Mode with a specific key. See // http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-revised-spec.pdf type gcm struct { - cipher Block + cipher Block + nonceSize int // productTable contains the first sixteen powers of the key, H. - // However, they are in bit reversed order. See NewGCM. + // However, they are in bit reversed order. See NewGCMWithNonceSize. productTable [16]gcmFieldElement } -// NewGCM returns the given 128-bit, block cipher wrapped in Galois Counter Mode. +// NewGCM returns the given 128-bit, block cipher wrapped in Galois Counter Mode +// with the standard nonce length. func NewGCM(cipher Block) (AEAD, error) { + return NewGCMWithNonceSize(cipher, gcmStandardNonceSize) +} + +// NewGCMWithNonceSize returns the given 128-bit, block cipher wrapped in Galois +// Counter Mode, which accepts nonces of the given length. +// +// Only use this function if you require compatibility with an existing +// cryptosystem that uses non-standard nonce lengths. All other users should use +// NewGCM, which is faster and more resistant to misuse. +func NewGCMWithNonceSize(cipher Block, size int) (AEAD, error) { if cipher.BlockSize() != gcmBlockSize { return nil, errors.New("cipher: NewGCM requires 128-bit block cipher") } @@ -67,7 +79,7 @@ func NewGCM(cipher Block) (AEAD, error) { var key [gcmBlockSize]byte cipher.Encrypt(key[:], key[:]) - g := &gcm{cipher: cipher} + g := &gcm{cipher: cipher, nonceSize: size} // We precompute 16 multiples of |key|. However, when we do lookups // into this table we'll be using bits from a field element and @@ -89,13 +101,13 @@ func NewGCM(cipher Block) (AEAD, error) { } const ( - gcmBlockSize = 16 - gcmTagSize = 16 - gcmNonceSize = 12 + gcmBlockSize = 16 + gcmTagSize = 16 + gcmStandardNonceSize = 12 ) -func (*gcm) NonceSize() int { - return gcmNonceSize +func (g *gcm) NonceSize() int { + return g.nonceSize } func (*gcm) Overhead() int { @@ -103,16 +115,13 @@ func (*gcm) Overhead() int { } func (g *gcm) Seal(dst, nonce, plaintext, data []byte) []byte { - if len(nonce) != gcmNonceSize { + if len(nonce) != g.nonceSize { panic("cipher: incorrect nonce length given to GCM") } - ret, out := sliceForAppend(dst, len(plaintext)+gcmTagSize) - // See GCM spec, section 7.1. var counter, tagMask [gcmBlockSize]byte - copy(counter[:], nonce) - counter[gcmBlockSize-1] = 1 + g.deriveCounter(&counter, nonce) g.cipher.Encrypt(tagMask[:], counter[:]) gcmInc32(&counter) @@ -126,7 +135,7 @@ func (g *gcm) Seal(dst, nonce, plaintext, data []byte) []byte { var errOpen = errors.New("cipher: message authentication failed") func (g *gcm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { - if len(nonce) != gcmNonceSize { + if len(nonce) != g.nonceSize { panic("cipher: incorrect nonce length given to GCM") } @@ -136,10 +145,8 @@ func (g *gcm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) { tag := ciphertext[len(ciphertext)-gcmTagSize:] ciphertext = ciphertext[:len(ciphertext)-gcmTagSize] - // See GCM spec, section 7.1. var counter, tagMask [gcmBlockSize]byte - copy(counter[:], nonce) - counter[gcmBlockSize-1] = 1 + g.deriveCounter(&counter, nonce) g.cipher.Encrypt(tagMask[:], counter[:]) gcmInc32(&counter) @@ -198,7 +205,7 @@ var gcmReductionTable = []uint16{ 0xe100, 0xfd20, 0xd940, 0xc560, 0x9180, 0x8da0, 0xa9c0, 0xb5e0, } -// mul sets y to y*H, where H is the GCM key, fixed during NewGCM. +// mul sets y to y*H, where H is the GCM key, fixed during NewGCMWithNonceSize. func (g *gcm) mul(y *gcmFieldElement) { var z gcmFieldElement @@ -219,7 +226,7 @@ func (g *gcm) mul(y *gcmFieldElement) { // the values in |table| are ordered for // little-endian bit positions. See the comment - // in NewGCM. + // in NewGCMWithNonceSize. t := &g.productTable[word&0xf] z.low ^= t.low @@ -301,6 +308,29 @@ func (g *gcm) counterCrypt(out, in []byte, counter *[gcmBlockSize]byte) { } } +// deriveCounter computes the initial GCM counter state from the given nonce. +// See NIST SP 800-38D, section 7.1. This assumes that counter is filled with +// zeros on entry. +func (g *gcm) deriveCounter(counter *[gcmBlockSize]byte, nonce []byte) { + // GCM has two modes of operation with respect to the initial counter + // state: a "fast path" for 96-bit (12-byte) nonces, and a "slow path" + // for nonces of other lengths. For a 96-bit nonce, the nonce, along + // with a four-byte big-endian counter starting at one, is used + // directly as the starting counter. For other nonce sizes, the counter + // is computed by passing it through the GHASH function. + if len(nonce) == gcmStandardNonceSize { + copy(counter[:], nonce) + counter[gcmBlockSize-1] = 1 + } else { + var y gcmFieldElement + g.update(&y, nonce) + y.high ^= uint64(len(nonce)) * 8 + g.mul(&y) + putUint64(counter[:8], y.low) + putUint64(counter[8:], y.high) + } +} + // auth calculates GHASH(ciphertext, additionalData), masks the result with // tagMask and writes the result to out. func (g *gcm) auth(out, ciphertext, additionalData []byte, tagMask *[gcmTagSize]byte) { diff --git a/libgo/go/crypto/cipher/gcm_test.go b/libgo/go/crypto/cipher/gcm_test.go index 0c502ce4059..81b9aa24191 100644 --- a/libgo/go/crypto/cipher/gcm_test.go +++ b/libgo/go/crypto/cipher/gcm_test.go @@ -101,6 +101,35 @@ var aesGCMTests = []struct { "", "b2051c80014f42f08735a7b0cd38e6bcd29962e5f2c13626b85a877101", }, + // These cases test non-standard nonce sizes. + { + "1672c3537afa82004c6b8a46f6f0d026", + "05", + "", + "", + "8e2ad721f9455f74d8b53d3141f27e8e", + }, + { + "9a4fea86a621a91ab371e492457796c0", + "75", + "ca6131faf0ff210e4e693d6c31c109fc5b6f54224eb120f37de31dc59ec669b6", + "4f6e2585c161f05a9ae1f2f894e9f0ab52b45d0f", + "5698c0a384241d30004290aac56bb3ece6fe8eacc5c4be98954deb9c3ff6aebf5d50e1af100509e1fba2a5e8a0af9670", + }, + { + "d0f1f4defa1e8c08b4b26d576392027c", + "42b4f01eb9f5a1ea5b1eb73b0fb0baed54f387ecaa0393c7d7dffc6af50146ecc021abf7eb9038d4303d91f8d741a11743166c0860208bcc02c6258fd9511a2fa626f96d60b72fcff773af4e88e7a923506e4916ecbd814651e9f445adef4ad6a6b6c7290cc13b956130eef5b837c939fcac0cbbcc9656cd75b13823ee5acdac", + "", + "", + "7ab49b57ddf5f62c427950111c5c4f0d", + }, + { + "4a0c00a3d284dea9d4bf8b8dde86685e", + "f8cbe82588e784bcacbe092cd9089b51e01527297f635bf294b3aa787d91057ef23869789698ac960707857f163ecb242135a228ad93964f5dc4a4d7f88fd7b3b07dd0a5b37f9768fb05a523639f108c34c661498a56879e501a2321c8a4a94d7e1b89db255ac1f685e185263368e99735ebe62a7f2931b47282be8eb165e4d7", + "6d4bf87640a6a48a50d28797b7", + "8d8c7ffc55086d539b5a8f0d1232654c", + "0d803ec309482f35b8e6226f2b56303239298e06b281c2d51aaba3c125", + }, } func TestAESGCM(t *testing.T) { @@ -114,7 +143,7 @@ func TestAESGCM(t *testing.T) { nonce, _ := hex.DecodeString(test.nonce) plaintext, _ := hex.DecodeString(test.plaintext) ad, _ := hex.DecodeString(test.ad) - aesgcm, err := cipher.NewGCM(aes) + aesgcm, err := cipher.NewGCMWithNonceSize(aes, len(nonce)) if err != nil { t.Fatal(err) } diff --git a/libgo/go/crypto/crypto.go b/libgo/go/crypto/crypto.go index 59b23e93f5c..184ea9d4d62 100644 --- a/libgo/go/crypto/crypto.go +++ b/libgo/go/crypto/crypto.go @@ -21,36 +21,40 @@ func (h Hash) HashFunc() Hash { } const ( - MD4 Hash = 1 + iota // import golang.org/x/crypto/md4 - MD5 // import crypto/md5 - SHA1 // import crypto/sha1 - SHA224 // import crypto/sha256 - SHA256 // import crypto/sha256 - SHA384 // import crypto/sha512 - SHA512 // import crypto/sha512 - MD5SHA1 // no implementation; MD5+SHA1 used for TLS RSA - RIPEMD160 // import golang.org/x/crypto/ripemd160 - SHA3_224 // import golang.org/x/crypto/sha3 - SHA3_256 // import golang.org/x/crypto/sha3 - SHA3_384 // import golang.org/x/crypto/sha3 - SHA3_512 // import golang.org/x/crypto/sha3 + MD4 Hash = 1 + iota // import golang.org/x/crypto/md4 + MD5 // import crypto/md5 + SHA1 // import crypto/sha1 + SHA224 // import crypto/sha256 + SHA256 // import crypto/sha256 + SHA384 // import crypto/sha512 + SHA512 // import crypto/sha512 + MD5SHA1 // no implementation; MD5+SHA1 used for TLS RSA + RIPEMD160 // import golang.org/x/crypto/ripemd160 + SHA3_224 // import golang.org/x/crypto/sha3 + SHA3_256 // import golang.org/x/crypto/sha3 + SHA3_384 // import golang.org/x/crypto/sha3 + SHA3_512 // import golang.org/x/crypto/sha3 + SHA512_224 // import crypto/sha512 + SHA512_256 // import crypto/sha512 maxHash ) var digestSizes = []uint8{ - MD4: 16, - MD5: 16, - SHA1: 20, - SHA224: 28, - SHA256: 32, - SHA384: 48, - SHA512: 64, - SHA3_224: 28, - SHA3_256: 32, - SHA3_384: 48, - SHA3_512: 64, - MD5SHA1: 36, - RIPEMD160: 20, + MD4: 16, + MD5: 16, + SHA1: 20, + SHA224: 28, + SHA256: 32, + SHA384: 48, + SHA512: 64, + SHA512_224: 28, + SHA512_256: 32, + SHA3_224: 28, + SHA3_256: 32, + SHA3_384: 48, + SHA3_512: 64, + MD5SHA1: 36, + RIPEMD160: 20, } // Size returns the length, in bytes, of a digest resulting from the given hash @@ -124,3 +128,19 @@ type SignerOpts interface { // hashing was done. HashFunc() Hash } + +// Decrypter is an interface for an opaque private key that can be used for +// asymmetric decryption operations. An example would be an RSA key +// kept in a hardware module. +type Decrypter interface { + // Public returns the public key corresponding to the opaque, + // private key. + Public() PublicKey + + // Decrypt decrypts msg. The opts argument should be appropriate for + // the primitive used. See the documentation in each implementation for + // details. + Decrypt(rand io.Reader, msg []byte, opts DecrypterOpts) (plaintext []byte, err error) +} + +type DecrypterOpts interface{} diff --git a/libgo/go/crypto/ecdsa/ecdsa.go b/libgo/go/crypto/ecdsa/ecdsa.go index d6135531bff..8d66477fd10 100644 --- a/libgo/go/crypto/ecdsa/ecdsa.go +++ b/libgo/go/crypto/ecdsa/ecdsa.go @@ -4,22 +4,33 @@ // Package ecdsa implements the Elliptic Curve Digital Signature Algorithm, as // defined in FIPS 186-3. +// +// This implementation derives the nonce from an AES-CTR CSPRNG keyed by +// ChopMD(256, SHA2-512(priv.D || entropy || hash)). The CSPRNG key is IRO by +// a result of Coron; the AES-CTR stream is IRO under standard assumptions. package ecdsa // References: // [NSA]: Suite B implementer's guide to FIPS 186-3, // http://www.nsa.gov/ia/_files/ecdsa.pdf // [SECG]: SECG, SEC1 -// http://www.secg.org/download/aid-780/sec1-v2.pdf +// http://www.secg.org/sec1-v2.pdf import ( "crypto" + "crypto/aes" + "crypto/cipher" "crypto/elliptic" + "crypto/sha512" "encoding/asn1" "io" "math/big" ) +const ( + aesIV = "IV for ECDSA CTR" +) + // PublicKey represents an ECDSA public key. type PublicKey struct { elliptic.Curve @@ -123,6 +134,38 @@ func fermatInverse(k, N *big.Int) *big.Int { // pair of integers. The security of the private key depends on the entropy of // rand. func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) { + // Get max(log2(q) / 2, 256) bits of entropy from rand. + entropylen := (priv.Curve.Params().BitSize + 7) / 16 + if entropylen > 32 { + entropylen = 32 + } + entropy := make([]byte, entropylen) + _, err = io.ReadFull(rand, entropy) + if err != nil { + return + } + + // Initialize an SHA-512 hash context; digest ... + md := sha512.New() + md.Write(priv.D.Bytes()) // the private key, + md.Write(entropy) // the entropy, + md.Write(hash) // and the input hash; + key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512), + // which is an indifferentiable MAC. + + // Create an AES-CTR instance to use as a CSPRNG. + block, err := aes.NewCipher(key) + if err != nil { + return nil, nil, err + } + + // Create a CSPRNG that xors a stream of zeros with + // the output of the AES-CTR instance. + csprng := cipher.StreamReader{ + R: zeroReader, + S: cipher.NewCTR(block, []byte(aesIV)), + } + // See [NSA] 3.4.1 c := priv.PublicKey.Curve N := c.Params().N @@ -130,7 +173,7 @@ func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err err var k, kInv *big.Int for { for { - k, err = randFieldElement(c, rand) + k, err = randFieldElement(c, csprng) if err != nil { r = nil return @@ -187,3 +230,17 @@ func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool { x.Mod(x, N) return x.Cmp(r) == 0 } + +type zr struct { + io.Reader +} + +// Read replaces the contents of dst with zeros. +func (z *zr) Read(dst []byte) (n int, err error) { + for i := range dst { + dst[i] = 0 + } + return len(dst), nil +} + +var zeroReader = &zr{} diff --git a/libgo/go/crypto/ecdsa/ecdsa_test.go b/libgo/go/crypto/ecdsa/ecdsa_test.go index 0c064319324..169944dfb27 100644 --- a/libgo/go/crypto/ecdsa/ecdsa_test.go +++ b/libgo/go/crypto/ecdsa/ecdsa_test.go @@ -72,6 +72,78 @@ func TestSignAndVerify(t *testing.T) { testSignAndVerify(t, elliptic.P521(), "p521") } +func testNonceSafety(t *testing.T, c elliptic.Curve, tag string) { + priv, _ := GenerateKey(c, rand.Reader) + + hashed := []byte("testing") + r0, s0, err := Sign(zeroReader, priv, hashed) + if err != nil { + t.Errorf("%s: error signing: %s", tag, err) + return + } + + hashed = []byte("testing...") + r1, s1, err := Sign(zeroReader, priv, hashed) + if err != nil { + t.Errorf("%s: error signing: %s", tag, err) + return + } + + if s0.Cmp(s1) == 0 { + // This should never happen. + t.Errorf("%s: the signatures on two different messages were the same") + } + + if r0.Cmp(r1) == 0 { + t.Errorf("%s: the nonce used for two diferent messages was the same") + } +} + +func TestNonceSafety(t *testing.T) { + testNonceSafety(t, elliptic.P224(), "p224") + if testing.Short() { + return + } + testNonceSafety(t, elliptic.P256(), "p256") + testNonceSafety(t, elliptic.P384(), "p384") + testNonceSafety(t, elliptic.P521(), "p521") +} + +func testINDCCA(t *testing.T, c elliptic.Curve, tag string) { + priv, _ := GenerateKey(c, rand.Reader) + + hashed := []byte("testing") + r0, s0, err := Sign(rand.Reader, priv, hashed) + if err != nil { + t.Errorf("%s: error signing: %s", tag, err) + return + } + + r1, s1, err := Sign(rand.Reader, priv, hashed) + if err != nil { + t.Errorf("%s: error signing: %s", tag, err) + return + } + + if s0.Cmp(s1) == 0 { + t.Errorf("%s: two signatures of the same message produced the same result") + } + + if r0.Cmp(r1) == 0 { + t.Errorf("%s: two signatures of the same message produced the same nonce") + } +} + +func TestINDCCA(t *testing.T) { + testINDCCA(t, elliptic.P224(), "p224") + if testing.Short() { + return + } + testINDCCA(t, elliptic.P256(), "p256") + testINDCCA(t, elliptic.P384(), "p384") + testINDCCA(t, elliptic.P521(), "p521") +} + func fromHex(s string) *big.Int { r, ok := new(big.Int).SetString(s, 16) if !ok { diff --git a/libgo/go/crypto/elliptic/elliptic.go b/libgo/go/crypto/elliptic/elliptic.go index ba673f80ca6..e6b59c5f436 100644 --- a/libgo/go/crypto/elliptic/elliptic.go +++ b/libgo/go/crypto/elliptic/elliptic.go @@ -24,7 +24,7 @@ import ( type Curve interface { // Params returns the parameters for the curve. Params() *CurveParams - // IsOnCurve returns true if the given (x,y) lies on the curve. + // IsOnCurve reports whether the given (x,y) lies on the curve. IsOnCurve(x, y *big.Int) bool // Add returns the sum of (x1,y1) and (x2,y2) Add(x1, y1, x2, y2 *big.Int) (x, y *big.Int) @@ -45,6 +45,7 @@ type CurveParams struct { B *big.Int // the constant of the curve equation Gx, Gy *big.Int // (x,y) of the base point BitSize int // the size of the underlying field + Name string // the canonical name of the curve } func (curve *CurveParams) Params() *CurveParams { @@ -307,7 +308,8 @@ func Marshal(curve Curve, x, y *big.Int) []byte { return ret } -// Unmarshal converts a point, serialized by Marshal, into an x, y pair. On error, x = nil. +// Unmarshal converts a point, serialized by Marshal, into an x, y pair. +// It is an error if the point is not on the curve. On error, x = nil. func Unmarshal(curve Curve, data []byte) (x, y *big.Int) { byteLen := (curve.Params().BitSize + 7) >> 3 if len(data) != 1+2*byteLen { @@ -318,6 +320,9 @@ func Unmarshal(curve Curve, data []byte) (x, y *big.Int) { } x = new(big.Int).SetBytes(data[1 : 1+byteLen]) y = new(big.Int).SetBytes(data[1+byteLen:]) + if !curve.IsOnCurve(x, y) { + x, y = nil, nil + } return } @@ -334,7 +339,7 @@ func initAll() { func initP384() { // See FIPS 186-3, section D.2.4 - p384 = new(CurveParams) + p384 = &CurveParams{Name: "P-384"} p384.P, _ = new(big.Int).SetString("39402006196394479212279040100143613805079739270465446667948293404245721771496870329047266088258938001861606973112319", 10) p384.N, _ = new(big.Int).SetString("39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942643", 10) p384.B, _ = new(big.Int).SetString("b3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef", 16) @@ -345,7 +350,7 @@ func initP384() { func initP521() { // See FIPS 186-3, section D.2.5 - p521 = new(CurveParams) + p521 = &CurveParams{Name: "P-521"} p521.P, _ = new(big.Int).SetString("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151", 10) p521.N, _ = new(big.Int).SetString("6864797660130609714981900799081393217269435300143305409394463459185543183397655394245057746333217197532963996371363321113864768612440380340372808892707005449", 10) p521.B, _ = new(big.Int).SetString("051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00", 16) diff --git a/libgo/go/crypto/elliptic/elliptic_test.go b/libgo/go/crypto/elliptic/elliptic_test.go index 4dc27c92bf4..7e27913dcd0 100644 --- a/libgo/go/crypto/elliptic/elliptic_test.go +++ b/libgo/go/crypto/elliptic/elliptic_test.go @@ -19,6 +19,19 @@ func TestOnCurve(t *testing.T) { } } +func TestOffCurve(t *testing.T) { + p224 := P224() + x, y := new(big.Int).SetInt64(1), new(big.Int).SetInt64(1) + if p224.IsOnCurve(x, y) { + t.Errorf("FAIL: point off curve is claimed to be on the curve") + } + b := Marshal(p224, x, y) + x1, y1 := Unmarshal(p224, b) + if x1 != nil || y1 != nil { + t.Errorf("FAIL: unmarshalling a point not on the curve succeeded") + } +} + type baseMultTest struct { k string x, y string diff --git a/libgo/go/crypto/elliptic/p224.go b/libgo/go/crypto/elliptic/p224.go index 1f7ff3f9da6..2d3fac74fbf 100644 --- a/libgo/go/crypto/elliptic/p224.go +++ b/libgo/go/crypto/elliptic/p224.go @@ -22,7 +22,7 @@ type p224Curve struct { func initP224() { // See FIPS 186-3, section D.2.2 - p224.CurveParams = new(CurveParams) + p224.CurveParams = &CurveParams{Name: "P-224"} p224.P, _ = new(big.Int).SetString("26959946667150639794667015087019630673557916260026308143510066298881", 10) p224.N, _ = new(big.Int).SetString("26959946667150639794667015087019625940457807714424391721682722368061", 10) p224.B, _ = new(big.Int).SetString("b4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4", 16) diff --git a/libgo/go/crypto/elliptic/p256.go b/libgo/go/crypto/elliptic/p256.go index 82be51e62cd..82bc7b3019e 100644 --- a/libgo/go/crypto/elliptic/p256.go +++ b/libgo/go/crypto/elliptic/p256.go @@ -23,7 +23,7 @@ var ( func initP256() { // See FIPS 186-3, section D.2.3 - p256.CurveParams = new(CurveParams) + p256.CurveParams = &CurveParams{Name: "P-256"} p256.P, _ = new(big.Int).SetString("115792089210356248762697446949407573530086143415290314195533631308867097853951", 10) p256.N, _ = new(big.Int).SetString("115792089210356248762697446949407573529996955224135760342422259061068512044369", 10) p256.B, _ = new(big.Int).SetString("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16) diff --git a/libgo/go/crypto/hmac/hmac.go b/libgo/go/crypto/hmac/hmac.go index b6f4919a7ce..e0cc1d6d224 100644 --- a/libgo/go/crypto/hmac/hmac.go +++ b/libgo/go/crypto/hmac/hmac.go @@ -11,7 +11,7 @@ The receiver verifies the hash by recomputing it using the same key. Receivers should be careful to use Equal to compare MACs in order to avoid timing side-channels: - // CheckMAC returns true if messageMAC is a valid HMAC tag for message. + // CheckMAC reports whether messageMAC is a valid HMAC tag for message. func CheckMAC(message, messageMAC, key []byte) bool { mac := hmac.New(sha256.New, key) mac.Write(message) diff --git a/libgo/go/crypto/rand/eagain.go b/libgo/go/crypto/rand/eagain.go new file mode 100644 index 00000000000..2c853d0a134 --- /dev/null +++ b/libgo/go/crypto/rand/eagain.go @@ -0,0 +1,27 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris + +package rand + +import ( + "os" + "syscall" +) + +func init() { + isEAGAIN = unixIsEAGAIN +} + +// unixIsEAGAIN reports whether err is a syscall.EAGAIN wrapped in a PathError. +// See golang.org/issue/9205 +func unixIsEAGAIN(err error) bool { + if pe, ok := err.(*os.PathError); ok { + if errno, ok := pe.Err.(syscall.Errno); ok && errno == syscall.EAGAIN { + return true + } + } + return false +} diff --git a/libgo/go/crypto/rand/rand.go b/libgo/go/crypto/rand/rand.go index 4da3adb7010..ee32fa0bd67 100644 --- a/libgo/go/crypto/rand/rand.go +++ b/libgo/go/crypto/rand/rand.go @@ -10,7 +10,9 @@ import "io" // Reader is a global, shared instance of a cryptographically // strong pseudo-random generator. +// // On Unix-like systems, Reader reads from /dev/urandom. +// On Linux, Reader uses getrandom(2) if available, /dev/urandom otherwise. // On Windows systems, Reader uses the CryptGenRandom API. var Reader io.Reader diff --git a/libgo/go/crypto/rand/rand_linux.go b/libgo/go/crypto/rand/rand_linux.go index 8cb59c75dff..7d6d9e8a094 100644 --- a/libgo/go/crypto/rand/rand_linux.go +++ b/libgo/go/crypto/rand/rand_linux.go @@ -5,7 +5,7 @@ package rand import ( - "internal/syscall" + "internal/syscall/unix" "sync" ) @@ -25,7 +25,7 @@ func pickStrategy() { // - the machine has no entropy available (early boot + no hardware // entropy source?) and we want to avoid blocking later. var buf [1]byte - n, err := syscall.GetRandom(buf[:], syscall.GRND_NONBLOCK) + n, err := unix.GetRandom(buf[:], unix.GRND_NONBLOCK) useSyscall = n == 1 && err == nil } @@ -34,6 +34,6 @@ func getRandomLinux(p []byte) (ok bool) { if !useSyscall { return false } - n, err := syscall.GetRandom(p, 0) + n, err := unix.GetRandom(p, 0) return n == len(p) && err == nil } diff --git a/libgo/go/crypto/rand/rand_unix.go b/libgo/go/crypto/rand/rand_unix.go index 62d0fbdb350..75c36e05b34 100644 --- a/libgo/go/crypto/rand/rand_unix.go +++ b/libgo/go/crypto/rand/rand_unix.go @@ -58,12 +58,28 @@ func (r *devReader) Read(b []byte) (n int, err error) { if runtime.GOOS == "plan9" { r.f = f } else { - r.f = bufio.NewReader(f) + r.f = bufio.NewReader(hideAgainReader{f}) } } return r.f.Read(b) } +var isEAGAIN func(error) bool // set by eagain.go on unix systems + +// hideAgainReader masks EAGAIN reads from /dev/urandom. +// See golang.org/issue/9205 +type hideAgainReader struct { + r io.Reader +} + +func (hr hideAgainReader) Read(p []byte) (n int, err error) { + n, err = hr.r.Read(p) + if err != nil && isEAGAIN != nil && isEAGAIN(err) { + err = nil + } + return +} + // Alternate pseudo-random implementation for use on // systems without a reliable /dev/urandom. diff --git a/libgo/go/crypto/rand/util_test.go b/libgo/go/crypto/rand/util_test.go index 1e2a4dd84b7..2f7cba8364a 100644 --- a/libgo/go/crypto/rand/util_test.go +++ b/libgo/go/crypto/rand/util_test.go @@ -10,7 +10,7 @@ import ( "testing" ) -// http://golang.org/issue/6849. +// https://golang.org/issue/6849. func TestPrimeSmall(t *testing.T) { for n := 2; n < 10; n++ { p, err := rand.Prime(rand.Reader, n) diff --git a/libgo/go/crypto/rsa/pkcs1v15.go b/libgo/go/crypto/rsa/pkcs1v15.go index 59e8bb5b7ba..34037b0d674 100644 --- a/libgo/go/crypto/rsa/pkcs1v15.go +++ b/libgo/go/crypto/rsa/pkcs1v15.go @@ -14,6 +14,16 @@ import ( // This file implements encryption and decryption using PKCS#1 v1.5 padding. +// PKCS1v15DecrypterOpts is for passing options to PKCS#1 v1.5 decryption using +// the crypto.Decrypter interface. +type PKCS1v15DecryptOptions struct { + // SessionKeyLen is the length of the session key that is being + // decrypted. If not zero, then a padding error during decryption will + // cause a random plaintext of this length to be returned rather than + // an error. These alternatives happen in constant time. + SessionKeyLen int +} + // EncryptPKCS1v15 encrypts the given message with RSA and the padding scheme from PKCS#1 v1.5. // The message must be no longer than the length of the public modulus minus 11 bytes. // WARNING: use of this function to encrypt plaintexts other than session keys diff --git a/libgo/go/crypto/rsa/pkcs1v15_test.go b/libgo/go/crypto/rsa/pkcs1v15_test.go index 2dc5dbc2c85..89253751ec2 100644 --- a/libgo/go/crypto/rsa/pkcs1v15_test.go +++ b/libgo/go/crypto/rsa/pkcs1v15_test.go @@ -51,14 +51,25 @@ var decryptPKCS1v15Tests = []DecryptPKCS1v15Test{ } func TestDecryptPKCS1v15(t *testing.T) { - for i, test := range decryptPKCS1v15Tests { - out, err := DecryptPKCS1v15(nil, rsaPrivateKey, decodeBase64(test.in)) - if err != nil { - t.Errorf("#%d error decrypting", i) - } - want := []byte(test.out) - if !bytes.Equal(out, want) { - t.Errorf("#%d got:%#v want:%#v", i, out, want) + decryptionFuncs := []func([]byte) ([]byte, error){ + func(ciphertext []byte) (plaintext []byte, err error) { + return DecryptPKCS1v15(nil, rsaPrivateKey, ciphertext) + }, + func(ciphertext []byte) (plaintext []byte, err error) { + return rsaPrivateKey.Decrypt(nil, ciphertext, nil) + }, + } + + for _, decryptFunc := range decryptionFuncs { + for i, test := range decryptPKCS1v15Tests { + out, err := decryptFunc(decodeBase64(test.in)) + if err != nil { + t.Errorf("#%d error decrypting", i) + } + want := []byte(test.out) + if !bytes.Equal(out, want) { + t.Errorf("#%d got:%#v want:%#v", i, out, want) + } } } } @@ -138,6 +149,22 @@ func TestEncryptPKCS1v15SessionKey(t *testing.T) { } } +func TestEncryptPKCS1v15DecrypterSessionKey(t *testing.T) { + for i, test := range decryptPKCS1v15SessionKeyTests { + plaintext, err := rsaPrivateKey.Decrypt(rand.Reader, decodeBase64(test.in), &PKCS1v15DecryptOptions{SessionKeyLen: 4}) + if err != nil { + t.Fatalf("#%d: error decrypting: %s", i, err) + } + if len(plaintext) != 4 { + t.Fatalf("#%d: incorrect length plaintext: got %d, want 4", i, len(plaintext)) + } + + if test.out != "FAIL" && !bytes.Equal(plaintext, []byte(test.out)) { + t.Errorf("#%d: incorrect plaintext: got %x, want %x", plaintext, test.out) + } + } +} + func TestNonZeroRandomBytes(t *testing.T) { random := rand.Reader diff --git a/libgo/go/crypto/rsa/pss.go b/libgo/go/crypto/rsa/pss.go index e9f2908250c..0a41814a4b1 100644 --- a/libgo/go/crypto/rsa/pss.go +++ b/libgo/go/crypto/rsa/pss.go @@ -255,7 +255,7 @@ func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte, saltLength = hash.Size() } - if opts.Hash != 0 { + if opts != nil && opts.Hash != 0 { hash = opts.Hash } diff --git a/libgo/go/crypto/rsa/pss_test.go b/libgo/go/crypto/rsa/pss_test.go index 32e6fc39d29..cae24e58c67 100644 --- a/libgo/go/crypto/rsa/pss_test.go +++ b/libgo/go/crypto/rsa/pss_test.go @@ -189,6 +189,15 @@ func TestPSSOpenSSL(t *testing.T) { } } +func TestPSSNilOpts(t *testing.T) { + hash := crypto.SHA256 + h := hash.New() + h.Write([]byte("testing")) + hashed := h.Sum(nil) + + SignPSS(rand.Reader, rsaPrivateKey, hash, hashed, nil) +} + func TestPSSSigning(t *testing.T) { var saltLengthCombinations = []struct { signSaltLength, verifySaltLength int diff --git a/libgo/go/crypto/rsa/rsa.go b/libgo/go/crypto/rsa/rsa.go index 2702311281c..1293b783679 100644 --- a/libgo/go/crypto/rsa/rsa.go +++ b/libgo/go/crypto/rsa/rsa.go @@ -24,6 +24,16 @@ type PublicKey struct { E int // public exponent } +// OAEPOptions is an interface for passing options to OAEP decryption using the +// crypto.Decrypter interface. +type OAEPOptions struct { + // Hash is the hash function that will be used when generating the mask. + Hash crypto.Hash + // Label is an arbitrary byte string that must be equal to the value + // used when encrypting. + Label []byte +} + var ( errPublicModulus = errors.New("crypto/rsa: missing public modulus") errPublicExponentSmall = errors.New("crypto/rsa: public exponent too small") @@ -77,6 +87,37 @@ func (priv *PrivateKey) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) return SignPKCS1v15(rand, priv, opts.HashFunc(), msg) } +// Decrypt decrypts ciphertext with priv. If opts is nil or of type +// *PKCS1v15DecryptOptions then PKCS#1 v1.5 decryption is performed. Otherwise +// opts must have type *OAEPOptions and OAEP decryption is done. +func (priv *PrivateKey) Decrypt(rand io.Reader, ciphertext []byte, opts crypto.DecrypterOpts) (plaintext []byte, err error) { + if opts == nil { + return DecryptPKCS1v15(rand, priv, ciphertext) + } + + switch opts := opts.(type) { + case *OAEPOptions: + return DecryptOAEP(opts.Hash.New(), rand, priv, ciphertext, opts.Label) + + case *PKCS1v15DecryptOptions: + if l := opts.SessionKeyLen; l > 0 { + plaintext = make([]byte, l) + if _, err := io.ReadFull(rand, plaintext); err != nil { + return nil, err + } + if err := DecryptPKCS1v15SessionKey(rand, priv, ciphertext, plaintext); err != nil { + return nil, err + } + return plaintext, nil + } else { + return DecryptPKCS1v15(rand, priv, ciphertext) + } + + default: + return nil, errors.New("crypto/rsa: invalid options for Decrypt") + } +} + type PrecomputedValues struct { Dp, Dq *big.Int // D mod (P-1) (or mod Q-1) Qinv *big.Int // Q^-1 mod P @@ -88,7 +129,7 @@ type PrecomputedValues struct { CRTValues []CRTValue } -// CRTValue contains the precomputed chinese remainder theorem values. +// CRTValue contains the precomputed Chinese remainder theorem values. type CRTValue struct { Exp *big.Int // D mod (prime-1). Coeff *big.Int // R·Coeff ≡ 1 mod Prime. @@ -102,19 +143,13 @@ func (priv *PrivateKey) Validate() error { return err } - // Check that the prime factors are actually prime. Note that this is - // just a sanity check. Since the random witnesses chosen by - // ProbablyPrime are deterministic, given the candidate number, it's - // easy for an attack to generate composites that pass this test. - for _, prime := range priv.Primes { - if !prime.ProbablyPrime(20) { - return errors.New("crypto/rsa: prime factor is composite") - } - } - // Check that Πprimes == n. modulus := new(big.Int).Set(bigOne) for _, prime := range priv.Primes { + // Any primes ≤ 1 will cause divide-by-zero panics later. + if prime.Cmp(bigOne) <= 0 { + return errors.New("crypto/rsa: invalid prime value") + } modulus.Mul(modulus, prime) } if modulus.Cmp(priv.N) != 0 { diff --git a/libgo/go/crypto/sha512/sha512.go b/libgo/go/crypto/sha512/sha512.go index bca7a91e22e..e7781fd2f41 100644 --- a/libgo/go/crypto/sha512/sha512.go +++ b/libgo/go/crypto/sha512/sha512.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Package sha512 implements the SHA384 and SHA512 hash algorithms as defined -// in FIPS 180-2. +// Package sha512 implements the SHA-384, SHA-512, SHA-512/224, and SHA-512/256 +// hash algorithms as defined in FIPS 180-4. package sha512 import ( @@ -14,16 +14,27 @@ import ( func init() { crypto.RegisterHash(crypto.SHA384, New384) crypto.RegisterHash(crypto.SHA512, New) + crypto.RegisterHash(crypto.SHA512_224, New512_224) + crypto.RegisterHash(crypto.SHA512_256, New512_256) } -// The size of a SHA512 checksum in bytes. -const Size = 64 +const ( + // Size is the size, in bytes, of a SHA-512 checksum. + Size = 64 + + // Size224 is the size, in bytes, of a SHA-512/224 checksum. + Size224 = 28 + + // Size256 is the size, in bytes, of a SHA-512/256 checksum. + Size256 = 32 -// The size of a SHA384 checksum in bytes. -const Size384 = 48 + // Size384 is the size, in bytes, of a SHA-384 checksum. + Size384 = 48 -// The blocksize of SHA512 and SHA384 in bytes. -const BlockSize = 128 + // BlockSize is the block size, in bytes, of the SHA-512/224, + // SHA-512/256, SHA-384 and SHA-512 hash functions. + BlockSize = 128 +) const ( chunk = 128 @@ -35,6 +46,22 @@ const ( init5 = 0x9b05688c2b3e6c1f init6 = 0x1f83d9abfb41bd6b init7 = 0x5be0cd19137e2179 + init0_224 = 0x8c3d37c819544da2 + init1_224 = 0x73e1996689dcd4d6 + init2_224 = 0x1dfab7ae32ff9c82 + init3_224 = 0x679dd514582f9fcf + init4_224 = 0x0f6d2b697bd44da8 + init5_224 = 0x77e36f7304c48942 + init6_224 = 0x3f9d85a86a1d36c8 + init7_224 = 0x1112e6ad91d692a1 + init0_256 = 0x22312194fc2bf72c + init1_256 = 0x9f555fa3c84c64c2 + init2_256 = 0x2393b86b6f53b151 + init3_256 = 0x963877195940eabd + init4_256 = 0x96283ee2a88effe3 + init5_256 = 0xbe5e1e2553863992 + init6_256 = 0x2b0199fc2c85b8aa + init7_256 = 0x0eb72ddc81c52ca2 init0_384 = 0xcbbb9d5dc1059ed8 init1_384 = 0x629a292a367cd507 init2_384 = 0x9159015a3070dd17 @@ -47,24 +74,16 @@ const ( // digest represents the partial evaluation of a checksum. type digest struct { - h [8]uint64 - x [chunk]byte - nx int - len uint64 - is384 bool // mark if this digest is SHA-384 + h [8]uint64 + x [chunk]byte + nx int + len uint64 + function crypto.Hash } func (d *digest) Reset() { - if !d.is384 { - d.h[0] = init0 - d.h[1] = init1 - d.h[2] = init2 - d.h[3] = init3 - d.h[4] = init4 - d.h[5] = init5 - d.h[6] = init6 - d.h[7] = init7 - } else { + switch d.function { + case crypto.SHA384: d.h[0] = init0_384 d.h[1] = init1_384 d.h[2] = init2_384 @@ -73,31 +92,77 @@ func (d *digest) Reset() { d.h[5] = init5_384 d.h[6] = init6_384 d.h[7] = init7_384 + case crypto.SHA512_224: + d.h[0] = init0_224 + d.h[1] = init1_224 + d.h[2] = init2_224 + d.h[3] = init3_224 + d.h[4] = init4_224 + d.h[5] = init5_224 + d.h[6] = init6_224 + d.h[7] = init7_224 + case crypto.SHA512_256: + d.h[0] = init0_256 + d.h[1] = init1_256 + d.h[2] = init2_256 + d.h[3] = init3_256 + d.h[4] = init4_256 + d.h[5] = init5_256 + d.h[6] = init6_256 + d.h[7] = init7_256 + default: + d.h[0] = init0 + d.h[1] = init1 + d.h[2] = init2 + d.h[3] = init3 + d.h[4] = init4 + d.h[5] = init5 + d.h[6] = init6 + d.h[7] = init7 } d.nx = 0 d.len = 0 } -// New returns a new hash.Hash computing the SHA512 checksum. +// New returns a new hash.Hash computing the SHA-512 checksum. func New() hash.Hash { - d := new(digest) + d := &digest{function: crypto.SHA512} d.Reset() return d } -// New384 returns a new hash.Hash computing the SHA384 checksum. +// New512_224 returns a new hash.Hash computing the SHA-512/224 checksum. +func New512_224() hash.Hash { + d := &digest{function: crypto.SHA512_224} + d.Reset() + return d +} + +// New512_256 returns a new hash.Hash computing the SHA-512/256 checksum. +func New512_256() hash.Hash { + d := &digest{function: crypto.SHA512_256} + d.Reset() + return d +} + +// New384 returns a new hash.Hash computing the SHA-384 checksum. func New384() hash.Hash { - d := new(digest) - d.is384 = true + d := &digest{function: crypto.SHA384} d.Reset() return d } func (d *digest) Size() int { - if !d.is384 { + switch d.function { + case crypto.SHA512_224: + return Size224 + case crypto.SHA512_256: + return Size256 + case crypto.SHA384: + return Size384 + default: return Size } - return Size384 } func (d *digest) BlockSize() int { return BlockSize } @@ -130,10 +195,16 @@ func (d0 *digest) Sum(in []byte) []byte { d := new(digest) *d = *d0 hash := d.checkSum() - if d.is384 { + switch d.function { + case crypto.SHA384: return append(in, hash[:Size384]...) + case crypto.SHA512_224: + return append(in, hash[:Size224]...) + case crypto.SHA512_256: + return append(in, hash[:Size256]...) + default: + return append(in, hash[:]...) } - return append(in, hash[:]...) } func (d *digest) checkSum() [Size]byte { @@ -159,7 +230,7 @@ func (d *digest) checkSum() [Size]byte { } h := d.h[:] - if d.is384 { + if d.function == crypto.SHA384 { h = d.h[:6] } @@ -180,7 +251,7 @@ func (d *digest) checkSum() [Size]byte { // Sum512 returns the SHA512 checksum of the data. func Sum512(data []byte) [Size]byte { - var d digest + d := digest{function: crypto.SHA512} d.Reset() d.Write(data) return d.checkSum() @@ -188,11 +259,30 @@ func Sum512(data []byte) [Size]byte { // Sum384 returns the SHA384 checksum of the data. func Sum384(data []byte) (sum384 [Size384]byte) { - var d digest - d.is384 = true + d := digest{function: crypto.SHA384} d.Reset() d.Write(data) sum := d.checkSum() copy(sum384[:], sum[:Size384]) return } + +// Sum512_224 returns the Sum512/224 checksum of the data. +func Sum512_224(data []byte) (sum224 [Size224]byte) { + d := digest{function: crypto.SHA512_224} + d.Reset() + d.Write(data) + sum := d.checkSum() + copy(sum224[:], sum[:Size224]) + return +} + +// Sum512_256 returns the Sum512/256 checksum of the data. +func Sum512_256(data []byte) (sum256 [Size256]byte) { + d := digest{function: crypto.SHA512_256} + d.Reset() + d.Write(data) + sum := d.checkSum() + copy(sum256[:], sum[:Size256]) + return +} diff --git a/libgo/go/crypto/sha512/sha512_test.go b/libgo/go/crypto/sha512/sha512_test.go index 541860f701b..04b3d4a3cc0 100644 --- a/libgo/go/crypto/sha512/sha512_test.go +++ b/libgo/go/crypto/sha512/sha512_test.go @@ -2,133 +2,279 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// SHA512 hash algorithm. See FIPS 180-2. +// SHA512 hash algorithm. See FIPS 180-4. package sha512 import ( - "fmt" + "encoding/hex" + "hash" "io" "testing" ) type sha512Test struct { - out string - in string + in string + out224 string + out256 string + out384 string + out512 string } var golden = []sha512Test{ - {"cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e", ""}, - {"1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75", "a"}, - {"2d408a0717ec188158278a796c689044361dc6fdde28d6f04973b80896e1823975cdbf12eb63f9e0591328ee235d80e9b5bf1aa6a44f4617ff3caf6400eb172d", "ab"}, - {"ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", "abc"}, - {"d8022f2060ad6efd297ab73dcc5355c9b214054b0d1776a136a669d26a7d3b14f73aa0d0ebff19ee333368f0164b6419a96da49e3e481753e7e96b716bdccb6f", "abcd"}, - {"878ae65a92e86cac011a570d4c30a7eaec442b85ce8eca0c2952b5e3cc0628c2e79d889ad4d5c7c626986d452dd86374b6ffaa7cd8b67665bef2289a5c70b0a1", "abcde"}, - {"e32ef19623e8ed9d267f657a81944b3d07adbb768518068e88435745564e8d4150a0a703be2a7d88b61e3d390c2bb97e2d4c311fdc69d6b1267f05f59aa920e7", "abcdef"}, - {"d716a4188569b68ab1b6dfac178e570114cdf0ea3a1cc0e31486c3e41241bc6a76424e8c37ab26f096fc85ef9886c8cb634187f4fddff645fb099f1ff54c6b8c", "abcdefg"}, - {"a3a8c81bc97c2560010d7389bc88aac974a104e0e2381220c6e084c4dccd1d2d17d4f86db31c2a851dc80e6681d74733c55dcd03dd96f6062cdda12a291ae6ce", "abcdefgh"}, - {"f22d51d25292ca1d0f68f69aedc7897019308cc9db46efb75a03dd494fc7f126c010e8ade6a00a0c1a5f1b75d81e0ed5a93ce98dc9b833db7839247b1d9c24fe", "abcdefghi"}, - {"ef6b97321f34b1fea2169a7db9e1960b471aa13302a988087357c520be957ca119c3ba68e6b4982c019ec89de3865ccf6a3cda1fe11e59f98d99f1502c8b9745", "abcdefghij"}, - {"2210d99af9c8bdecda1b4beff822136753d8342505ddce37f1314e2cdbb488c6016bdaa9bd2ffa513dd5de2e4b50f031393d8ab61f773b0e0130d7381e0f8a1d", "Discard medicine more than two years old."}, - {"a687a8985b4d8d0a24f115fe272255c6afaf3909225838546159c1ed685c211a203796ae8ecc4c81a5b6315919b3a64f10713da07e341fcdbb08541bf03066ce", "He who has a shady past knows that nice guys finish last."}, - {"8ddb0392e818b7d585ab22769a50df660d9f6d559cca3afc5691b8ca91b8451374e42bcdabd64589ed7c91d85f626596228a5c8572677eb98bc6b624befb7af8", "I wouldn't marry him with a ten foot pole."}, - {"26ed8f6ca7f8d44b6a8a54ae39640fa8ad5c673f70ee9ce074ba4ef0d483eea00bab2f61d8695d6b34df9c6c48ae36246362200ed820448bdc03a720366a87c6", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"}, - {"e5a14bf044be69615aade89afcf1ab0389d5fc302a884d403579d1386a2400c089b0dbb387ed0f463f9ee342f8244d5a38cfbc0e819da9529fbff78368c9a982", "The days of the digital watch are numbered. -Tom Stoppard"}, - {"420a1faa48919e14651bed45725abe0f7a58e0f099424c4e5a49194946e38b46c1f8034b18ef169b2e31050d1648e0b982386595f7df47da4b6fd18e55333015", "Nepal premier won't resign."}, - {"d926a863beadb20134db07683535c72007b0e695045876254f341ddcccde132a908c5af57baa6a6a9c63e6649bba0c213dc05fadcf9abccea09f23dcfb637fbe", "For every action there is an equal and opposite government program."}, - {"9a98dd9bb67d0da7bf83da5313dff4fd60a4bac0094f1b05633690ffa7f6d61de9a1d4f8617937d560833a9aaa9ccafe3fd24db418d0e728833545cadd3ad92d", "His money is twice tainted: 'taint yours and 'taint mine."}, - {"d7fde2d2351efade52f4211d3746a0780a26eec3df9b2ed575368a8a1c09ec452402293a8ea4eceb5a4f60064ea29b13cdd86918cd7a4faf366160b009804107", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"}, - {"b0f35ffa2697359c33a56f5c0cf715c7aeed96da9905ca2698acadb08fbc9e669bf566b6bd5d61a3e86dc22999bcc9f2224e33d1d4f32a228cf9d0349e2db518", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"}, - {"3d2e5f91778c9e66f7e061293aaa8a8fc742dd3b2e4f483772464b1144189b49273e610e5cccd7a81a19ca1fa70f16b10f1a100a4d8c1372336be8484c64b311", "size: a.out: bad magic"}, - {"b2f68ff58ac015efb1c94c908b0d8c2bf06f491e4de8e6302c49016f7f8a33eac3e959856c7fddbc464de618701338a4b46f76dbfaf9a1e5262b5f40639771c7", "The major problem is with sendmail. -Mark Horton"}, - {"d8c92db5fdf52cf8215e4df3b4909d29203ff4d00e9ad0b64a6a4e04dec5e74f62e7c35c7fb881bd5de95442123df8f57a489b0ae616bd326f84d10021121c57", "Give me a rock, paper and scissors and I will move the world. CCFestoon"}, - {"19a9f8dc0a233e464e8566ad3ca9b91e459a7b8c4780985b015776e1bf239a19bc233d0556343e2b0a9bc220900b4ebf4f8bdf89ff8efeaf79602d6849e6f72e", "If the enemy is within range, then so are you."}, - {"00b4c41f307bde87301cdc5b5ab1ae9a592e8ecbb2021dd7bc4b34e2ace60741cc362560bec566ba35178595a91932b8d5357e2c9cec92d393b0fa7831852476", "It's well we cannot hear the screams/That we create in others' dreams."}, - {"91eccc3d5375fd026e4d6787874b1dce201cecd8a27dbded5065728cb2d09c58a3d467bb1faf353bf7ba567e005245d5321b55bc344f7c07b91cb6f26c959be7", "You remind me of a TV show, but that's all right: I watch it anyway."}, - {"fabbbe22180f1f137cfdc9556d2570e775d1ae02a597ded43a72a40f9b485d500043b7be128fb9fcd982b83159a0d99aa855a9e7cc4240c00dc01a9bdf8218d7", "C is as portable as Stonehedge!!"}, - {"2ecdec235c1fa4fc2a154d8fba1dddb8a72a1ad73838b51d792331d143f8b96a9f6fcb0f34d7caa351fe6d88771c4f105040e0392f06e0621689d33b2f3ba92e", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"}, - {"7ad681f6f96f82f7abfa7ecc0334e8fa16d3dc1cdc45b60b7af43fe4075d2357c0c1d60e98350f1afb1f2fe7a4d7cd2ad55b88e458e06b73c40b437331f5dab4", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"}, - {"833f9248ab4a3b9e5131f745fda1ffd2dd435b30e965957e78291c7ab73605fd1912b0794e5c233ab0a12d205a39778d19b83515d6a47003f19cdee51d98c7e0", "How can you write a big system without C++? -Paul Glick"}, + { + "", + "6ed0dd02806fa89e25de060c19d3ac86cabb87d6a0ddd05c333b84f4", + "c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a", + "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b", + "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e", + }, + { + "a", + "d5cdb9ccc769a5121d4175f2bfdd13d6310e0d3d361ea75d82108327", + "455e518824bc0601f9fb858ff5c37d417d67c2f8e0df2babe4808858aea830f8", + "54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31", + "1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75", + }, + { + "ab", + "b35878d07bfedf39fc638af08547eb5d1072d8546319f247b442fbf5", + "22d4d37ec6370571af7109fb12eae79673d5f7c83e6e677083faa3cfac3b2c14", + "c7be03ba5bcaa384727076db0018e99248e1a6e8bd1b9ef58a9ec9dd4eeebb3f48b836201221175befa74ddc3d35afdd", + "2d408a0717ec188158278a796c689044361dc6fdde28d6f04973b80896e1823975cdbf12eb63f9e0591328ee235d80e9b5bf1aa6a44f4617ff3caf6400eb172d", + }, + { + "abc", + "4634270f707b6a54daae7530460842e20e37ed265ceee9a43e8924aa", + "53048e2681941ef99b2e29b76b4c7dabe4c2d0c634fc6d46e0e2f13107e7af23", + "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7", + "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", + }, + { + "abcd", + "0c9f157ab030fb06e957c14e3938dc5908962e5dd7b66f04a36fc534", + "d2891c7978be0e24948f37caa415b87cb5cbe2b26b7bad9dc6391b8a6f6ddcc9", + "1165b3406ff0b52a3d24721f785462ca2276c9f454a116c2b2ba20171a7905ea5a026682eb659c4d5f115c363aa3c79b", + "d8022f2060ad6efd297ab73dcc5355c9b214054b0d1776a136a669d26a7d3b14f73aa0d0ebff19ee333368f0164b6419a96da49e3e481753e7e96b716bdccb6f", + }, + { + "abcde", + "880e79bb0a1d2c9b7528d851edb6b8342c58c831de98123b432a4515", + "de8322b46e78b67d4431997070703e9764e03a1237b896fd8b379ed4576e8363", + "4c525cbeac729eaf4b4665815bc5db0c84fe6300068a727cf74e2813521565abc0ec57a37ee4d8be89d097c0d2ad52f0", + "878ae65a92e86cac011a570d4c30a7eaec442b85ce8eca0c2952b5e3cc0628c2e79d889ad4d5c7c626986d452dd86374b6ffaa7cd8b67665bef2289a5c70b0a1", + }, + { + "abcdef", + "236c829cfea4fd6d4de61ad15fcf34dca62342adaf9f2001c16f29b8", + "e4fdcb11d1ac14e698743acd8805174cea5ddc0d312e3e47f6372032571bad84", + "c6a4c65b227e7387b9c3e839d44869c4cfca3ef583dea64117859b808c1e3d8ae689e1e314eeef52a6ffe22681aa11f5", + "e32ef19623e8ed9d267f657a81944b3d07adbb768518068e88435745564e8d4150a0a703be2a7d88b61e3d390c2bb97e2d4c311fdc69d6b1267f05f59aa920e7", + }, + { + "abcdefg", + "4767af672b3ed107f25018dc22d6fa4b07d156e13b720971e2c4f6bf", + "a8117f680bdceb5d1443617cbdae9255f6900075422326a972fdd2f65ba9bee3", + "9f11fc131123f844c1226f429b6a0a6af0525d9f40f056c7fc16cdf1b06bda08e302554417a59fa7dcf6247421959d22", + "d716a4188569b68ab1b6dfac178e570114cdf0ea3a1cc0e31486c3e41241bc6a76424e8c37ab26f096fc85ef9886c8cb634187f4fddff645fb099f1ff54c6b8c", + }, + { + "abcdefgh", + "792e25e0ae286d123a38950007e037d3122e76c4ee201668c385edab", + "a29b9645d2a02a8b582888d044199787220e316bf2e89d1422d3df26bf545bbe", + "9000cd7cada59d1d2eb82912f7f24e5e69cc5517f68283b005fa27c285b61e05edf1ad1a8a9bded6fd29eb87d75ad806", + "a3a8c81bc97c2560010d7389bc88aac974a104e0e2381220c6e084c4dccd1d2d17d4f86db31c2a851dc80e6681d74733c55dcd03dd96f6062cdda12a291ae6ce", + }, + { + "abcdefghi", + "56b275d36127dc070cda4019baf2ce2579a25d8c67fa2bc9be61b539", + "b955095330f9c8188d11884ec1679dc44c9c5b25ff9bda700416df9cdd39188f", + "ef54915b60cf062b8dd0c29ae3cad69abe6310de63ac081f46ef019c5c90897caefd79b796cfa81139788a260ded52df", + "f22d51d25292ca1d0f68f69aedc7897019308cc9db46efb75a03dd494fc7f126c010e8ade6a00a0c1a5f1b75d81e0ed5a93ce98dc9b833db7839247b1d9c24fe", + }, + { + "abcdefghij", + "f809423cbb25e81a2a64aecee2cd5fdc7d91d5db583901fbf1db3116", + "550762913d51eefbcd1a55068fcfc9b154fd11c1078b996df0d926ea59d2a68d", + "a12070030a02d86b0ddacd0d3a5b598344513d0a051e7355053e556a0055489c1555399b03342845c4adde2dc44ff66c", + "ef6b97321f34b1fea2169a7db9e1960b471aa13302a988087357c520be957ca119c3ba68e6b4982c019ec89de3865ccf6a3cda1fe11e59f98d99f1502c8b9745", + }, + { + "Discard medicine more than two years old.", + "4c46e10b5b72204e509c3c06072cea970bc020cd45a61a0acdfa97ac", + "690c8ad3916cefd3ad29226d9875965e3ee9ec0d4482eacc248f2ff4aa0d8e5b", + "86f58ec2d74d1b7f8eb0c2ff0967316699639e8d4eb129de54bdf34c96cdbabe200d052149f2dd787f43571ba74670d4", + "2210d99af9c8bdecda1b4beff822136753d8342505ddce37f1314e2cdbb488c6016bdaa9bd2ffa513dd5de2e4b50f031393d8ab61f773b0e0130d7381e0f8a1d", + }, + { + "He who has a shady past knows that nice guys finish last.", + "cb0cef13c1848d91a6d02637c7c520de1914ad4a7aea824671cc328e", + "25938ca49f7ef1178ce81620842b65e576245fcaed86026a36b516b80bb86b3b", + "ae4a2b639ca9bfa04b1855d5a05fe7f230994f790891c6979103e2605f660c4c1262a48142dcbeb57a1914ba5f7c3fa7", + "a687a8985b4d8d0a24f115fe272255c6afaf3909225838546159c1ed685c211a203796ae8ecc4c81a5b6315919b3a64f10713da07e341fcdbb08541bf03066ce", + }, + { + "I wouldn't marry him with a ten foot pole.", + "6c7bd0f3a6544ea698006c2ea583a85f80ea2913590a186db8bb2f1b", + "698e420c3a7038e53d8e73f4be2b02e03b93464ac1a61ebe69f557079921ef65", + "40ae213df6436eca952aa6841886fcdb82908ef1576a99c8f49bb9dd5023169f7c53035abdda0b54c302f4974e2105e7", + "8ddb0392e818b7d585ab22769a50df660d9f6d559cca3afc5691b8ca91b8451374e42bcdabd64589ed7c91d85f626596228a5c8572677eb98bc6b624befb7af8", + }, + { + "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave", + "981323be3eca6ccfa598e58dd74ed8cb05d5f7f6653b7604b684f904", + "839b414d7e3900ee243aa3d1f9b6955720e64041f5ab9bedd3eb0a08da5a2ca8", + "e7cf8b873c9bc950f06259aa54309f349cefa72c00d597aebf903e6519a50011dfe355afff064a10701c705693848df9", + "26ed8f6ca7f8d44b6a8a54ae39640fa8ad5c673f70ee9ce074ba4ef0d483eea00bab2f61d8695d6b34df9c6c48ae36246362200ed820448bdc03a720366a87c6", + }, + { + "The days of the digital watch are numbered. -Tom Stoppard", + "e6fbf82df5138bf361e826903cadf0612cb2986649ba47a57e1bca99", + "5625ecb9d284e54c00b257b67a8cacb25a78db2845c60ef2d29e43c84f236e8e", + "c3d4f0f4047181c7d39d34703365f7bf70207183caf2c2f6145f04da895ef69124d9cdeb635da636c3a474e61024e29b", + "e5a14bf044be69615aade89afcf1ab0389d5fc302a884d403579d1386a2400c089b0dbb387ed0f463f9ee342f8244d5a38cfbc0e819da9529fbff78368c9a982", + }, + { + "Nepal premier won't resign.", + "6ec2cb2ecafc1a9bddaf4caf57344d853e6ded398927d5694fd7714f", + "9b81d06bca2f985e6ad3249096ff3c0f2a9ec5bb16ef530d738d19d81e7806f2", + "a097aab567e167d5cf93676ed73252a69f9687cb3179bb2d27c9878119e94bf7b7c4b58dc90582edfaf66e11388ed714", + "420a1faa48919e14651bed45725abe0f7a58e0f099424c4e5a49194946e38b46c1f8034b18ef169b2e31050d1648e0b982386595f7df47da4b6fd18e55333015", + }, + { + "For every action there is an equal and opposite government program.", + "7f62f36e716e0badaf4a4658da9d09bea26357a1bc6aeb8cf7c3ae35", + "08241df8d91edfcd68bb1a1dada6e0ae1475a5c6e7b8f12d8e24ca43a38240a9", + "5026ca45c41fc64712eb65065da92f6467541c78f8966d3fe2c8e3fb769a3ec14215f819654b47bd64f7f0eac17184f3", + "d926a863beadb20134db07683535c72007b0e695045876254f341ddcccde132a908c5af57baa6a6a9c63e6649bba0c213dc05fadcf9abccea09f23dcfb637fbe", + }, + { + "His money is twice tainted: 'taint yours and 'taint mine.", + "45adffcb86a05ee4d91263a6115dda011b805d442c60836963cb8378", + "4ff74d9213a8117745f5d37b5353a774ec81c5dfe65c4c8986a56fc01f2c551e", + "ac1cc0f5ac8d5f5514a7b738ac322b7fb52a161b449c3672e9b6a6ad1a5e4b26b001cf3bad24c56598676ca17d4b445a", + "9a98dd9bb67d0da7bf83da5313dff4fd60a4bac0094f1b05633690ffa7f6d61de9a1d4f8617937d560833a9aaa9ccafe3fd24db418d0e728833545cadd3ad92d", + }, + { + "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977", + "51cb518f1f68daa901a3075a0a5e1acc755b4e5c82cb47687537f880", + "b5baf747c307f98849ec881cf0d48605ae4edd386372aea9b26e71db517e650b", + "722d10c5de371ec0c8c4b5247ac8a5f1d240d68c73f8da13d8b25f0166d6f309bf9561979a111a0049405771d201941a", + "d7fde2d2351efade52f4211d3746a0780a26eec3df9b2ed575368a8a1c09ec452402293a8ea4eceb5a4f60064ea29b13cdd86918cd7a4faf366160b009804107", + }, + { + "It's a tiny change to the code and not completely disgusting. - Bob Manchek", + "3b59c5e64b0da7bfc18d7017bf458d90f2c83601ff1afc6263ac0993", + "7eef0538ebd7ecf18611d23b0e1cd26a74d65b929a2e374197dc66e755ca4944", + "dc2d3ea18bfa10549c63bf2b75b39b5167a80c12aff0e05443168ea87ff149fb0eda5e0bd234eb5d48c7d02ffc5807f1", + "b0f35ffa2697359c33a56f5c0cf715c7aeed96da9905ca2698acadb08fbc9e669bf566b6bd5d61a3e86dc22999bcc9f2224e33d1d4f32a228cf9d0349e2db518", + }, + { + "size: a.out: bad magic", + "6a9525c0fac0f91b489bc4f0f539b9ec4a156a4e98bc15b655c2c881", + "d05600964f83f55323104aadab434f32391c029718a7690d08ddb2d7e8708443", + "1d67c969e2a945ae5346d2139760261504d4ba164c522443afe19ef3e29b152a4c52445489cfc9d7215e5a450e8e1e4e", + "3d2e5f91778c9e66f7e061293aaa8a8fc742dd3b2e4f483772464b1144189b49273e610e5cccd7a81a19ca1fa70f16b10f1a100a4d8c1372336be8484c64b311", + }, + { + "The major problem is with sendmail. -Mark Horton", + "a1b2b2905b1527d682049c6a76e35c7d8c72551abfe7833ac1be595f", + "53ed5f9b5c0b674ac0f3425d9f9a5d462655b07cc90f5d0f692eec093884a607", + "5ff8e075e465646e7b73ef36d812c6e9f7d60fa6ea0e533e5569b4f73cde53cdd2cc787f33540af57cca3fe467d32fe0", + "b2f68ff58ac015efb1c94c908b0d8c2bf06f491e4de8e6302c49016f7f8a33eac3e959856c7fddbc464de618701338a4b46f76dbfaf9a1e5262b5f40639771c7", + }, + { + "Give me a rock, paper and scissors and I will move the world. CCFestoon", + "76cf045c76a5f2e3d64d56c3cdba6a25479334611bc375460526f8c1", + "5a0147685a44eea2435dbd582724efca7637acd9c428e5e1a05115bc3bc2a0e0", + "5bd0a997a67c9ae1979a894eb0cde403dde003c9b6f2c03cf21925c42ff4e1176e6df1ca005381612ef18457b9b7ec3b", + "d8c92db5fdf52cf8215e4df3b4909d29203ff4d00e9ad0b64a6a4e04dec5e74f62e7c35c7fb881bd5de95442123df8f57a489b0ae616bd326f84d10021121c57", + }, + { + "If the enemy is within range, then so are you.", + "4473671daeecfdb6f6c5bc06b26374aa5e497cc37119fe14144c430c", + "1152c9b27a99dbf4057d21438f4e63dd0cd0977d5ff12317c64d3b97fcac875a", + "1eee6da33e7e54fc5be52ae23b94b16ba4d2a947ae4505c6a3edfc7401151ea5205ac01b669b56f27d8ef7f175ed7762", + "19a9f8dc0a233e464e8566ad3ca9b91e459a7b8c4780985b015776e1bf239a19bc233d0556343e2b0a9bc220900b4ebf4f8bdf89ff8efeaf79602d6849e6f72e", + }, + { + "It's well we cannot hear the screams/That we create in others' dreams.", + "6accb6394758523fcd453d47d37ebd10868957a0a9e81c796736abf8", + "105e890f5d5cf1748d9a7b4cdaf58b69855779deebc2097747c2210a17b2cb51", + "76b06e9dea66bfbb1a96029426dc0dfd7830bd297eb447ff5358d94a87cd00c88b59df2493fef56ecbb5231073892ea9", + "00b4c41f307bde87301cdc5b5ab1ae9a592e8ecbb2021dd7bc4b34e2ace60741cc362560bec566ba35178595a91932b8d5357e2c9cec92d393b0fa7831852476", + }, + { + "You remind me of a TV show, but that's all right: I watch it anyway.", + "6f173f4b6eac7f2a73eaa0833c4563752df2c869dc00b7d30219e12e", + "74644ead770da1434365cd912656fe1aca2056d3039d39f10eb1151bddb32cf3", + "12acaf21452cff586143e3f5db0bfdf7802c057e1adf2a619031c4e1b0ccc4208cf6cef8fe722bbaa2fb46a30d9135d8", + "91eccc3d5375fd026e4d6787874b1dce201cecd8a27dbded5065728cb2d09c58a3d467bb1faf353bf7ba567e005245d5321b55bc344f7c07b91cb6f26c959be7", + }, + { + "C is as portable as Stonehedge!!", + "db05bf4d0f73325208755f4af96cfac6cb3db5dbfc323d675d68f938", + "50a234625de5587581883dad9ef399460928032a5ea6bd005d7dc7b68d8cc3d6", + "0fc23d7f4183efd186f0bc4fc5db867e026e2146b06cb3d52f4bdbd57d1740122caa853b41868b197b2ac759db39df88", + "fabbbe22180f1f137cfdc9556d2570e775d1ae02a597ded43a72a40f9b485d500043b7be128fb9fcd982b83159a0d99aa855a9e7cc4240c00dc01a9bdf8218d7", + }, + { + "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley", + "05ffa71bb02e855de1aaee1777b3bdbaf7507646f19c4c6aa29933d0", + "a7a3846005f8a9935a0a2d43e7fd56d95132a9a3609bf3296ef80b8218acffa0", + "bc805578a7f85d34a86a32976e1c34fe65cf815186fbef76f46ef99cda10723f971f3f1464d488243f5e29db7488598d", + "2ecdec235c1fa4fc2a154d8fba1dddb8a72a1ad73838b51d792331d143f8b96a9f6fcb0f34d7caa351fe6d88771c4f105040e0392f06e0621689d33b2f3ba92e", + }, + { + "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule", + "3ad3c89e15b91e6273534c5d18adadbb528e7b840b288f64e81b8c6d", + "688ff03e367680757aa9906cb1e2ad218c51f4526dc0426ea229a5ba9d002c69", + "b23918399a12ebf4431559eec3813eaf7412e875fd7464f16d581e473330842d2e96c6be49a7ce3f9bb0b8bc0fcbe0fe", + "7ad681f6f96f82f7abfa7ecc0334e8fa16d3dc1cdc45b60b7af43fe4075d2357c0c1d60e98350f1afb1f2fe7a4d7cd2ad55b88e458e06b73c40b437331f5dab4", + }, + { + "How can you write a big system without C++? -Paul Glick", + "e3763669d1b760c1be7bfcb6625f92300a8430419d1dbad57ec9f53c", + "3fa46d52094b01021cff5af9a438982b887a5793f624c0a6644149b6b7c3f485", + "1764b700eb1ead52a2fc33cc28975c2180f1b8faa5038d94cffa8d78154aab16e91dd787e7b0303948ebed62561542c8", + "833f9248ab4a3b9e5131f745fda1ffd2dd435b30e965957e78291c7ab73605fd1912b0794e5c233ab0a12d205a39778d19b83515d6a47003f19cdee51d98c7e0", + }, } -var golden384 = []sha512Test{ - {"38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b", ""}, - {"54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31", "a"}, - {"c7be03ba5bcaa384727076db0018e99248e1a6e8bd1b9ef58a9ec9dd4eeebb3f48b836201221175befa74ddc3d35afdd", "ab"}, - {"cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7", "abc"}, - {"1165b3406ff0b52a3d24721f785462ca2276c9f454a116c2b2ba20171a7905ea5a026682eb659c4d5f115c363aa3c79b", "abcd"}, - {"4c525cbeac729eaf4b4665815bc5db0c84fe6300068a727cf74e2813521565abc0ec57a37ee4d8be89d097c0d2ad52f0", "abcde"}, - {"c6a4c65b227e7387b9c3e839d44869c4cfca3ef583dea64117859b808c1e3d8ae689e1e314eeef52a6ffe22681aa11f5", "abcdef"}, - {"9f11fc131123f844c1226f429b6a0a6af0525d9f40f056c7fc16cdf1b06bda08e302554417a59fa7dcf6247421959d22", "abcdefg"}, - {"9000cd7cada59d1d2eb82912f7f24e5e69cc5517f68283b005fa27c285b61e05edf1ad1a8a9bded6fd29eb87d75ad806", "abcdefgh"}, - {"ef54915b60cf062b8dd0c29ae3cad69abe6310de63ac081f46ef019c5c90897caefd79b796cfa81139788a260ded52df", "abcdefghi"}, - {"a12070030a02d86b0ddacd0d3a5b598344513d0a051e7355053e556a0055489c1555399b03342845c4adde2dc44ff66c", "abcdefghij"}, - {"86f58ec2d74d1b7f8eb0c2ff0967316699639e8d4eb129de54bdf34c96cdbabe200d052149f2dd787f43571ba74670d4", "Discard medicine more than two years old."}, - {"ae4a2b639ca9bfa04b1855d5a05fe7f230994f790891c6979103e2605f660c4c1262a48142dcbeb57a1914ba5f7c3fa7", "He who has a shady past knows that nice guys finish last."}, - {"40ae213df6436eca952aa6841886fcdb82908ef1576a99c8f49bb9dd5023169f7c53035abdda0b54c302f4974e2105e7", "I wouldn't marry him with a ten foot pole."}, - {"e7cf8b873c9bc950f06259aa54309f349cefa72c00d597aebf903e6519a50011dfe355afff064a10701c705693848df9", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"}, - {"c3d4f0f4047181c7d39d34703365f7bf70207183caf2c2f6145f04da895ef69124d9cdeb635da636c3a474e61024e29b", "The days of the digital watch are numbered. -Tom Stoppard"}, - {"a097aab567e167d5cf93676ed73252a69f9687cb3179bb2d27c9878119e94bf7b7c4b58dc90582edfaf66e11388ed714", "Nepal premier won't resign."}, - {"5026ca45c41fc64712eb65065da92f6467541c78f8966d3fe2c8e3fb769a3ec14215f819654b47bd64f7f0eac17184f3", "For every action there is an equal and opposite government program."}, - {"ac1cc0f5ac8d5f5514a7b738ac322b7fb52a161b449c3672e9b6a6ad1a5e4b26b001cf3bad24c56598676ca17d4b445a", "His money is twice tainted: 'taint yours and 'taint mine."}, - {"722d10c5de371ec0c8c4b5247ac8a5f1d240d68c73f8da13d8b25f0166d6f309bf9561979a111a0049405771d201941a", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"}, - {"dc2d3ea18bfa10549c63bf2b75b39b5167a80c12aff0e05443168ea87ff149fb0eda5e0bd234eb5d48c7d02ffc5807f1", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"}, - {"1d67c969e2a945ae5346d2139760261504d4ba164c522443afe19ef3e29b152a4c52445489cfc9d7215e5a450e8e1e4e", "size: a.out: bad magic"}, - {"5ff8e075e465646e7b73ef36d812c6e9f7d60fa6ea0e533e5569b4f73cde53cdd2cc787f33540af57cca3fe467d32fe0", "The major problem is with sendmail. -Mark Horton"}, - {"5bd0a997a67c9ae1979a894eb0cde403dde003c9b6f2c03cf21925c42ff4e1176e6df1ca005381612ef18457b9b7ec3b", "Give me a rock, paper and scissors and I will move the world. CCFestoon"}, - {"1eee6da33e7e54fc5be52ae23b94b16ba4d2a947ae4505c6a3edfc7401151ea5205ac01b669b56f27d8ef7f175ed7762", "If the enemy is within range, then so are you."}, - {"76b06e9dea66bfbb1a96029426dc0dfd7830bd297eb447ff5358d94a87cd00c88b59df2493fef56ecbb5231073892ea9", "It's well we cannot hear the screams/That we create in others' dreams."}, - {"12acaf21452cff586143e3f5db0bfdf7802c057e1adf2a619031c4e1b0ccc4208cf6cef8fe722bbaa2fb46a30d9135d8", "You remind me of a TV show, but that's all right: I watch it anyway."}, - {"0fc23d7f4183efd186f0bc4fc5db867e026e2146b06cb3d52f4bdbd57d1740122caa853b41868b197b2ac759db39df88", "C is as portable as Stonehedge!!"}, - {"bc805578a7f85d34a86a32976e1c34fe65cf815186fbef76f46ef99cda10723f971f3f1464d488243f5e29db7488598d", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"}, - {"b23918399a12ebf4431559eec3813eaf7412e875fd7464f16d581e473330842d2e96c6be49a7ce3f9bb0b8bc0fcbe0fe", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule"}, - {"1764b700eb1ead52a2fc33cc28975c2180f1b8faa5038d94cffa8d78154aab16e91dd787e7b0303948ebed62561542c8", "How can you write a big system without C++? -Paul Glick"}, -} +func testHash(t *testing.T, name, in, outHex string, oneShotResult []byte, digestFunc hash.Hash) { + if calculated := hex.EncodeToString(oneShotResult); calculated != outHex { + t.Errorf("one-shot result for %s(%q) = %q, but expected %q", name, in, calculated, outHex) + return + } -func TestGolden(t *testing.T) { - for i := 0; i < len(golden); i++ { - g := golden[i] - s := fmt.Sprintf("%x", Sum512([]byte(g.in))) - if s != g.out { - t.Fatalf("Sum512 function: sha512(%s) = %s want %s", g.in, s, g.out) + for pass := 0; pass < 3; pass++ { + if pass < 2 { + io.WriteString(digestFunc, in) + } else { + io.WriteString(digestFunc, in[:len(in)/2]) + digestFunc.Sum(nil) + io.WriteString(digestFunc, in[len(in)/2:]) } - c := New() - for j := 0; j < 3; j++ { - if j < 2 { - io.WriteString(c, g.in) - } else { - io.WriteString(c, g.in[0:len(g.in)/2]) - c.Sum(nil) - io.WriteString(c, g.in[len(g.in)/2:]) - } - s := fmt.Sprintf("%x", c.Sum(nil)) - if s != g.out { - t.Fatalf("sha512[%d](%s) = %s want %s", j, g.in, s, g.out) - } - c.Reset() + + if calculated := hex.EncodeToString(digestFunc.Sum(nil)); calculated != outHex { + t.Errorf("%s(%q) = %q (in pass #%d), but expected %q", name, in, calculated, pass, outHex) } + digestFunc.Reset() } - for i := 0; i < len(golden384); i++ { - g := golden384[i] - s := fmt.Sprintf("%x", Sum384([]byte(g.in))) - if s != g.out { - t.Fatalf("Sum384 function: sha384(%s) = %s want %s", g.in, s, g.out) - } - c := New384() - for j := 0; j < 3; j++ { - if j < 2 { - io.WriteString(c, g.in) - } else { - io.WriteString(c, g.in[0:len(g.in)/2]) - c.Sum(nil) - io.WriteString(c, g.in[len(g.in)/2:]) - } - s := fmt.Sprintf("%x", c.Sum(nil)) - if s != g.out { - t.Fatalf("sha384[%d](%s) = %s want %s", j, g.in, s, g.out) - } - c.Reset() - } +} + +func TestGolden(t *testing.T) { + for _, test := range golden { + in := []byte(test.in) + + sum224 := Sum512_224(in) + sum256 := Sum512_256(in) + sum384 := Sum384(in) + sum512 := Sum512(in) + testHash(t, "SHA512/224", test.in, test.out224, sum224[:], New512_224()) + testHash(t, "SHA512/256", test.in, test.out256, sum256[:], New512_256()) + testHash(t, "SHA384", test.in, test.out384, sum384[:], New384()) + testHash(t, "SHA512", test.in, test.out512, sum512[:], New()) } } @@ -141,6 +287,14 @@ func TestSize(t *testing.T) { if got := c.Size(); got != Size384 { t.Errorf("New384.Size = %d; want %d", got, Size384) } + c = New512_224() + if got := c.Size(); got != Size224 { + t.Errorf("New512224.Size = %d; want %d", got, Size224) + } + c = New512_256() + if got := c.Size(); got != Size256 { + t.Errorf("New512256.Size = %d; want %d", got, Size256) + } } func TestBlockSize(t *testing.T) { diff --git a/libgo/go/crypto/tls/cipher_suites.go b/libgo/go/crypto/tls/cipher_suites.go index 226e06d68d6..a5fed293752 100644 --- a/libgo/go/crypto/tls/cipher_suites.go +++ b/libgo/go/crypto/tls/cipher_suites.go @@ -48,6 +48,12 @@ const ( // suiteTLS12 indicates that the cipher suite should only be advertised // and accepted when using TLS 1.2. suiteTLS12 + // suiteSHA384 indicates that the cipher suite uses SHA384 as the + // handshake hash. + suiteSHA384 + // suiteDefaultOff indicates that this cipher suite is not included by + // default. + suiteDefaultOff ) // A cipherSuite is a specific combination of key agreement, cipher and MAC @@ -71,13 +77,15 @@ var cipherSuites = []*cipherSuite{ // and RC4 comes before AES (because of the Lucky13 attack). {TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadAESGCM}, {TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12, nil, nil, aeadAESGCM}, - {TLS_ECDHE_RSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheRSAKA, suiteECDHE, cipherRC4, macSHA1, nil}, - {TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherRC4, macSHA1, nil}, + {TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM}, + {TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM}, + {TLS_ECDHE_RSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheRSAKA, suiteECDHE | suiteDefaultOff, cipherRC4, macSHA1, nil}, + {TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteDefaultOff, cipherRC4, macSHA1, nil}, {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil}, {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherAES, macSHA1, nil}, {TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil}, {TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherAES, macSHA1, nil}, - {TLS_RSA_WITH_RC4_128_SHA, 16, 20, 0, rsaKA, 0, cipherRC4, macSHA1, nil}, + {TLS_RSA_WITH_RC4_128_SHA, 16, 20, 0, rsaKA, suiteDefaultOff, cipherRC4, macSHA1, nil}, {TLS_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil}, {TLS_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil}, {TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, ecdheRSAKA, suiteECDHE, cipher3DES, macSHA1, nil}, @@ -267,6 +275,8 @@ const ( TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA uint16 = 0xc014 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0xc02f TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 uint16 = 0xc02b + TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0xc030 + TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 uint16 = 0xc02c // TLS_FALLBACK_SCSV isn't a standard cipher suite but an indicator // that the client is doing version fallback. See diff --git a/libgo/go/crypto/tls/common.go b/libgo/go/crypto/tls/common.go index 776b70c93c8..a3d75d69cbf 100644 --- a/libgo/go/crypto/tls/common.go +++ b/libgo/go/crypto/tls/common.go @@ -8,7 +8,9 @@ import ( "container/list" "crypto" "crypto/rand" + "crypto/sha512" "crypto/x509" + "errors" "fmt" "io" "math/big" @@ -30,7 +32,7 @@ const ( recordHeaderLen = 5 // record header length maxHandshake = 65536 // maximum handshake we support (protocol max is 16 MB) - minVersion = VersionSSL30 + minVersion = VersionTLS10 maxVersion = VersionTLS12 ) @@ -73,6 +75,7 @@ const ( extensionSupportedPoints uint16 = 11 extensionSignatureAlgorithms uint16 = 13 extensionALPN uint16 = 16 + extensionSCT uint16 = 18 // https://tools.ietf.org/html/rfc6962#section-6 extensionSessionTicket uint16 = 35 extensionNextProtoNeg uint16 = 13172 // not IANA assigned extensionRenegotiationInfo uint16 = 0xff01 @@ -123,6 +126,7 @@ const ( const ( hashSHA1 uint8 = 2 hashSHA256 uint8 = 4 + hashSHA384 uint8 = 5 ) // Signature algorithms for TLS 1.2 (See RFC 5246, section A.4.1) @@ -137,34 +141,31 @@ type signatureAndHash struct { hash, signature uint8 } -// supportedSKXSignatureAlgorithms contains the signature and hash algorithms -// that the code advertises as supported in a TLS 1.2 ClientHello. -var supportedSKXSignatureAlgorithms = []signatureAndHash{ +// supportedSignatureAlgorithms contains the signature and hash algorithms that +// the code advertises as supported in a TLS 1.2 ClientHello and in a TLS 1.2 +// CertificateRequest. +var supportedSignatureAlgorithms = []signatureAndHash{ {hashSHA256, signatureRSA}, {hashSHA256, signatureECDSA}, + {hashSHA384, signatureRSA}, + {hashSHA384, signatureECDSA}, {hashSHA1, signatureRSA}, {hashSHA1, signatureECDSA}, } -// supportedClientCertSignatureAlgorithms contains the signature and hash -// algorithms that the code advertises as supported in a TLS 1.2 -// CertificateRequest. -var supportedClientCertSignatureAlgorithms = []signatureAndHash{ - {hashSHA256, signatureRSA}, - {hashSHA256, signatureECDSA}, -} - // ConnectionState records basic TLS details about the connection. type ConnectionState struct { - Version uint16 // TLS version used by the connection (e.g. VersionTLS12) - HandshakeComplete bool // TLS handshake is complete - DidResume bool // connection resumes a previous TLS connection - CipherSuite uint16 // cipher suite in use (TLS_RSA_WITH_RC4_128_SHA, ...) - NegotiatedProtocol string // negotiated next protocol (from Config.NextProtos) - NegotiatedProtocolIsMutual bool // negotiated protocol was advertised by server - ServerName string // server name requested by client, if any (server side only) - PeerCertificates []*x509.Certificate // certificate chain presented by remote peer - VerifiedChains [][]*x509.Certificate // verified chains built from PeerCertificates + Version uint16 // TLS version used by the connection (e.g. VersionTLS12) + HandshakeComplete bool // TLS handshake is complete + DidResume bool // connection resumes a previous TLS connection + CipherSuite uint16 // cipher suite in use (TLS_RSA_WITH_RC4_128_SHA, ...) + NegotiatedProtocol string // negotiated next protocol (from Config.NextProtos) + NegotiatedProtocolIsMutual bool // negotiated protocol was advertised by server + ServerName string // server name requested by client, if any (server side only) + PeerCertificates []*x509.Certificate // certificate chain presented by remote peer + VerifiedChains [][]*x509.Certificate // verified chains built from PeerCertificates + SignedCertificateTimestamps [][]byte // SCTs from the server, if any + OCSPResponse []byte // stapled OCSP response from server, if any // TLSUnique contains the "tls-unique" channel binding value (see RFC // 5929, section 3). For resumed sessions this value will be nil @@ -190,11 +191,12 @@ const ( // ClientSessionState contains the state needed by clients to resume TLS // sessions. type ClientSessionState struct { - sessionTicket []uint8 // Encrypted ticket used for session resumption with server - vers uint16 // SSL/TLS version negotiated for the session - cipherSuite uint16 // Ciphersuite negotiated for the session - masterSecret []byte // MasterSecret generated by client on a full handshake - serverCertificates []*x509.Certificate // Certificate chain presented by the server + sessionTicket []uint8 // Encrypted ticket used for session resumption with server + vers uint16 // SSL/TLS version negotiated for the session + cipherSuite uint16 // Ciphersuite negotiated for the session + masterSecret []byte // MasterSecret generated by client on a full handshake + serverCertificates []*x509.Certificate // Certificate chain presented by the server + verifiedChains [][]*x509.Certificate // Certificate chains we built for verification } // ClientSessionCache is a cache of ClientSessionState objects that can be used @@ -265,10 +267,12 @@ type Config struct { NameToCertificate map[string]*Certificate // GetCertificate returns a Certificate based on the given - // ClientHelloInfo. If GetCertificate is nil or returns nil, then the - // certificate is retrieved from NameToCertificate. If - // NameToCertificate is nil, the first element of Certificates will be - // used. + // ClientHelloInfo. It will only be called if the client supplies SNI + // information or if Certificates is empty. + // + // If GetCertificate is nil or returns nil, then the certificate is + // retrieved from NameToCertificate. If NameToCertificate is nil, the + // first element of Certificates will be used. GetCertificate func(clientHello *ClientHelloInfo) (*Certificate, error) // RootCAs defines the set of root certificate authorities @@ -330,7 +334,7 @@ type Config struct { ClientSessionCache ClientSessionCache // MinVersion contains the minimum SSL/TLS version that is acceptable. - // If zero, then SSLv3 is taken as the minimum. + // If zero, then TLS 1.0 is taken as the minimum. MinVersion uint16 // MaxVersion contains the maximum SSL/TLS version that is acceptable. @@ -344,6 +348,38 @@ type Config struct { CurvePreferences []CurveID serverInitOnce sync.Once // guards calling (*Config).serverInit + + // mutex protects sessionTicketKeys + mutex sync.RWMutex + // sessionTicketKeys contains zero or more ticket keys. If the length + // is zero, SessionTicketsDisabled must be true. The first key is used + // for new tickets and any subsequent keys can be used to decrypt old + // tickets. + sessionTicketKeys []ticketKey +} + +// ticketKeyNameLen is the number of bytes of identifier that is prepended to +// an encrypted session ticket in order to identify the key used to encrypt it. +const ticketKeyNameLen = 16 + +// ticketKey is the internal representation of a session ticket key. +type ticketKey struct { + // keyName is an opaque byte string that serves to identify the session + // ticket key. It's exposed as plaintext in every session ticket. + keyName [ticketKeyNameLen]byte + aesKey [16]byte + hmacKey [16]byte +} + +// ticketKeyFromBytes converts from the external representation of a session +// ticket key to a ticketKey. Externally, session ticket keys are 32 random +// bytes and this function expands that into sufficient name and key material. +func ticketKeyFromBytes(b [32]byte) (key ticketKey) { + hashed := sha512.Sum512(b[:]) + copy(key.keyName[:], hashed[:ticketKeyNameLen]) + copy(key.aesKey[:], hashed[ticketKeyNameLen:ticketKeyNameLen+16]) + copy(key.hmacKey[:], hashed[ticketKeyNameLen+16:ticketKeyNameLen+32]) + return key } func (c *Config) serverInit() { @@ -351,16 +387,51 @@ func (c *Config) serverInit() { return } - // If the key has already been set then we have nothing to do. + alreadySet := false for _, b := range c.SessionTicketKey { if b != 0 { + alreadySet = true + break + } + } + + if !alreadySet { + if _, err := io.ReadFull(c.rand(), c.SessionTicketKey[:]); err != nil { + c.SessionTicketsDisabled = true return } } - if _, err := io.ReadFull(c.rand(), c.SessionTicketKey[:]); err != nil { - c.SessionTicketsDisabled = true + c.sessionTicketKeys = []ticketKey{ticketKeyFromBytes(c.SessionTicketKey)} +} + +func (c *Config) ticketKeys() []ticketKey { + c.mutex.RLock() + // c.sessionTicketKeys is constant once created. SetSessionTicketKeys + // will only update it by replacing it with a new value. + ret := c.sessionTicketKeys + c.mutex.RUnlock() + return ret +} + +// SetSessionTicketKeys updates the session ticket keys for a server. The first +// key will be used when creating new tickets, while all keys can be used for +// decrypting tickets. It is safe to call this function while the server is +// running in order to rotate the session ticket keys. The function will panic +// if keys is empty. +func (c *Config) SetSessionTicketKeys(keys [][32]byte) { + if len(keys) == 0 { + panic("tls: keys must have at least one key") } + + newKeys := make([]ticketKey, len(keys)) + for i, bytes := range keys { + newKeys[i] = ticketKeyFromBytes(bytes) + } + + c.mutex.Lock() + c.sessionTicketKeys = newKeys + c.mutex.Unlock() } func (c *Config) rand() io.Reader { @@ -428,13 +499,18 @@ func (c *Config) mutualVersion(vers uint16) (uint16, bool) { // getCertificate returns the best certificate for the given ClientHelloInfo, // defaulting to the first element of c.Certificates. func (c *Config) getCertificate(clientHello *ClientHelloInfo) (*Certificate, error) { - if c.GetCertificate != nil { + if c.GetCertificate != nil && + (len(c.Certificates) == 0 || len(clientHello.ServerName) > 0) { cert, err := c.GetCertificate(clientHello) if cert != nil || err != nil { return cert, err } } + if len(c.Certificates) == 0 { + return nil, errors.New("crypto/tls: no certificates configured") + } + if len(c.Certificates) == 1 || c.NameToCertificate == nil { // There's only one choice, so no point doing any work. return &c.Certificates[0], nil @@ -488,14 +564,17 @@ func (c *Config) BuildNameToCertificate() { type Certificate struct { Certificate [][]byte // PrivateKey contains the private key corresponding to the public key - // in Leaf. For a server, this must be a *rsa.PrivateKey or - // *ecdsa.PrivateKey. For a client doing client authentication, this - // can be any type that implements crypto.Signer (which includes RSA - // and ECDSA private keys). + // in Leaf. For a server, this must implement crypto.Signer and/or + // crypto.Decrypter, with an RSA or ECDSA PublicKey. For a client + // (performing client authentication), this must be a crypto.Signer + // with an RSA or ECDSA PublicKey. PrivateKey crypto.PrivateKey // OCSPStaple contains an optional OCSP response which will be served // to clients that request it. OCSPStaple []byte + // SignedCertificateTimestamps contains an optional list of Signed + // Certificate Timestamps which will be served to clients that request it. + SignedCertificateTimestamps [][]byte // Leaf is the parsed form of the leaf certificate, which may be // initialized using x509.ParseCertificate to reduce per-handshake // processing for TLS clients doing client authentication. If nil, the @@ -610,12 +689,24 @@ func defaultCipherSuites() []uint16 { } func initDefaultCipherSuites() { - varDefaultCipherSuites = make([]uint16, len(cipherSuites)) - for i, suite := range cipherSuites { - varDefaultCipherSuites[i] = suite.id + varDefaultCipherSuites = make([]uint16, 0, len(cipherSuites)) + for _, suite := range cipherSuites { + if suite.flags&suiteDefaultOff != 0 { + continue + } + varDefaultCipherSuites = append(varDefaultCipherSuites, suite.id) } } func unexpectedMessageError(wanted, got interface{}) error { return fmt.Errorf("tls: received unexpected handshake message of type %T when waiting for %T", got, wanted) } + +func isSupportedSignatureAndHash(sigHash signatureAndHash, sigHashes []signatureAndHash) bool { + for _, s := range sigHashes { + if s == sigHash { + return true + } + } + return false +} diff --git a/libgo/go/crypto/tls/conn.go b/libgo/go/crypto/tls/conn.go index ba8e4c22b70..e3dcf15400c 100644 --- a/libgo/go/crypto/tls/conn.go +++ b/libgo/go/crypto/tls/conn.go @@ -35,7 +35,8 @@ type Conn struct { handshakeComplete bool didResume bool // whether this connection was a session resumption cipherSuite uint16 - ocspResponse []byte // stapled OCSP response + ocspResponse []byte // stapled OCSP response + scts [][]byte // signed certificate timestamps from server peerCertificates []*x509.Certificate // verifiedChains contains the certificate chains that we built, as // opposed to the ones presented by the server. @@ -570,15 +571,11 @@ Again: return c.in.setErrorLocked(fmt.Errorf("tls: oversized record received with length %d", n)) } if !c.haveVers { - // First message, be extra suspicious: - // this might not be a TLS client. - // Bail out before reading a full 'body', if possible. - // The current max version is 3.1. - // If the version is >= 16.0, it's probably not real. - // Similarly, a clientHello message encodes in - // well under a kilobyte. If the length is >= 12 kB, + // First message, be extra suspicious: this might not be a TLS + // client. Bail out before reading a full 'body', if possible. + // The current max version is 3.3 so if the version is >= 16.0, // it's probably not real. - if (typ != recordTypeAlert && typ != want) || vers >= 0x1000 || n >= 0x3000 { + if (typ != recordTypeAlert && typ != want) || vers >= 0x1000 { c.sendAlert(alertUnexpectedMessage) return c.in.setErrorLocked(fmt.Errorf("tls: first record does not look like a TLS handshake")) } @@ -926,7 +923,7 @@ func (c *Conn) Read(b []byte) (n int, err error) { // tried to reuse the HTTP connection for a new // request. // See https://codereview.appspot.com/76400046 - // and http://golang.org/issue/3514 + // and https://golang.org/issue/3514 if ri := c.rawInput; ri != nil && n != 0 && err == nil && c.input == nil && len(ri.data) > 0 && recordType(ri.data[0]) == recordTypeAlert { @@ -997,6 +994,8 @@ func (c *Conn) ConnectionState() ConnectionState { state.PeerCertificates = c.peerCertificates state.VerifiedChains = c.verifiedChains state.ServerName = c.serverName + state.SignedCertificateTimestamps = c.scts + state.OCSPResponse = c.ocspResponse if !c.didResume { state.TLSUnique = c.firstFinished[:] } @@ -1026,5 +1025,8 @@ func (c *Conn) VerifyHostname(host string) error { if !c.handshakeComplete { return errors.New("tls: handshake has not yet been performed") } + if len(c.verifiedChains) == 0 { + return errors.New("tls: handshake did not verify certificate chain") + } return c.peerCertificates[0].VerifyHostname(host) } diff --git a/libgo/go/crypto/tls/handshake_client.go b/libgo/go/crypto/tls/handshake_client.go index 7f662e9c9f3..0b591d7309c 100644 --- a/libgo/go/crypto/tls/handshake_client.go +++ b/libgo/go/crypto/tls/handshake_client.go @@ -54,6 +54,7 @@ func (c *Conn) clientHandshake() error { compressionMethods: []uint8{compressionNone}, random: make([]byte, 32), ocspStapling: true, + scts: true, serverName: c.config.ServerName, supportedCurves: c.config.curvePreferences(), supportedPoints: []uint8{pointFormatUncompressed}, @@ -88,7 +89,7 @@ NextCipherSuite: } if hello.vers >= VersionTLS12 { - hello.signatureAndHashes = supportedSKXSignatureAlgorithms + hello.signatureAndHashes = supportedSignatureAlgorithms } var session *ClientSessionState @@ -168,18 +169,26 @@ NextCipherSuite: serverHello: serverHello, hello: hello, suite: suite, - finishedHash: newFinishedHash(c.vers), + finishedHash: newFinishedHash(c.vers, suite), session: session, } - hs.finishedHash.Write(hs.hello.marshal()) - hs.finishedHash.Write(hs.serverHello.marshal()) - isResume, err := hs.processServerHello() if err != nil { return err } + // No signatures of the handshake are needed in a resumption. + // Otherwise, in a full handshake, if we don't have any certificates + // configured then we will never send a CertificateVerify message and + // thus no signatures are needed in that case either. + if isResume || len(c.config.Certificates) == 0 { + hs.finishedHash.discardHandshakeBuffer() + } + + hs.finishedHash.Write(hs.hello.marshal()) + hs.finishedHash.Write(hs.serverHello.marshal()) + if isResume { if err := hs.establishKeys(); err != nil { return err @@ -423,7 +432,6 @@ func (hs *clientHandshakeState) doFullHandshake() error { } if chainToSend != nil { - var signed []byte certVerify := &certificateVerifyMsg{ hasSignatureAndHash: c.vers >= VersionTLS12, } @@ -433,31 +441,42 @@ func (hs *clientHandshakeState) doFullHandshake() error { c.sendAlert(alertInternalError) return fmt.Errorf("tls: client certificate private key of type %T does not implement crypto.Signer", chainToSend.PrivateKey) } + + var signatureType uint8 switch key.Public().(type) { case *ecdsa.PublicKey: - digest, hashFunc, hashId := hs.finishedHash.hashForClientCertificate(signatureECDSA) - signed, err = key.Sign(c.config.rand(), digest, hashFunc) - certVerify.signatureAndHash.signature = signatureECDSA - certVerify.signatureAndHash.hash = hashId + signatureType = signatureECDSA case *rsa.PublicKey: - digest, hashFunc, hashId := hs.finishedHash.hashForClientCertificate(signatureRSA) - signed, err = key.Sign(c.config.rand(), digest, hashFunc) - certVerify.signatureAndHash.signature = signatureRSA - certVerify.signatureAndHash.hash = hashId + signatureType = signatureRSA default: - err = fmt.Errorf("tls: unknown client certificate key type: %T", key) + c.sendAlert(alertInternalError) + return fmt.Errorf("tls: failed to sign handshake with client certificate: unknown client certificate key type: %T", key) + } + + certVerify.signatureAndHash, err = hs.finishedHash.selectClientCertSignatureAlgorithm(certReq.signatureAndHashes, signatureType) + if err != nil { + c.sendAlert(alertInternalError) + return err } + digest, hashFunc, err := hs.finishedHash.hashForClientCertificate(certVerify.signatureAndHash, hs.masterSecret) if err != nil { c.sendAlert(alertInternalError) - return errors.New("tls: failed to sign handshake with client certificate: " + err.Error()) + return err + } + certVerify.signature, err = key.Sign(c.config.rand(), digest, hashFunc) + if err != nil { + c.sendAlert(alertInternalError) + return err } - certVerify.signature = signed hs.finishedHash.Write(certVerify.marshal()) c.writeRecord(recordTypeHandshake, certVerify.marshal()) } - hs.masterSecret = masterFromPreMasterSecret(c.vers, preMasterSecret, hs.hello.random, hs.serverHello.random) + hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.hello.random, hs.serverHello.random) + + hs.finishedHash.discardHandshakeBuffer() + return nil } @@ -465,7 +484,7 @@ func (hs *clientHandshakeState) establishKeys() error { c := hs.c clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV := - keysFromMasterSecret(c.vers, hs.masterSecret, hs.hello.random, hs.serverHello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen) + keysFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.hello.random, hs.serverHello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen) var clientCipher, serverCipher interface{} var clientHash, serverHash macFunction if hs.suite.cipher != nil { @@ -522,11 +541,13 @@ func (hs *clientHandshakeState) processServerHello() (bool, error) { c.clientProtocol = hs.serverHello.alpnProtocol c.clientProtocolFallback = false } + c.scts = hs.serverHello.scts if hs.serverResumedSession() { // Restore masterSecret and peerCerts from previous state hs.masterSecret = hs.session.masterSecret c.peerCertificates = hs.session.serverCertificates + c.verifiedChains = hs.session.verifiedChains return true, nil } return false, nil @@ -584,6 +605,7 @@ func (hs *clientHandshakeState) readSessionTicket() error { cipherSuite: hs.suite.id, masterSecret: hs.masterSecret, serverCertificates: c.peerCertificates, + verifiedChains: c.verifiedChains, } return nil diff --git a/libgo/go/crypto/tls/handshake_client_test.go b/libgo/go/crypto/tls/handshake_client_test.go index e5eaa7de208..664fe8de6a0 100644 --- a/libgo/go/crypto/tls/handshake_client_test.go +++ b/libgo/go/crypto/tls/handshake_client_test.go @@ -9,6 +9,8 @@ import ( "crypto/ecdsa" "crypto/rsa" "crypto/x509" + "encoding/base64" + "encoding/binary" "encoding/pem" "fmt" "io" @@ -49,6 +51,10 @@ type clientTest struct { // key, if not nil, contains either a *rsa.PrivateKey or // *ecdsa.PrivateKey which is the private key for the reference server. key interface{} + // extensions, if not nil, contains a list of extension data to be returned + // from the ServerHello. The data should be in standard TLS format with + // a 2-byte uint16 type, 2-byte data length, followed by the extension data. + extensions [][]byte // validate, if not nil, is a function that will be called with the // ConnectionState of the resulting connection. It returns a non-nil // error if the ConnectionState is unacceptable. @@ -111,6 +117,19 @@ func (test *clientTest) connFromCommand() (conn *recordingConn, child *exec.Cmd, const serverPort = 24323 command = append(command, "-accept", strconv.Itoa(serverPort)) + if len(test.extensions) > 0 { + var serverInfo bytes.Buffer + for _, ext := range test.extensions { + pem.Encode(&serverInfo, &pem.Block{ + Type: fmt.Sprintf("SERVERINFO FOR EXTENSION %d", binary.BigEndian.Uint16(ext)), + Bytes: ext, + }) + } + serverInfoPath := tempFile(serverInfo.String()) + defer os.Remove(serverInfoPath) + command = append(command, "-serverinfo", serverInfoPath) + } + cmd := exec.Command(command[0], command[1:]...) stdin = blockingSource(make(chan bool)) cmd.Stdin = stdin @@ -127,7 +146,6 @@ func (test *clientTest) connFromCommand() (conn *recordingConn, child *exec.Cmd, // connection. var tcpConn net.Conn for i := uint(0); i < 5; i++ { - var err error tcpConn, err = net.DialTCP("tcp", nil, &net.TCPAddr{ IP: net.IPv4(127, 0, 0, 1), Port: serverPort, @@ -137,7 +155,7 @@ func (test *clientTest) connFromCommand() (conn *recordingConn, child *exec.Cmd, } time.Sleep((1 << i) * 5 * time.Millisecond) } - if tcpConn == nil { + if err != nil { close(stdin) out.WriteTo(os.Stdout) cmd.Process.Kill() @@ -190,11 +208,11 @@ func (test *clientTest) run(t *testing.T, write bool) { doneChan := make(chan bool) go func() { if _, err := client.Write([]byte("hello\n")); err != nil { - t.Logf("Client.Write failed: %s", err) + t.Errorf("Client.Write failed: %s", err) } if test.validate != nil { if err := test.validate(client.ConnectionState()); err != nil { - t.Logf("validate callback returned error: %s", err) + t.Errorf("validate callback returned error: %s", err) } } client.Close() @@ -311,6 +329,16 @@ func TestHandshakeClientECDHEECDSAAESGCM(t *testing.T) { runClientTestTLS12(t, test) } +func TestHandshakeClientAES256GCMSHA384(t *testing.T) { + test := &clientTest{ + name: "ECDHE-ECDSA-AES256-GCM-SHA384", + command: []string{"openssl", "s_server", "-cipher", "ECDHE-ECDSA-AES256-GCM-SHA384"}, + cert: testECDSACertificate, + key: testECDSAPrivateKey, + } + runClientTestTLS12(t, test) +} + func TestHandshakeClientCertRSA(t *testing.T) { config := *testConfig cert, _ := X509KeyPair([]byte(clientCertificatePEM), []byte(clientKeyPEM)) @@ -335,6 +363,16 @@ func TestHandshakeClientCertRSA(t *testing.T) { runClientTestTLS10(t, test) runClientTestTLS12(t, test) + + test = &clientTest{ + name: "ClientCert-RSA-AES256-GCM-SHA384", + command: []string{"openssl", "s_server", "-cipher", "ECDHE-RSA-AES256-GCM-SHA384", "-verify", "1"}, + config: &config, + cert: testRSACertificate, + key: testRSAPrivateKey, + } + + runClientTestTLS12(t, test) } func TestHandshakeClientCertECDSA(t *testing.T) { @@ -368,31 +406,67 @@ func TestClientResumption(t *testing.T) { CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA}, Certificates: testConfig.Certificates, } + + issuer, err := x509.ParseCertificate(testRSACertificateIssuer) + if err != nil { + panic(err) + } + + rootCAs := x509.NewCertPool() + rootCAs.AddCert(issuer) + clientConfig := &Config{ CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA}, - InsecureSkipVerify: true, ClientSessionCache: NewLRUClientSessionCache(32), + RootCAs: rootCAs, + ServerName: "example.golang", } testResumeState := func(test string, didResume bool) { - hs, err := testHandshake(clientConfig, serverConfig) + _, hs, err := testHandshake(clientConfig, serverConfig) if err != nil { t.Fatalf("%s: handshake failed: %s", test, err) } if hs.DidResume != didResume { t.Fatalf("%s resumed: %v, expected: %v", test, hs.DidResume, didResume) } + if didResume && (hs.PeerCertificates == nil || hs.VerifiedChains == nil) { + t.Fatalf("expected non-nil certificates after resumption. Got peerCertificates: %#v, verifedCertificates: %#v", hs.PeerCertificates, hs.VerifiedChains) + } + } + + getTicket := func() []byte { + return clientConfig.ClientSessionCache.(*lruSessionCache).q.Front().Value.(*lruSessionCacheEntry).state.sessionTicket + } + randomKey := func() [32]byte { + var k [32]byte + if _, err := io.ReadFull(serverConfig.rand(), k[:]); err != nil { + t.Fatalf("Failed to read new SessionTicketKey: %s", err) + } + return k } testResumeState("Handshake", false) + ticket := getTicket() testResumeState("Resume", true) - - if _, err := io.ReadFull(serverConfig.rand(), serverConfig.SessionTicketKey[:]); err != nil { - t.Fatalf("Failed to invalidate SessionTicketKey") + if !bytes.Equal(ticket, getTicket()) { + t.Fatal("first ticket doesn't match ticket after resumption") } + + key2 := randomKey() + serverConfig.SetSessionTicketKeys([][32]byte{key2}) + testResumeState("InvalidSessionTicketKey", false) testResumeState("ResumeAfterInvalidSessionTicketKey", true) + serverConfig.SetSessionTicketKeys([][32]byte{randomKey(), key2}) + ticket = getTicket() + testResumeState("KeyChange", true) + if bytes.Equal(ticket, getTicket()) { + t.Fatal("new ticket wasn't included while resuming") + } + testResumeState("KeyChangeFinish", true) + clientConfig.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_RC4_128_SHA} testResumeState("DifferentCipherSuite", false) testResumeState("DifferentCipherSuiteRecovers", true) @@ -488,3 +562,41 @@ func TestHandshakeClientALPNNoMatch(t *testing.T) { } runClientTestTLS12(t, test) } + +// sctsBase64 contains data from `openssl s_client -serverinfo 18 -connect ritter.vg:443` +const sctsBase64 = "ABIBaQFnAHUApLkJkLQYWBSHuxOizGdwCjw1mAT5G9+443fNDsgN3BAAAAFHl5nuFgAABAMARjBEAiAcS4JdlW5nW9sElUv2zvQyPoZ6ejKrGGB03gjaBZFMLwIgc1Qbbn+hsH0RvObzhS+XZhr3iuQQJY8S9G85D9KeGPAAdgBo9pj4H2SCvjqM7rkoHUz8cVFdZ5PURNEKZ6y7T0/7xAAAAUeX4bVwAAAEAwBHMEUCIDIhFDgG2HIuADBkGuLobU5a4dlCHoJLliWJ1SYT05z6AiEAjxIoZFFPRNWMGGIjskOTMwXzQ1Wh2e7NxXE1kd1J0QsAdgDuS723dc5guuFCaR+r4Z5mow9+X7By2IMAxHuJeqj9ywAAAUhcZIqHAAAEAwBHMEUCICmJ1rBT09LpkbzxtUC+Hi7nXLR0J+2PmwLp+sJMuqK+AiEAr0NkUnEVKVhAkccIFpYDqHOlZaBsuEhWWrYpg2RtKp0=" + +func TestHandshakClientSCTs(t *testing.T) { + config := *testConfig + + scts, err := base64.StdEncoding.DecodeString(sctsBase64) + if err != nil { + t.Fatal(err) + } + + test := &clientTest{ + name: "SCT", + // Note that this needs OpenSSL 1.0.2 because that is the first + // version that supports the -serverinfo flag. + command: []string{"openssl", "s_server"}, + config: &config, + extensions: [][]byte{scts}, + validate: func(state ConnectionState) error { + expectedSCTs := [][]byte{ + scts[8:125], + scts[127:245], + scts[247:], + } + if n := len(state.SignedCertificateTimestamps); n != len(expectedSCTs) { + return fmt.Errorf("Got %d scts, wanted %d", n, len(expectedSCTs)) + } + for i, expected := range expectedSCTs { + if sct := state.SignedCertificateTimestamps[i]; !bytes.Equal(sct, expected) { + return fmt.Errorf("SCT #%d contained %x, expected %x", i, sct, expected) + } + } + return nil + }, + } + runClientTestTLS12(t, test) +} diff --git a/libgo/go/crypto/tls/handshake_messages.go b/libgo/go/crypto/tls/handshake_messages.go index 5d14871a348..799a776799a 100644 --- a/libgo/go/crypto/tls/handshake_messages.go +++ b/libgo/go/crypto/tls/handshake_messages.go @@ -16,6 +16,7 @@ type clientHelloMsg struct { nextProtoNeg bool serverName string ocspStapling bool + scts bool supportedCurves []CurveID supportedPoints []uint8 ticketSupported bool @@ -40,6 +41,7 @@ func (m *clientHelloMsg) equal(i interface{}) bool { m.nextProtoNeg == m1.nextProtoNeg && m.serverName == m1.serverName && m.ocspStapling == m1.ocspStapling && + m.scts == m1.scts && eqCurveIDs(m.supportedCurves, m1.supportedCurves) && bytes.Equal(m.supportedPoints, m1.supportedPoints) && m.ticketSupported == m1.ticketSupported && @@ -99,6 +101,9 @@ func (m *clientHelloMsg) marshal() []byte { } numExtensions++ } + if m.scts { + numExtensions++ + } if numExtensions > 0 { extensionsLength += 4 * numExtensions length += 2 + extensionsLength @@ -271,6 +276,13 @@ func (m *clientHelloMsg) marshal() []byte { lengths[0] = byte(stringsLength >> 8) lengths[1] = byte(stringsLength) } + if m.scts { + // https://tools.ietf.org/html/rfc6962#section-3.3.1 + z[0] = byte(extensionSCT >> 8) + z[1] = byte(extensionSCT) + // zero uint16 for the zero-length extension_data + z = z[4:] + } m.raw = x @@ -326,6 +338,7 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool { m.sessionTicket = nil m.signatureAndHashes = nil m.alpnProtocols = nil + m.scts = false if len(data) == 0 { // ClientHello is optionally followed by extension data @@ -354,12 +367,16 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool { switch extension { case extensionServerName: - if length < 2 { + d := data[:length] + if len(d) < 2 { return false } - numNames := int(data[0])<<8 | int(data[1]) - d := data[2:] - for i := 0; i < numNames; i++ { + namesLen := int(d[0])<<8 | int(d[1]) + d = d[2:] + if len(d) != namesLen { + return false + } + for len(d) > 0 { if len(d) < 3 { return false } @@ -370,7 +387,7 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool { return false } if nameType == 0 { - m.serverName = string(d[0:nameLen]) + m.serverName = string(d[:nameLen]) break } d = d[nameLen:] @@ -430,7 +447,7 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool { m.signatureAndHashes[i].signature = d[1] d = d[2:] } - case extensionRenegotiationInfo + 1: + case extensionRenegotiationInfo: if length != 1 || data[0] != 0 { return false } @@ -453,6 +470,11 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool { m.alpnProtocols = append(m.alpnProtocols, string(d[:stringLen])) d = d[stringLen:] } + case extensionSCT: + m.scts = true + if length != 0 { + return false + } } data = data[length:] } @@ -470,6 +492,7 @@ type serverHelloMsg struct { nextProtoNeg bool nextProtos []string ocspStapling bool + scts [][]byte ticketSupported bool secureRenegotiation bool alpnProtocol string @@ -481,6 +504,15 @@ func (m *serverHelloMsg) equal(i interface{}) bool { return false } + if len(m.scts) != len(m1.scts) { + return false + } + for i, sct := range m.scts { + if !bytes.Equal(sct, m1.scts[i]) { + return false + } + } + return bytes.Equal(m.raw, m1.raw) && m.vers == m1.vers && bytes.Equal(m.random, m1.random) && @@ -530,6 +562,14 @@ func (m *serverHelloMsg) marshal() []byte { extensionsLength += 2 + 1 + alpnLen numExtensions++ } + sctLen := 0 + if len(m.scts) > 0 { + for _, sct := range m.scts { + sctLen += len(sct) + 2 + } + extensionsLength += 2 + sctLen + numExtensions++ + } if numExtensions > 0 { extensionsLength += 4 * numExtensions @@ -605,6 +645,23 @@ func (m *serverHelloMsg) marshal() []byte { copy(z[7:], []byte(m.alpnProtocol)) z = z[7+alpnLen:] } + if sctLen > 0 { + z[0] = byte(extensionSCT >> 8) + z[1] = byte(extensionSCT) + l := sctLen + 2 + z[2] = byte(l >> 8) + z[3] = byte(l) + z[4] = byte(sctLen >> 8) + z[5] = byte(sctLen) + + z = z[6:] + for _, sct := range m.scts { + z[0] = byte(len(sct) >> 8) + z[1] = byte(len(sct)) + copy(z[2:], sct) + z = z[len(sct)+2:] + } + } m.raw = x @@ -634,6 +691,7 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool { m.nextProtoNeg = false m.nextProtos = nil m.ocspStapling = false + m.scts = nil m.ticketSupported = false m.alpnProtocol = "" @@ -706,6 +764,34 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool { } d = d[1:] m.alpnProtocol = string(d) + case extensionSCT: + d := data[:length] + + if len(d) < 2 { + return false + } + l := int(d[0])<<8 | int(d[1]) + d = d[2:] + if len(d) != l { + return false + } + if l == 0 { + continue + } + + m.scts = make([][]byte, 0, 3) + for len(d) != 0 { + if len(d) < 2 { + return false + } + sctLen := int(d[0])<<8 | int(d[1]) + d = d[2:] + if len(d) < sctLen { + return false + } + m.scts = append(m.scts, d[:sctLen]) + d = d[sctLen:] + } } data = data[length:] } diff --git a/libgo/go/crypto/tls/handshake_messages_test.go b/libgo/go/crypto/tls/handshake_messages_test.go index a96e95c3f03..95d825bd175 100644 --- a/libgo/go/crypto/tls/handshake_messages_test.go +++ b/libgo/go/crypto/tls/handshake_messages_test.go @@ -136,12 +136,15 @@ func (*clientHelloMsg) Generate(rand *rand.Rand, size int) reflect.Value { } } if rand.Intn(10) > 5 { - m.signatureAndHashes = supportedSKXSignatureAlgorithms + m.signatureAndHashes = supportedSignatureAlgorithms } m.alpnProtocols = make([]string, rand.Intn(5)) for i := range m.alpnProtocols { m.alpnProtocols[i] = randomString(rand.Intn(20)+1, rand) } + if rand.Intn(10) > 5 { + m.scts = true + } return reflect.ValueOf(m) } @@ -172,6 +175,14 @@ func (*serverHelloMsg) Generate(rand *rand.Rand, size int) reflect.Value { } m.alpnProtocol = randomString(rand.Intn(32)+1, rand) + if rand.Intn(10) > 5 { + numSCTs := rand.Intn(4) + m.scts = make([][]byte, numSCTs) + for i := range m.scts { + m.scts[i] = randomBytes(rand.Intn(500), rand) + } + } + return reflect.ValueOf(m) } diff --git a/libgo/go/crypto/tls/handshake_server.go b/libgo/go/crypto/tls/handshake_server.go index 0d907656c6c..e16cddcbd81 100644 --- a/libgo/go/crypto/tls/handshake_server.go +++ b/libgo/go/crypto/tls/handshake_server.go @@ -25,6 +25,8 @@ type serverHandshakeState struct { suite *cipherSuite ellipticOk bool ecdsaOk bool + rsaDecryptOk bool + rsaSignOk bool sessionState *sessionState finishedHash finishedHash masterSecret []byte @@ -57,6 +59,14 @@ func (c *Conn) serverHandshake() error { if err := hs.establishKeys(); err != nil { return err } + // ticketSupported is set in a resumption handshake if the + // ticket from the client was encrypted with an old session + // ticket key and thus a refreshed ticket should be sent. + if hs.hello.ticketSupported { + if err := hs.sendSessionTicket(); err != nil { + return err + } + } if err := hs.sendFinished(c.firstFinished[:]); err != nil { return err } @@ -111,9 +121,6 @@ func (hs *serverHandshakeState) readClientHello() (isResume bool, err error) { } c.haveVers = true - hs.finishedHash = newFinishedHash(c.vers) - hs.finishedHash.Write(hs.clientHello.marshal()) - hs.hello = new(serverHelloMsg) supportedCurve := false @@ -173,33 +180,47 @@ Curves: // Although sending an empty NPN extension is reasonable, Firefox has // had a bug around this. Best to send nothing at all if // config.NextProtos is empty. See - // https://code.google.com/p/go/issues/detail?id=5445. + // https://golang.org/issue/5445. if hs.clientHello.nextProtoNeg && len(config.NextProtos) > 0 { hs.hello.nextProtoNeg = true hs.hello.nextProtos = config.NextProtos } } - if len(config.Certificates) == 0 { + if hs.cert, err = config.getCertificate(&ClientHelloInfo{ + CipherSuites: hs.clientHello.cipherSuites, + ServerName: hs.clientHello.serverName, + SupportedCurves: hs.clientHello.supportedCurves, + SupportedPoints: hs.clientHello.supportedPoints, + }); err != nil { c.sendAlert(alertInternalError) - return false, errors.New("tls: no certificates configured") + return false, err } - hs.cert = &config.Certificates[0] - if len(hs.clientHello.serverName) > 0 { - chi := &ClientHelloInfo{ - CipherSuites: hs.clientHello.cipherSuites, - ServerName: hs.clientHello.serverName, - SupportedCurves: hs.clientHello.supportedCurves, - SupportedPoints: hs.clientHello.supportedPoints, + if hs.clientHello.scts { + hs.hello.scts = hs.cert.SignedCertificateTimestamps + } + + if priv, ok := hs.cert.PrivateKey.(crypto.Signer); ok { + switch priv.Public().(type) { + case *ecdsa.PublicKey: + hs.ecdsaOk = true + case *rsa.PublicKey: + hs.rsaSignOk = true + default: + c.sendAlert(alertInternalError) + return false, fmt.Errorf("crypto/tls: unsupported signing key type (%T)", priv.Public()) } - if hs.cert, err = config.getCertificate(chi); err != nil { + } + if priv, ok := hs.cert.PrivateKey.(crypto.Decrypter); ok { + switch priv.Public().(type) { + case *rsa.PublicKey: + hs.rsaDecryptOk = true + default: c.sendAlert(alertInternalError) - return false, err + return false, fmt.Errorf("crypto/tls: unsupported decryption key type (%T)", priv.Public()) } } - _, hs.ecdsaOk = hs.cert.PrivateKey.(*ecdsa.PrivateKey) - if hs.checkForResumption() { return true, nil } @@ -214,7 +235,7 @@ Curves: } for _, id := range preferenceList { - if hs.suite = c.tryCipherSuite(id, supportedList, c.vers, hs.ellipticOk, hs.ecdsaOk); hs.suite != nil { + if hs.setCipherSuite(id, supportedList, c.vers) { break } } @@ -228,9 +249,9 @@ Curves: for _, id := range hs.clientHello.cipherSuites { if id == TLS_FALLBACK_SCSV { // The client is doing a fallback connection. - if hs.clientHello.vers < c.config.MaxVersion { + if hs.clientHello.vers < c.config.maxVersion() { c.sendAlert(alertInappropriateFallback) - return false, errors.New("tls: client using inppropriate protocol fallback") + return false, errors.New("tls: client using inappropriate protocol fallback") } break } @@ -239,7 +260,7 @@ Curves: return false, nil } -// checkForResumption returns true if we should perform resumption on this connection. +// checkForResumption reports whether we should perform resumption on this connection. func (hs *serverHandshakeState) checkForResumption() bool { c := hs.c @@ -248,7 +269,8 @@ func (hs *serverHandshakeState) checkForResumption() bool { } var ok bool - if hs.sessionState, ok = c.decryptTicket(hs.clientHello.sessionTicket); !ok { + var sessionTicket = append([]uint8{}, hs.clientHello.sessionTicket...) + if hs.sessionState, ok = c.decryptTicket(sessionTicket); !ok { return false } @@ -272,8 +294,7 @@ func (hs *serverHandshakeState) checkForResumption() bool { } // Check that we also support the ciphersuite from the session. - hs.suite = c.tryCipherSuite(hs.sessionState.cipherSuite, c.config.cipherSuites(), hs.sessionState.vers, hs.ellipticOk, hs.ecdsaOk) - if hs.suite == nil { + if !hs.setCipherSuite(hs.sessionState.cipherSuite, c.config.cipherSuites(), hs.sessionState.vers) { return false } @@ -296,6 +317,10 @@ func (hs *serverHandshakeState) doResumeHandshake() error { // We echo the client's session ID in the ServerHello to let it know // that we're doing a resumption. hs.hello.sessionId = hs.clientHello.sessionId + hs.hello.ticketSupported = hs.sessionState.usedOldKey + hs.finishedHash = newFinishedHash(c.vers, hs.suite) + hs.finishedHash.discardHandshakeBuffer() + hs.finishedHash.Write(hs.clientHello.marshal()) hs.finishedHash.Write(hs.hello.marshal()) c.writeRecord(recordTypeHandshake, hs.hello.marshal()) @@ -320,6 +345,14 @@ func (hs *serverHandshakeState) doFullHandshake() error { hs.hello.ticketSupported = hs.clientHello.ticketSupported && !config.SessionTicketsDisabled hs.hello.cipherSuite = hs.suite.id + + hs.finishedHash = newFinishedHash(hs.c.vers, hs.suite) + if config.ClientAuth == NoClientCert { + // No need to keep a full record of the handshake if client + // certificates won't be used. + hs.finishedHash.discardHandshakeBuffer() + } + hs.finishedHash.Write(hs.clientHello.marshal()) hs.finishedHash.Write(hs.hello.marshal()) c.writeRecord(recordTypeHandshake, hs.hello.marshal()) @@ -356,7 +389,7 @@ func (hs *serverHandshakeState) doFullHandshake() error { } if c.vers >= VersionTLS12 { certReq.hasSignatureAndHash = true - certReq.signatureAndHashes = supportedClientCertSignatureAlgorithms + certReq.signatureAndHashes = supportedSignatureAlgorithms } // An empty list of certificateAuthorities signals to @@ -420,6 +453,13 @@ func (hs *serverHandshakeState) doFullHandshake() error { } hs.finishedHash.Write(ckx.marshal()) + preMasterSecret, err := keyAgreement.processClientKeyExchange(config, hs.cert, ckx, c.vers) + if err != nil { + c.sendAlert(alertHandshakeFailure) + return err + } + hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.clientHello.random, hs.hello.random) + // If we received a client cert in response to our certificate request message, // the client will send us a certificateVerifyMsg immediately after the // clientKeyExchangeMsg. This message is a digest of all preceding @@ -437,8 +477,31 @@ func (hs *serverHandshakeState) doFullHandshake() error { return unexpectedMessageError(certVerify, msg) } + // Determine the signature type. + var signatureAndHash signatureAndHash + if certVerify.hasSignatureAndHash { + signatureAndHash = certVerify.signatureAndHash + if !isSupportedSignatureAndHash(signatureAndHash, supportedSignatureAlgorithms) { + return errors.New("tls: unsupported hash function for client certificate") + } + } else { + // Before TLS 1.2 the signature algorithm was implicit + // from the key type, and only one hash per signature + // algorithm was possible. Leave the hash as zero. + switch pub.(type) { + case *ecdsa.PublicKey: + signatureAndHash.signature = signatureECDSA + case *rsa.PublicKey: + signatureAndHash.signature = signatureRSA + } + } + switch key := pub.(type) { case *ecdsa.PublicKey: + if signatureAndHash.signature != signatureECDSA { + err = errors.New("bad signature type for client's ECDSA certificate") + break + } ecdsaSig := new(ecdsaSignature) if _, err = asn1.Unmarshal(certVerify.signature, ecdsaSig); err != nil { break @@ -447,29 +510,34 @@ func (hs *serverHandshakeState) doFullHandshake() error { err = errors.New("ECDSA signature contained zero or negative values") break } - digest, _, _ := hs.finishedHash.hashForClientCertificate(signatureECDSA) + var digest []byte + if digest, _, err = hs.finishedHash.hashForClientCertificate(signatureAndHash, hs.masterSecret); err != nil { + break + } if !ecdsa.Verify(key, digest, ecdsaSig.R, ecdsaSig.S) { err = errors.New("ECDSA verification failure") - break } case *rsa.PublicKey: - digest, hashFunc, _ := hs.finishedHash.hashForClientCertificate(signatureRSA) + if signatureAndHash.signature != signatureRSA { + err = errors.New("bad signature type for client's RSA certificate") + break + } + var digest []byte + var hashFunc crypto.Hash + if digest, hashFunc, err = hs.finishedHash.hashForClientCertificate(signatureAndHash, hs.masterSecret); err != nil { + break + } err = rsa.VerifyPKCS1v15(key, hashFunc, digest, certVerify.signature) } if err != nil { c.sendAlert(alertBadCertificate) - return errors.New("could not validate signature of connection nonces: " + err.Error()) + return errors.New("tls: could not validate signature of connection nonces: " + err.Error()) } hs.finishedHash.Write(certVerify.marshal()) } - preMasterSecret, err := keyAgreement.processClientKeyExchange(config, hs.cert, ckx, c.vers) - if err != nil { - c.sendAlert(alertHandshakeFailure) - return err - } - hs.masterSecret = masterFromPreMasterSecret(c.vers, preMasterSecret, hs.clientHello.random, hs.hello.random) + hs.finishedHash.discardHandshakeBuffer() return nil } @@ -478,7 +546,7 @@ func (hs *serverHandshakeState) establishKeys() error { c := hs.c clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV := - keysFromMasterSecret(c.vers, hs.masterSecret, hs.clientHello.random, hs.hello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen) + keysFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.clientHello.random, hs.hello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen) var clientCipher, serverCipher interface{} var clientHash, serverHash macFunction @@ -619,18 +687,6 @@ func (hs *serverHandshakeState) processCertsFromClient(certificates [][]byte) (c return nil, errors.New("tls: failed to verify client's certificate: " + err.Error()) } - ok := false - for _, ku := range certs[0].ExtKeyUsage { - if ku == x509.ExtKeyUsageClientAuth { - ok = true - break - } - } - if !ok { - c.sendAlert(alertHandshakeFailure) - return nil, errors.New("tls: client's certificate's extended key usage doesn't permit it to be used for client authentication") - } - c.verifiedChains = chains } @@ -650,9 +706,10 @@ func (hs *serverHandshakeState) processCertsFromClient(certificates [][]byte) (c return nil, nil } -// tryCipherSuite returns a cipherSuite with the given id if that cipher suite -// is acceptable to use. -func (c *Conn) tryCipherSuite(id uint16, supportedCipherSuites []uint16, version uint16, ellipticOk, ecdsaOk bool) *cipherSuite { +// setCipherSuite sets a cipherSuite with the given id as the serverHandshakeState +// suite if that cipher suite is acceptable to use. +// It returns a bool indicating if the suite was set. +func (hs *serverHandshakeState) setCipherSuite(id uint16, supportedCipherSuites []uint16, version uint16) bool { for _, supported := range supportedCipherSuites { if id == supported { var candidate *cipherSuite @@ -668,18 +725,26 @@ func (c *Conn) tryCipherSuite(id uint16, supportedCipherSuites []uint16, version } // Don't select a ciphersuite which we can't // support for this client. - if (candidate.flags&suiteECDHE != 0) && !ellipticOk { - continue - } - if (candidate.flags&suiteECDSA != 0) != ecdsaOk { + if candidate.flags&suiteECDHE != 0 { + if !hs.ellipticOk { + continue + } + if candidate.flags&suiteECDSA != 0 { + if !hs.ecdsaOk { + continue + } + } else if !hs.rsaSignOk { + continue + } + } else if !hs.rsaDecryptOk { continue } if version < VersionTLS12 && candidate.flags&suiteTLS12 != 0 { continue } - return candidate + hs.suite = candidate + return true } } - - return nil + return false } diff --git a/libgo/go/crypto/tls/handshake_server_test.go b/libgo/go/crypto/tls/handshake_server_test.go index 0338af457ee..20c2bd6d4d4 100644 --- a/libgo/go/crypto/tls/handshake_server_test.go +++ b/libgo/go/crypto/tls/handshake_server_test.go @@ -37,6 +37,15 @@ func (zeroSource) Read(b []byte) (n int, err error) { var testConfig *Config +func allCipherSuites() []uint16 { + ids := make([]uint16, len(cipherSuites)) + for i, suite := range cipherSuites { + ids[i] = suite.id + } + + return ids +} + func init() { testConfig = &Config{ Time: func() time.Time { return time.Unix(0, 0) }, @@ -45,6 +54,7 @@ func init() { InsecureSkipVerify: true, MinVersion: VersionSSL30, MaxVersion: VersionTLS12, + CipherSuites: allCipherSuites(), } testConfig.Certificates[0].Certificate = [][]byte{testRSACertificate} testConfig.Certificates[0].PrivateKey = testRSAPrivateKey @@ -53,7 +63,11 @@ func init() { testConfig.BuildNameToCertificate() } -func testClientHelloFailure(t *testing.T, m handshakeMessage, expectedSubStr string) { +func testClientHello(t *testing.T, serverConfig *Config, m handshakeMessage) { + testClientHelloFailure(t, serverConfig, m, "") +} + +func testClientHelloFailure(t *testing.T, serverConfig *Config, m handshakeMessage, expectedSubStr string) { // Create in-memory network connection, // send message to server. Should return // expected error. @@ -66,22 +80,26 @@ func testClientHelloFailure(t *testing.T, m handshakeMessage, expectedSubStr str cli.writeRecord(recordTypeHandshake, m.marshal()) c.Close() }() - err := Server(s, testConfig).Handshake() + err := Server(s, serverConfig).Handshake() s.Close() - if err == nil || !strings.Contains(err.Error(), expectedSubStr) { + if len(expectedSubStr) == 0 { + if err != nil && err != io.EOF { + t.Errorf("Got error: %s; expected to succeed", err, expectedSubStr) + } + } else if err == nil || !strings.Contains(err.Error(), expectedSubStr) { t.Errorf("Got error: %s; expected to match substring '%s'", err, expectedSubStr) } } func TestSimpleError(t *testing.T) { - testClientHelloFailure(t, &serverHelloDoneMsg{}, "unexpected handshake message") + testClientHelloFailure(t, testConfig, &serverHelloDoneMsg{}, "unexpected handshake message") } var badProtocolVersions = []uint16{0x0000, 0x0005, 0x0100, 0x0105, 0x0200, 0x0205} func TestRejectBadProtocolVersion(t *testing.T) { for _, v := range badProtocolVersions { - testClientHelloFailure(t, &clientHelloMsg{vers: v}, "unsupported, maximum protocol version") + testClientHelloFailure(t, testConfig, &clientHelloMsg{vers: v}, "unsupported, maximum protocol version") } } @@ -91,7 +109,7 @@ func TestNoSuiteOverlap(t *testing.T) { cipherSuites: []uint16{0xff00}, compressionMethods: []uint8{0}, } - testClientHelloFailure(t, clientHello, "no cipher suite supported by both client and server") + testClientHelloFailure(t, testConfig, clientHello, "no cipher suite supported by both client and server") } func TestNoCompressionOverlap(t *testing.T) { @@ -100,7 +118,117 @@ func TestNoCompressionOverlap(t *testing.T) { cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA}, compressionMethods: []uint8{0xff}, } - testClientHelloFailure(t, clientHello, "client does not support uncompressed connections") + testClientHelloFailure(t, testConfig, clientHello, "client does not support uncompressed connections") +} + +func TestNoRC4ByDefault(t *testing.T) { + clientHello := &clientHelloMsg{ + vers: 0x0301, + cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA}, + compressionMethods: []uint8{0}, + } + serverConfig := *testConfig + // Reset the enabled cipher suites to nil in order to test the + // defaults. + serverConfig.CipherSuites = nil + testClientHelloFailure(t, &serverConfig, clientHello, "no cipher suite supported by both client and server") +} + +func TestDontSelectECDSAWithRSAKey(t *testing.T) { + // Test that, even when both sides support an ECDSA cipher suite, it + // won't be selected if the server's private key doesn't support it. + clientHello := &clientHelloMsg{ + vers: 0x0301, + cipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA}, + compressionMethods: []uint8{0}, + supportedCurves: []CurveID{CurveP256}, + supportedPoints: []uint8{pointFormatUncompressed}, + } + serverConfig := *testConfig + serverConfig.CipherSuites = clientHello.cipherSuites + serverConfig.Certificates = make([]Certificate, 1) + serverConfig.Certificates[0].Certificate = [][]byte{testECDSACertificate} + serverConfig.Certificates[0].PrivateKey = testECDSAPrivateKey + serverConfig.BuildNameToCertificate() + // First test that it *does* work when the server's key is ECDSA. + testClientHello(t, &serverConfig, clientHello) + + // Now test that switching to an RSA key causes the expected error (and + // not an internal error about a signing failure). + serverConfig.Certificates = testConfig.Certificates + testClientHelloFailure(t, &serverConfig, clientHello, "no cipher suite supported by both client and server") +} + +func TestDontSelectRSAWithECDSAKey(t *testing.T) { + // Test that, even when both sides support an RSA cipher suite, it + // won't be selected if the server's private key doesn't support it. + clientHello := &clientHelloMsg{ + vers: 0x0301, + cipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA}, + compressionMethods: []uint8{0}, + supportedCurves: []CurveID{CurveP256}, + supportedPoints: []uint8{pointFormatUncompressed}, + } + serverConfig := *testConfig + serverConfig.CipherSuites = clientHello.cipherSuites + // First test that it *does* work when the server's key is RSA. + testClientHello(t, &serverConfig, clientHello) + + // Now test that switching to an ECDSA key causes the expected error + // (and not an internal error about a signing failure). + serverConfig.Certificates = make([]Certificate, 1) + serverConfig.Certificates[0].Certificate = [][]byte{testECDSACertificate} + serverConfig.Certificates[0].PrivateKey = testECDSAPrivateKey + serverConfig.BuildNameToCertificate() + testClientHelloFailure(t, &serverConfig, clientHello, "no cipher suite supported by both client and server") +} + +func TestRenegotiationExtension(t *testing.T) { + clientHello := &clientHelloMsg{ + vers: VersionTLS12, + compressionMethods: []uint8{compressionNone}, + random: make([]byte, 32), + secureRenegotiation: true, + cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA}, + } + + var buf []byte + c, s := net.Pipe() + + go func() { + cli := Client(c, testConfig) + cli.vers = clientHello.vers + cli.writeRecord(recordTypeHandshake, clientHello.marshal()) + + buf = make([]byte, 1024) + n, err := c.Read(buf) + if err != nil { + t.Fatalf("Server read returned error: %s", err) + } + buf = buf[:n] + c.Close() + }() + + Server(s, testConfig).Handshake() + + if len(buf) < 5+4 { + t.Fatalf("Server returned short message of length %d", len(buf)) + } + // buf contains a TLS record, with a 5 byte record header and a 4 byte + // handshake header. The length of the ServerHello is taken from the + // handshake header. + serverHelloLen := int(buf[6])<<16 | int(buf[7])<<8 | int(buf[8]) + + var serverHello serverHelloMsg + // unmarshal expects to be given the handshake header, but + // serverHelloLen doesn't include it. + if !serverHello.unmarshal(buf[5 : 9+serverHelloLen]) { + t.Fatalf("Failed to parse ServerHello") + } + + if !serverHello.secureRenegotiation { + t.Errorf("Secure renegotiation extension was not echoed.") + } } func TestTLS12OnlyCipherSuites(t *testing.T) { @@ -175,19 +303,20 @@ func TestClose(t *testing.T) { } } -func testHandshake(clientConfig, serverConfig *Config) (state ConnectionState, err error) { +func testHandshake(clientConfig, serverConfig *Config) (serverState, clientState ConnectionState, err error) { c, s := net.Pipe() done := make(chan bool) go func() { cli := Client(c, clientConfig) cli.Handshake() + clientState = cli.ConnectionState() c.Close() done <- true }() server := Server(s, serverConfig) err = server.Handshake() if err == nil { - state = server.ConnectionState() + serverState = server.ConnectionState() } s.Close() <-done @@ -202,7 +331,7 @@ func TestVersion(t *testing.T) { clientConfig := &Config{ InsecureSkipVerify: true, } - state, err := testHandshake(clientConfig, serverConfig) + state, _, err := testHandshake(clientConfig, serverConfig) if err != nil { t.Fatalf("handshake failed: %s", err) } @@ -221,7 +350,7 @@ func TestCipherSuitePreference(t *testing.T) { CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_RC4_128_SHA}, InsecureSkipVerify: true, } - state, err := testHandshake(clientConfig, serverConfig) + state, _, err := testHandshake(clientConfig, serverConfig) if err != nil { t.Fatalf("handshake failed: %s", err) } @@ -231,7 +360,7 @@ func TestCipherSuitePreference(t *testing.T) { } serverConfig.PreferServerCipherSuites = true - state, err = testHandshake(clientConfig, serverConfig) + state, _, err = testHandshake(clientConfig, serverConfig) if err != nil { t.Fatalf("handshake failed: %s", err) } @@ -240,6 +369,33 @@ func TestCipherSuitePreference(t *testing.T) { } } +func TestSCTHandshake(t *testing.T) { + expected := [][]byte{[]byte("certificate"), []byte("transparency")} + serverConfig := &Config{ + Certificates: []Certificate{{ + Certificate: [][]byte{testRSACertificate}, + PrivateKey: testRSAPrivateKey, + SignedCertificateTimestamps: expected, + }}, + } + clientConfig := &Config{ + InsecureSkipVerify: true, + } + _, state, err := testHandshake(clientConfig, serverConfig) + if err != nil { + t.Fatalf("handshake failed: %s", err) + } + actual := state.SignedCertificateTimestamps + if len(actual) != len(expected) { + t.Fatalf("got %d scts, want %d", len(actual), len(expected)) + } + for i, sct := range expected { + if !bytes.Equal(sct, actual[i]) { + t.Fatalf("SCT #%d was %x, but expected %x", i, actual[i], sct) + } + } +} + // Note: see comment in handshake_test.go for details of how the reference // tests work. @@ -257,9 +413,6 @@ type serverTest struct { expectedPeerCerts []string // config, if not nil, contains a custom Config to use for this test. config *Config - // expectAlert, if true, indicates that a fatal alert should be returned - // when handshaking with the server. - expectAlert bool // expectHandshakeErrorIncluding, when not empty, contains a string // that must be a substring of the error resulting from the handshake. expectHandshakeErrorIncluding string @@ -384,9 +537,7 @@ func (test *serverTest) run(t *testing.T, write bool) { if !write { flows, err := test.loadData() if err != nil { - if !test.expectAlert { - t.Fatalf("%s: failed to load data from %s", test.name, test.dataPath()) - } + t.Fatalf("%s: failed to load data from %s", test.name, test.dataPath()) } for i, b := range flows { if i%2 == 0 { @@ -395,17 +546,11 @@ func (test *serverTest) run(t *testing.T, write bool) { } bb := make([]byte, len(b)) n, err := io.ReadFull(clientConn, bb) - if test.expectAlert { - if err == nil { - t.Fatal("Expected read failure but read succeeded") - } - } else { - if err != nil { - t.Fatalf("%s #%d: %s\nRead %d, wanted %d, got %x, wanted %x\n", test.name, i+1, err, n, len(bb), bb[:n], b) - } - if !bytes.Equal(b, bb) { - t.Fatalf("%s #%d: mismatch on read: got:%x want:%x", test.name, i+1, bb, b) - } + if err != nil { + t.Fatalf("%s #%d: %s\nRead %d, wanted %d, got %x, wanted %x\n", test.name, i+1, err, n, len(bb), bb[:n], b) + } + if !bytes.Equal(b, bb) { + t.Fatalf("%s #%d: mismatch on read: got:%x want:%x", test.name, i+1, bb, b) } } clientConn.Close() @@ -516,6 +661,14 @@ func TestHandshakeServerAESGCM(t *testing.T) { runServerTestTLS12(t, test) } +func TestHandshakeServerAES256GCMSHA384(t *testing.T) { + test := &serverTest{ + name: "RSA-AES256-GCM-SHA384", + command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "ECDHE-RSA-AES256-GCM-SHA384"}, + } + runServerTestTLS12(t, test) +} + func TestHandshakeServerECDHEECDSAAES(t *testing.T) { config := *testConfig config.Certificates = make([]Certificate, 1) @@ -599,7 +752,7 @@ func TestHandshakeServerSNIGetCertificate(t *testing.T) { return cert, nil } test := &serverTest{ - name: "SNI", + name: "SNI-GetCertificate", command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA", "-servername", "snitest.com"}, config: &config, } @@ -617,7 +770,7 @@ func TestHandshakeServerSNIGetCertificateNotFound(t *testing.T) { return nil, nil } test := &serverTest{ - name: "SNI", + name: "SNI-GetCertificateNotFound", command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA", "-servername", "snitest.com"}, config: &config, } @@ -627,18 +780,50 @@ func TestHandshakeServerSNIGetCertificateNotFound(t *testing.T) { // TestHandshakeServerSNICertForNameError tests to make sure that errors in // GetCertificate result in a tls alert. func TestHandshakeServerSNIGetCertificateError(t *testing.T) { - config := *testConfig + const errMsg = "TestHandshakeServerSNIGetCertificateError error" - config.GetCertificate = func(clientHello *ClientHelloInfo) (*Certificate, error) { - return nil, fmt.Errorf("Test error in GetCertificate") + serverConfig := *testConfig + serverConfig.GetCertificate = func(clientHello *ClientHelloInfo) (*Certificate, error) { + return nil, errors.New(errMsg) } - test := &serverTest{ - name: "SNI", - command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA", "-servername", "snitest.com"}, - config: &config, - expectAlert: true, + + clientHello := &clientHelloMsg{ + vers: 0x0301, + cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA}, + compressionMethods: []uint8{0}, + serverName: "test", } - runServerTestTLS12(t, test) + testClientHelloFailure(t, &serverConfig, clientHello, errMsg) +} + +// TestHandshakeServerEmptyCertificates tests that GetCertificates is called in +// the case that Certificates is empty, even without SNI. +func TestHandshakeServerEmptyCertificates(t *testing.T) { + const errMsg = "TestHandshakeServerEmptyCertificates error" + + serverConfig := *testConfig + serverConfig.GetCertificate = func(clientHello *ClientHelloInfo) (*Certificate, error) { + return nil, errors.New(errMsg) + } + serverConfig.Certificates = nil + + clientHello := &clientHelloMsg{ + vers: 0x0301, + cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA}, + compressionMethods: []uint8{0}, + } + testClientHelloFailure(t, &serverConfig, clientHello, errMsg) + + // With an empty Certificates and a nil GetCertificate, the server + // should always return a “no certificates” error. + serverConfig.GetCertificate = nil + + clientHello = &clientHelloMsg{ + vers: 0x0301, + cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA}, + compressionMethods: []uint8{0}, + } + testClientHelloFailure(t, &serverConfig, clientHello, "no certificates") } // TestCipherSuiteCertPreferance ensures that we select an RSA ciphersuite with @@ -716,11 +901,15 @@ func TestResumptionDisabled(t *testing.T) { } func TestFallbackSCSV(t *testing.T) { + serverConfig := &Config{ + Certificates: testConfig.Certificates, + } test := &serverTest{ - name: "FallbackSCSV", + name: "FallbackSCSV", + config: serverConfig, // OpenSSL 1.0.1j is needed for the -fallback_scsv option. command: []string{"openssl", "s_client", "-fallback_scsv"}, - expectHandshakeErrorIncluding: "inppropriate protocol fallback", + expectHandshakeErrorIncluding: "inappropriate protocol fallback", } runServerTestTLS11(t, test) } @@ -840,7 +1029,9 @@ func fromHex(s string) []byte { return b } -var testRSACertificate = fromHex("308202b030820219a00302010202090085b0bba48a7fb8ca300d06092a864886f70d01010505003045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c7464301e170d3130303432343039303933385a170d3131303432343039303933385a3045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c746430819f300d06092a864886f70d010101050003818d0030818902818100bb79d6f517b5e5bf4610d0dc69bee62b07435ad0032d8a7a4385b71452e7a5654c2c78b8238cb5b482e5de1f953b7e62a52ca533d6fe125c7a56fcf506bffa587b263fb5cd04d3d0c921964ac7f4549f5abfef427100fe1899077f7e887d7df10439c4a22edb51c97ce3c04c3b326601cfafb11db8719a1ddbdb896baeda2d790203010001a381a73081a4301d0603551d0e04160414b1ade2855acfcb28db69ce2369ded3268e18883930750603551d23046e306c8014b1ade2855acfcb28db69ce2369ded3268e188839a149a4473045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c746482090085b0bba48a7fb8ca300c0603551d13040530030101ff300d06092a864886f70d010105050003818100086c4524c76bb159ab0c52ccf2b014d7879d7a6475b55a9566e4c52b8eae12661feb4f38b36e60d392fdf74108b52513b1187a24fb301dbaed98b917ece7d73159db95d31d78ea50565cd5825a2d5a5f33c4b6d8c97590968c0f5298b5cd981f89205ff2a01ca31b9694dda9fd57e970e8266d71999b266e3850296c90a7bdd9") +var testRSACertificate = fromHex("30820263308201cca003020102020900a273000c8100cbf3300d06092a864886f70d01010b0500302b31173015060355040a130e476f6f676c652054455354494e473110300e06035504031307476f20526f6f74301e170d3135303130313030303030305a170d3235303130313030303030305a302631173015060355040a130e476f6f676c652054455354494e47310b300906035504031302476f30819f300d06092a864886f70d010101050003818d0030818902818100af8788f6201b95656c14ab4405af3b4514e3b76dfd00634d957ffe6a623586c04af9187cf6aa255e7a64316600baf48e92afc76bd876d4f35f41cb6e5615971b97c13c123921663d2b16d1bcdb1cc0a7dab7caadbadacbd52150ecde8dabd16b814b8902f3c4bec16c89b14484bd21d1047d9d164df98215f6effad60947f2fb0203010001a38193308190300e0603551d0f0101ff0404030205a0301d0603551d250416301406082b0601050507030106082b06010505070302300c0603551d130101ff0402300030190603551d0e0412041012508d896f1bd1dc544d6ecb695e06f4301b0603551d23041430128010bf3db6a966f2b840cfeab40378481a4130190603551d1104123010820e6578616d706c652e676f6c616e67300d06092a864886f70d01010b050003818100927caf91551218965931a64840d52dd5eebb02a0f5c21e7c9bb3307d3cdc76da4f3dc0faae2d33246b037b1b67591121b511bc77b9d9e06ea82d2e35fa645f223e63106bbeff14866d0df01531a814381e3b84872ccb98ed5176b9b14fdddb9b84048640fa51ddbab48debe346de46b94f86c7f9a4c24134acccf6eab0ab3918") + +var testRSACertificateIssuer = fromHex("3082024d308201b6a003020102020827326bd913b7c43d300d06092a864886f70d01010b0500302b31173015060355040a130e476f6f676c652054455354494e473110300e06035504031307476f20526f6f74301e170d3135303130313030303030305a170d3235303130313030303030305a302b31173015060355040a130e476f6f676c652054455354494e473110300e06035504031307476f20526f6f7430819f300d06092a864886f70d010101050003818d0030818902818100f0429a7b9f66a222c8453800452db355b34c4409fee09af2510a6589bfa35bdb4d453200d1de24338d6d5e5a91cc8301628445d6eb4e675927b9c1ea5c0f676acfb0f708ce4f19827e321c1898bf86df9823d5f0b05df2b6779888eff8abbc7f41c6e7d2667386a579b8cbaad3f6fd597cd7c4b187911a425aed1b555c1965190203010001a37a3078300e0603551d0f0101ff040403020204301d0603551d250416301406082b0601050507030106082b06010505070302300f0603551d130101ff040530030101ff30190603551d0e04120410bf3db6a966f2b840cfeab40378481a41301b0603551d23041430128010bf3db6a966f2b840cfeab40378481a41300d06092a864886f70d01010b050003818100586e68c1219ed4f5782b7cfd53cf1a55750a98781b2023f8694bb831fff6d7d4aad1f0ac782b1ec787f00a8956bdd06b4a1063444fcafe955c07d679163a730802c568886a2cf8a3c2ab41176957131c4b9e077ebd7ffbb91fdad8b08b932e9aeefac04923ffdc0aa145563f7f061995317400203578f350e3e566deb29dec5e") var testECDSACertificate = fromHex("3082020030820162020900b8bf2d47a0d2ebf4300906072a8648ce3d04013045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c7464301e170d3132313132323135303633325a170d3232313132303135303633325a3045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c746430819b301006072a8648ce3d020106052b81040023038186000400c4a1edbe98f90b4873367ec316561122f23d53c33b4d213dcd6b75e6f6b0dc9adf26c1bcb287f072327cb3642f1c90bcea6823107efee325c0483a69e0286dd33700ef0462dd0da09c706283d881d36431aa9e9731bd96b068c09b23de76643f1a5c7fe9120e5858b65f70dd9bd8ead5d7f5d5ccb9b69f30665b669a20e227e5bffe3b300906072a8648ce3d040103818c0030818802420188a24febe245c5487d1bacf5ed989dae4770c05e1bb62fbdf1b64db76140d311a2ceee0b7e927eff769dc33b7ea53fcefa10e259ec472d7cacda4e970e15a06fd00242014dfcbe67139c2d050ebd3fa38c25c13313830d9406bbd4377af6ec7ac9862eddd711697f857c56defb31782be4c7780daecbbe9e4e3624317b6a0f399512078f2a") @@ -848,13 +1039,13 @@ var testSNICertificate = fromHex("308201f23082015da003020102020100300b06092a8648 var testRSAPrivateKey = &rsa.PrivateKey{ PublicKey: rsa.PublicKey{ - N: bigFromString("131650079503776001033793877885499001334664249354723305978524647182322416328664556247316495448366990052837680518067798333412266673813370895702118944398081598789828837447552603077848001020611640547221687072142537202428102790818451901395596882588063427854225330436740647715202971973145151161964464812406232198521"), + N: bigFromString("123260960069105588390096594560395120585636206567569540256061833976822892593755073841963170165000086278069699238754008398039246547214989242849418349143232951701395321381739566687846006911427966669790845430647688107009232778985142860108863460556510585049041936029324503323373417214453307648498561956908810892027L"), E: 65537, }, - D: bigFromString("29354450337804273969007277378287027274721892607543397931919078829901848876371746653677097639302788129485893852488285045793268732234230875671682624082413996177431586734171663258657462237320300610850244186316880055243099640544518318093544057213190320837094958164973959123058337475052510833916491060913053867729"), + D: bigFromString("73196363031103823625826315929954946106043759818067219550565550066527203472294428548476778865091068522665312037075674791871635825938217363523103946045078950060973913307430314113074463630778799389010335923241901501086246276485964417618981733827707048660375428006201525399194575538037883519254056917253456403553L"), Primes: []*big.Int{ - bigFromString("11969277782311800166562047708379380720136961987713178380670422671426759650127150688426177829077494755200794297055316163155755835813760102405344560929062149"), - bigFromString("10998999429884441391899182616418192492905073053684657075974935218461686523870125521822756579792315215543092255516093840728890783887287417039645833477273829"), + bigFromString("11157426355495284553529769521954035649776033703833034489026848970480272318436419662860715175517581249375929775774910501512841707465207184924996975125010787L"), + bigFromString("11047436580963564307160117670964629323534448585520694947919342920137706075617545637058809770319843170934495909554506529982972972247390145716507031692656521L"), }, } diff --git a/libgo/go/crypto/tls/key_agreement.go b/libgo/go/crypto/tls/key_agreement.go index 0974fc6e0f4..0e6a7c22624 100644 --- a/libgo/go/crypto/tls/key_agreement.go +++ b/libgo/go/crypto/tls/key_agreement.go @@ -11,7 +11,6 @@ import ( "crypto/md5" "crypto/rsa" "crypto/sha1" - "crypto/sha256" "crypto/x509" "encoding/asn1" "errors" @@ -31,12 +30,6 @@ func (ka rsaKeyAgreement) generateServerKeyExchange(config *Config, cert *Certif } func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) { - preMasterSecret := make([]byte, 48) - _, err := io.ReadFull(config.rand(), preMasterSecret[2:]) - if err != nil { - return nil, err - } - if len(ckx.ciphertext) < 2 { return nil, errClientKeyExchange } @@ -49,8 +42,12 @@ func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, cert *Certifi } ciphertext = ckx.ciphertext[2:] } - - err = rsa.DecryptPKCS1v15SessionKey(config.rand(), cert.PrivateKey.(*rsa.PrivateKey), ciphertext, preMasterSecret) + priv, ok := cert.PrivateKey.(crypto.Decrypter) + if !ok { + return nil, errors.New("tls: certificate private key does not implement crypto.Decrypter") + } + // Perform constant time RSA PKCS#1 v1.5 decryption + preMasterSecret, err := priv.Decrypt(config.rand(), ciphertext, &rsa.PKCS1v15DecryptOptions{SessionKeyLen: 48}) if err != nil { return nil, err } @@ -110,30 +107,26 @@ func md5SHA1Hash(slices [][]byte) []byte { return md5sha1 } -// sha256Hash implements TLS 1.2's hash function. -func sha256Hash(slices [][]byte) []byte { - h := sha256.New() - for _, slice := range slices { - h.Write(slice) - } - return h.Sum(nil) -} - // hashForServerKeyExchange hashes the given slices and returns their digest -// and the identifier of the hash function used. The hashFunc argument is only -// used for >= TLS 1.2 and precisely identifies the hash function to use. -func hashForServerKeyExchange(sigType, hashFunc uint8, version uint16, slices ...[]byte) ([]byte, crypto.Hash, error) { +// and the identifier of the hash function used. The sigAndHash argument is +// only used for >= TLS 1.2 and precisely identifies the hash function to use. +func hashForServerKeyExchange(sigAndHash signatureAndHash, version uint16, slices ...[]byte) ([]byte, crypto.Hash, error) { if version >= VersionTLS12 { - switch hashFunc { - case hashSHA256: - return sha256Hash(slices), crypto.SHA256, nil - case hashSHA1: - return sha1Hash(slices), crypto.SHA1, nil - default: - return nil, crypto.Hash(0), errors.New("tls: unknown hash function used by peer") + if !isSupportedSignatureAndHash(sigAndHash, supportedSignatureAlgorithms) { + return nil, crypto.Hash(0), errors.New("tls: unsupported hash function used by peer") } + hashFunc, err := lookupTLSHash(sigAndHash.hash) + if err != nil { + return nil, crypto.Hash(0), err + } + h := hashFunc.New() + for _, slice := range slices { + h.Write(slice) + } + digest := h.Sum(nil) + return digest, hashFunc, nil } - if sigType == signatureECDSA { + if sigAndHash.signature == signatureECDSA { return sha1Hash(slices), crypto.SHA1, nil } return md5SHA1Hash(slices), crypto.MD5SHA1, nil @@ -142,20 +135,19 @@ func hashForServerKeyExchange(sigType, hashFunc uint8, version uint16, slices .. // pickTLS12HashForSignature returns a TLS 1.2 hash identifier for signing a // ServerKeyExchange given the signature type being used and the client's // advertised list of supported signature and hash combinations. -func pickTLS12HashForSignature(sigType uint8, clientSignatureAndHashes []signatureAndHash) (uint8, error) { - if len(clientSignatureAndHashes) == 0 { +func pickTLS12HashForSignature(sigType uint8, clientList []signatureAndHash) (uint8, error) { + if len(clientList) == 0 { // If the client didn't specify any signature_algorithms // extension then we can assume that it supports SHA1. See // http://tools.ietf.org/html/rfc5246#section-7.4.1.4.1 return hashSHA1, nil } - for _, sigAndHash := range clientSignatureAndHashes { + for _, sigAndHash := range clientList { if sigAndHash.signature != sigType { continue } - switch sigAndHash.hash { - case hashSHA1, hashSHA256: + if isSupportedSignatureAndHash(sigAndHash, supportedSignatureAlgorithms) { return sigAndHash.hash, nil } } @@ -228,41 +220,42 @@ NextCandidate: serverECDHParams[3] = byte(len(ecdhePublic)) copy(serverECDHParams[4:], ecdhePublic) - var tls12HashId uint8 + sigAndHash := signatureAndHash{signature: ka.sigType} + if ka.version >= VersionTLS12 { - if tls12HashId, err = pickTLS12HashForSignature(ka.sigType, clientHello.signatureAndHashes); err != nil { + if sigAndHash.hash, err = pickTLS12HashForSignature(ka.sigType, clientHello.signatureAndHashes); err != nil { return nil, err } } - digest, hashFunc, err := hashForServerKeyExchange(ka.sigType, tls12HashId, ka.version, clientHello.random, hello.random, serverECDHParams) + digest, hashFunc, err := hashForServerKeyExchange(sigAndHash, ka.version, clientHello.random, hello.random, serverECDHParams) if err != nil { return nil, err } + + priv, ok := cert.PrivateKey.(crypto.Signer) + if !ok { + return nil, errors.New("tls: certificate private key does not implement crypto.Signer") + } var sig []byte switch ka.sigType { case signatureECDSA: - privKey, ok := cert.PrivateKey.(*ecdsa.PrivateKey) + _, ok := priv.Public().(*ecdsa.PublicKey) if !ok { - return nil, errors.New("ECDHE ECDSA requires an ECDSA server private key") + return nil, errors.New("ECDHE ECDSA requires an ECDSA server key") } - r, s, err := ecdsa.Sign(config.rand(), privKey, digest) - if err != nil { - return nil, errors.New("failed to sign ECDHE parameters: " + err.Error()) - } - sig, err = asn1.Marshal(ecdsaSignature{r, s}) case signatureRSA: - privKey, ok := cert.PrivateKey.(*rsa.PrivateKey) + _, ok := priv.Public().(*rsa.PublicKey) if !ok { - return nil, errors.New("ECDHE RSA requires a RSA server private key") - } - sig, err = rsa.SignPKCS1v15(config.rand(), privKey, hashFunc, digest) - if err != nil { - return nil, errors.New("failed to sign ECDHE parameters: " + err.Error()) + return nil, errors.New("ECDHE RSA requires a RSA server key") } default: return nil, errors.New("unknown ECDHE signature algorithm") } + sig, err = priv.Sign(config.rand(), digest, hashFunc) + if err != nil { + return nil, errors.New("failed to sign ECDHE parameters: " + err.Error()) + } skx := new(serverKeyExchangeMsg) sigAndHashLen := 0 @@ -273,8 +266,8 @@ NextCandidate: copy(skx.key, serverECDHParams) k := skx.key[len(serverECDHParams):] if ka.version >= VersionTLS12 { - k[0] = tls12HashId - k[1] = ka.sigType + k[0] = sigAndHash.hash + k[1] = sigAndHash.signature k = k[2:] } k[0] = byte(len(sig) >> 8) @@ -335,15 +328,14 @@ func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHell return errServerKeyExchange } - var tls12HashId uint8 + sigAndHash := signatureAndHash{signature: ka.sigType} if ka.version >= VersionTLS12 { // handle SignatureAndHashAlgorithm - var sigAndHash []uint8 - sigAndHash, sig = sig[:2], sig[2:] - if sigAndHash[1] != ka.sigType { + sigAndHash = signatureAndHash{hash: sig[0], signature: sig[1]} + if sigAndHash.signature != ka.sigType { return errServerKeyExchange } - tls12HashId = sigAndHash[0] + sig = sig[2:] if len(sig) < 2 { return errServerKeyExchange } @@ -354,7 +346,7 @@ func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHell } sig = sig[2:] - digest, hashFunc, err := hashForServerKeyExchange(ka.sigType, tls12HashId, ka.version, clientHello.random, serverHello.random, serverECDHParams) + digest, hashFunc, err := hashForServerKeyExchange(sigAndHash, ka.version, clientHello.random, serverHello.random, serverECDHParams) if err != nil { return err } diff --git a/libgo/go/crypto/tls/prf.go b/libgo/go/crypto/tls/prf.go index fb8b3ab4d1e..6127c1ccfe7 100644 --- a/libgo/go/crypto/tls/prf.go +++ b/libgo/go/crypto/tls/prf.go @@ -10,6 +10,8 @@ import ( "crypto/md5" "crypto/sha1" "crypto/sha256" + "crypto/sha512" + "errors" "hash" ) @@ -65,12 +67,14 @@ func prf10(result, secret, label, seed []byte) { } // prf12 implements the TLS 1.2 pseudo-random function, as defined in RFC 5246, section 5. -func prf12(result, secret, label, seed []byte) { - labelAndSeed := make([]byte, len(label)+len(seed)) - copy(labelAndSeed, label) - copy(labelAndSeed[len(label):], seed) +func prf12(hashFunc func() hash.Hash) func(result, secret, label, seed []byte) { + return func(result, secret, label, seed []byte) { + labelAndSeed := make([]byte, len(label)+len(seed)) + copy(labelAndSeed, label) + copy(labelAndSeed[len(label):], seed) - pHash(result, secret, labelAndSeed, sha256.New) + pHash(result, secret, labelAndSeed, hashFunc) + } } // prf30 implements the SSL 3.0 pseudo-random function, as defined in @@ -117,41 +121,49 @@ var keyExpansionLabel = []byte("key expansion") var clientFinishedLabel = []byte("client finished") var serverFinishedLabel = []byte("server finished") -func prfForVersion(version uint16) func(result, secret, label, seed []byte) { +func prfAndHashForVersion(version uint16, suite *cipherSuite) (func(result, secret, label, seed []byte), crypto.Hash) { switch version { case VersionSSL30: - return prf30 + return prf30, crypto.Hash(0) case VersionTLS10, VersionTLS11: - return prf10 + return prf10, crypto.Hash(0) case VersionTLS12: - return prf12 + if suite.flags&suiteSHA384 != 0 { + return prf12(sha512.New384), crypto.SHA384 + } + return prf12(sha256.New), crypto.SHA256 default: panic("unknown version") } } +func prfForVersion(version uint16, suite *cipherSuite) func(result, secret, label, seed []byte) { + prf, _ := prfAndHashForVersion(version, suite) + return prf +} + // masterFromPreMasterSecret generates the master secret from the pre-master // secret. See http://tools.ietf.org/html/rfc5246#section-8.1 -func masterFromPreMasterSecret(version uint16, preMasterSecret, clientRandom, serverRandom []byte) []byte { +func masterFromPreMasterSecret(version uint16, suite *cipherSuite, preMasterSecret, clientRandom, serverRandom []byte) []byte { var seed [tlsRandomLength * 2]byte copy(seed[0:len(clientRandom)], clientRandom) copy(seed[len(clientRandom):], serverRandom) masterSecret := make([]byte, masterSecretLength) - prfForVersion(version)(masterSecret, preMasterSecret, masterSecretLabel, seed[0:]) + prfForVersion(version, suite)(masterSecret, preMasterSecret, masterSecretLabel, seed[0:]) return masterSecret } // keysFromMasterSecret generates the connection keys from the master // secret, given the lengths of the MAC key, cipher key and IV, as defined in // RFC 2246, section 6.3. -func keysFromMasterSecret(version uint16, masterSecret, clientRandom, serverRandom []byte, macLen, keyLen, ivLen int) (clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV []byte) { +func keysFromMasterSecret(version uint16, suite *cipherSuite, masterSecret, clientRandom, serverRandom []byte, macLen, keyLen, ivLen int) (clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV []byte) { var seed [tlsRandomLength * 2]byte copy(seed[0:len(clientRandom)], serverRandom) copy(seed[len(serverRandom):], clientRandom) n := 2*macLen + 2*keyLen + 2*ivLen keyMaterial := make([]byte, n) - prfForVersion(version)(keyMaterial, masterSecret, keyExpansionLabel, seed[0:]) + prfForVersion(version, suite)(keyMaterial, masterSecret, keyExpansionLabel, seed[0:]) clientMAC = keyMaterial[:macLen] keyMaterial = keyMaterial[macLen:] serverMAC = keyMaterial[:macLen] @@ -166,11 +178,33 @@ func keysFromMasterSecret(version uint16, masterSecret, clientRandom, serverRand return } -func newFinishedHash(version uint16) finishedHash { - if version >= VersionTLS12 { - return finishedHash{sha256.New(), sha256.New(), nil, nil, version} +// lookupTLSHash looks up the corresponding crypto.Hash for a given +// TLS hash identifier. +func lookupTLSHash(hash uint8) (crypto.Hash, error) { + switch hash { + case hashSHA1: + return crypto.SHA1, nil + case hashSHA256: + return crypto.SHA256, nil + case hashSHA384: + return crypto.SHA384, nil + default: + return 0, errors.New("tls: unsupported hash algorithm") + } +} + +func newFinishedHash(version uint16, cipherSuite *cipherSuite) finishedHash { + var buffer []byte + if version == VersionSSL30 || version >= VersionTLS12 { + buffer = []byte{} } - return finishedHash{sha1.New(), sha1.New(), md5.New(), md5.New(), version} + + prf, hash := prfAndHashForVersion(version, cipherSuite) + if hash != 0 { + return finishedHash{hash.New(), hash.New(), nil, nil, buffer, version, prf} + } + + return finishedHash{sha1.New(), sha1.New(), md5.New(), md5.New(), buffer, version, prf} } // A finishedHash calculates the hash of a set of handshake messages suitable @@ -183,10 +217,14 @@ type finishedHash struct { clientMD5 hash.Hash serverMD5 hash.Hash + // In TLS 1.2, a full buffer is sadly required. + buffer []byte + version uint16 + prf func(result, secret, label, seed []byte) } -func (h finishedHash) Write(msg []byte) (n int, err error) { +func (h *finishedHash) Write(msg []byte) (n int, err error) { h.client.Write(msg) h.server.Write(msg) @@ -194,14 +232,29 @@ func (h finishedHash) Write(msg []byte) (n int, err error) { h.clientMD5.Write(msg) h.serverMD5.Write(msg) } + + if h.buffer != nil { + h.buffer = append(h.buffer, msg...) + } + return len(msg), nil } +func (h finishedHash) Sum() []byte { + if h.version >= VersionTLS12 { + return h.client.Sum(nil) + } + + out := make([]byte, 0, md5.Size+sha1.Size) + out = h.clientMD5.Sum(out) + return h.client.Sum(out) +} + // finishedSum30 calculates the contents of the verify_data member of a SSLv3 // Finished message given the MD5 and SHA1 hashes of a set of handshake // messages. -func finishedSum30(md5, sha1 hash.Hash, masterSecret []byte, magic [4]byte) []byte { - md5.Write(magic[:]) +func finishedSum30(md5, sha1 hash.Hash, masterSecret []byte, magic []byte) []byte { + md5.Write(magic) md5.Write(masterSecret) md5.Write(ssl30Pad1[:]) md5Digest := md5.Sum(nil) @@ -212,7 +265,7 @@ func finishedSum30(md5, sha1 hash.Hash, masterSecret []byte, magic [4]byte) []by md5.Write(md5Digest) md5Digest = md5.Sum(nil) - sha1.Write(magic[:]) + sha1.Write(magic) sha1.Write(masterSecret) sha1.Write(ssl30Pad1[:40]) sha1Digest := sha1.Sum(nil) @@ -236,19 +289,11 @@ var ssl3ServerFinishedMagic = [4]byte{0x53, 0x52, 0x56, 0x52} // Finished message. func (h finishedHash) clientSum(masterSecret []byte) []byte { if h.version == VersionSSL30 { - return finishedSum30(h.clientMD5, h.client, masterSecret, ssl3ClientFinishedMagic) + return finishedSum30(h.clientMD5, h.client, masterSecret, ssl3ClientFinishedMagic[:]) } out := make([]byte, finishedVerifyLength) - if h.version >= VersionTLS12 { - seed := h.client.Sum(nil) - prf12(out, masterSecret, clientFinishedLabel, seed) - } else { - seed := make([]byte, 0, md5.Size+sha1.Size) - seed = h.clientMD5.Sum(seed) - seed = h.client.Sum(seed) - prf10(out, masterSecret, clientFinishedLabel, seed) - } + h.prf(out, masterSecret, clientFinishedLabel, h.Sum()) return out } @@ -256,36 +301,67 @@ func (h finishedHash) clientSum(masterSecret []byte) []byte { // Finished message. func (h finishedHash) serverSum(masterSecret []byte) []byte { if h.version == VersionSSL30 { - return finishedSum30(h.serverMD5, h.server, masterSecret, ssl3ServerFinishedMagic) + return finishedSum30(h.serverMD5, h.server, masterSecret, ssl3ServerFinishedMagic[:]) } out := make([]byte, finishedVerifyLength) - if h.version >= VersionTLS12 { - seed := h.server.Sum(nil) - prf12(out, masterSecret, serverFinishedLabel, seed) - } else { - seed := make([]byte, 0, md5.Size+sha1.Size) - seed = h.serverMD5.Sum(seed) - seed = h.server.Sum(seed) - prf10(out, masterSecret, serverFinishedLabel, seed) - } + h.prf(out, masterSecret, serverFinishedLabel, h.Sum()) return out } +// selectClientCertSignatureAlgorithm returns a signatureAndHash to sign a +// client's CertificateVerify with, or an error if none can be found. +func (h finishedHash) selectClientCertSignatureAlgorithm(serverList []signatureAndHash, sigType uint8) (signatureAndHash, error) { + if h.version < VersionTLS12 { + // Nothing to negotiate before TLS 1.2. + return signatureAndHash{signature: sigType}, nil + } + + for _, v := range serverList { + if v.signature == sigType && isSupportedSignatureAndHash(v, supportedSignatureAlgorithms) { + return v, nil + } + } + return signatureAndHash{}, errors.New("tls: no supported signature algorithm found for signing client certificate") +} + // hashForClientCertificate returns a digest, hash function, and TLS 1.2 hash // id suitable for signing by a TLS client certificate. -func (h finishedHash) hashForClientCertificate(sigType uint8) ([]byte, crypto.Hash, uint8) { +func (h finishedHash) hashForClientCertificate(signatureAndHash signatureAndHash, masterSecret []byte) ([]byte, crypto.Hash, error) { + if (h.version == VersionSSL30 || h.version >= VersionTLS12) && h.buffer == nil { + panic("a handshake hash for a client-certificate was requested after discarding the handshake buffer") + } + + if h.version == VersionSSL30 { + if signatureAndHash.signature != signatureRSA { + return nil, 0, errors.New("tls: unsupported signature type for client certificate") + } + + md5Hash := md5.New() + md5Hash.Write(h.buffer) + sha1Hash := sha1.New() + sha1Hash.Write(h.buffer) + return finishedSum30(md5Hash, sha1Hash, masterSecret, nil), crypto.MD5SHA1, nil + } if h.version >= VersionTLS12 { - digest := h.server.Sum(nil) - return digest, crypto.SHA256, hashSHA256 + hashAlg, err := lookupTLSHash(signatureAndHash.hash) + if err != nil { + return nil, 0, err + } + hash := hashAlg.New() + hash.Write(h.buffer) + return hash.Sum(nil), hashAlg, nil } - if sigType == signatureECDSA { - digest := h.server.Sum(nil) - return digest, crypto.SHA1, hashSHA1 + + if signatureAndHash.signature == signatureECDSA { + return h.server.Sum(nil), crypto.SHA1, nil } - digest := make([]byte, 0, 36) - digest = h.serverMD5.Sum(digest) - digest = h.server.Sum(digest) - return digest, crypto.MD5SHA1, 0 /* not specified in TLS 1.2. */ + return h.Sum(), crypto.MD5SHA1, nil +} + +// discardHandshakeBuffer is called when there is no more need to +// buffer the entirety of the handshake messages. +func (h *finishedHash) discardHandshakeBuffer() { + h.buffer = nil } diff --git a/libgo/go/crypto/tls/prf_test.go b/libgo/go/crypto/tls/prf_test.go index a9b6c9e4c79..0a1b1bcbd1b 100644 --- a/libgo/go/crypto/tls/prf_test.go +++ b/libgo/go/crypto/tls/prf_test.go @@ -35,6 +35,7 @@ func TestSplitPreMasterSecret(t *testing.T) { type testKeysFromTest struct { version uint16 + suite *cipherSuite preMasterSecret string clientRandom, serverRandom string masterSecret string @@ -49,13 +50,13 @@ func TestKeysFromPreMasterSecret(t *testing.T) { clientRandom, _ := hex.DecodeString(test.clientRandom) serverRandom, _ := hex.DecodeString(test.serverRandom) - masterSecret := masterFromPreMasterSecret(test.version, in, clientRandom, serverRandom) + masterSecret := masterFromPreMasterSecret(test.version, test.suite, in, clientRandom, serverRandom) if s := hex.EncodeToString(masterSecret); s != test.masterSecret { t.Errorf("#%d: bad master secret %s, want %s", i, s, test.masterSecret) continue } - clientMAC, serverMAC, clientKey, serverKey, _, _ := keysFromMasterSecret(test.version, masterSecret, clientRandom, serverRandom, test.macLen, test.keyLen, 0) + clientMAC, serverMAC, clientKey, serverKey, _, _ := keysFromMasterSecret(test.version, test.suite, masterSecret, clientRandom, serverRandom, test.macLen, test.keyLen, 0) clientMACString := hex.EncodeToString(clientMAC) serverMACString := hex.EncodeToString(serverMAC) clientKeyString := hex.EncodeToString(clientKey) @@ -69,10 +70,20 @@ func TestKeysFromPreMasterSecret(t *testing.T) { } } +func cipherSuiteById(id uint16) *cipherSuite { + for _, cipherSuite := range cipherSuites { + if cipherSuite.id == id { + return cipherSuite + } + } + panic("ciphersuite not found") +} + // These test vectors were generated from GnuTLS using `gnutls-cli --insecure -d 9 ` var testKeysFromTests = []testKeysFromTest{ { VersionTLS10, + cipherSuiteById(TLS_RSA_WITH_RC4_128_SHA), "0302cac83ad4b1db3b9ab49ad05957de2a504a634a386fc600889321e1a971f57479466830ac3e6f468e87f5385fa0c5", "4ae66303755184a3917fcb44880605fcc53baa01912b22ed94473fc69cebd558", "4ae663020ec16e6bb5130be918cfcafd4d765979a3136a5d50c593446e4e44db", @@ -86,6 +97,7 @@ var testKeysFromTests = []testKeysFromTest{ }, { VersionTLS10, + cipherSuiteById(TLS_RSA_WITH_RC4_128_SHA), "03023f7527316bc12cbcd69e4b9e8275d62c028f27e65c745cfcddc7ce01bd3570a111378b63848127f1c36e5f9e4890", "4ae66364b5ea56b20ce4e25555aed2d7e67f42788dd03f3fee4adae0459ab106", "4ae66363ab815cbf6a248b87d6b556184e945e9b97fbdf247858b0bdafacfa1c", @@ -99,6 +111,7 @@ var testKeysFromTests = []testKeysFromTest{ }, { VersionTLS10, + cipherSuiteById(TLS_RSA_WITH_RC4_128_SHA), "832d515f1d61eebb2be56ba0ef79879efb9b527504abb386fb4310ed5d0e3b1f220d3bb6b455033a2773e6d8bdf951d278a187482b400d45deb88a5d5a6bb7d6a7a1decc04eb9ef0642876cd4a82d374d3b6ff35f0351dc5d411104de431375355addc39bfb1f6329fb163b0bc298d658338930d07d313cd980a7e3d9196cac1", "4ae663b2ee389c0de147c509d8f18f5052afc4aaf9699efe8cb05ece883d3a5e", "4ae664d503fd4cff50cfc1fb8fc606580f87b0fcdac9554ba0e01d785bdf278e", @@ -112,6 +125,7 @@ var testKeysFromTests = []testKeysFromTest{ }, { VersionSSL30, + cipherSuiteById(TLS_RSA_WITH_RC4_128_SHA), "832d515f1d61eebb2be56ba0ef79879efb9b527504abb386fb4310ed5d0e3b1f220d3bb6b455033a2773e6d8bdf951d278a187482b400d45deb88a5d5a6bb7d6a7a1decc04eb9ef0642876cd4a82d374d3b6ff35f0351dc5d411104de431375355addc39bfb1f6329fb163b0bc298d658338930d07d313cd980a7e3d9196cac1", "4ae663b2ee389c0de147c509d8f18f5052afc4aaf9699efe8cb05ece883d3a5e", "4ae664d503fd4cff50cfc1fb8fc606580f87b0fcdac9554ba0e01d785bdf278e", diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA b/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA index 00722cba945..4bad7865df3 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA +++ b/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA @@ -1,18 +1,19 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......| +00000000 16 03 01 00 81 01 00 00 7d 03 03 00 00 00 00 00 |........}.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| -00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1a c0 2f |.............../| -00000030 c0 2b c0 11 c0 07 c0 13 c0 09 c0 14 c0 0a 00 05 |.+..............| -00000040 00 2f 00 35 c0 12 00 0a 01 00 00 2e 00 05 00 05 |./.5............| -00000050 01 00 00 00 00 00 0a 00 08 00 06 00 17 00 18 00 |................| -00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................| -00000070 03 02 01 02 03 ff 01 00 01 00 |..........| +00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1e c0 2f |.............../| +00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........| +00000040 c0 0a 00 05 00 2f 00 35 c0 12 00 0a 01 00 00 36 |...../.5.......6| +00000050 00 05 00 05 01 00 00 00 00 00 0a 00 08 00 06 00 |................| +00000060 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| +00000070 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| +00000080 01 00 00 12 00 00 |......| >>> Flow 2 (server to client) -00000000 16 03 01 00 59 02 00 00 55 03 01 53 04 f1 03 46 |....Y...U..S...F| -00000010 0f 84 c4 cb 55 ef 85 f6 4f d7 0e e1 4b 10 d4 bb |....U...O...K...| -00000020 35 87 2d f3 d7 18 ec 4e 95 4b f4 20 28 82 94 d9 |5.-....N.K. (...| -00000030 df c4 fc ee 21 23 c1 e2 76 3e 7b 09 af 2c 39 23 |....!#..v>{..,9#| -00000040 f8 46 6c 31 88 42 f0 79 de 37 2b 00 c0 09 00 00 |.Fl1.B.y.7+.....| +00000000 16 03 01 00 59 02 00 00 55 03 01 c0 e1 5c 5b 45 |....Y...U....\[E| +00000010 70 fc a1 73 44 e7 69 b6 83 a1 71 bc 03 21 2e cc |p..sD.i...q..!..| +00000020 21 7a 28 20 82 6b 2f 77 7d 40 c7 20 0d e4 19 db |!z( .k/w}@. ....| +00000030 35 cd 75 a4 e7 e5 6c 3e c9 d5 fe 9d c5 88 78 7b |5.u...l>......x{| +00000040 c4 fc 04 9a c1 10 7a 15 d9 e9 4a 95 c0 09 00 00 |......z...J.....| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 01 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..| 00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....| @@ -47,21 +48,21 @@ 00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....| 00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.| 00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....| -00000270 2a 16 03 01 00 d5 0c 00 00 d1 03 00 17 41 04 4f |*............A.O| -00000280 47 16 72 98 9e 9f 2e 8e 78 e9 0f fe 95 83 7b aa |G.r.....x.....{.| -00000290 e5 3d c0 7d cf 83 bd 22 0b fd 48 f1 a7 49 a5 7d |.=.}..."..H..I.}| -000002a0 8e 0c 83 7f e1 2d 71 03 cc 90 09 ab f7 35 81 48 |.....-q......5.H| -000002b0 a4 1e 7d 87 21 23 12 58 2c 47 f3 af c7 6c 71 00 |..}.!#.X,G...lq.| -000002c0 8a 30 81 87 02 42 00 b4 03 38 60 43 d9 32 ef 64 |.0...B...8`C.2.d| -000002d0 5a 9c 91 95 0d 10 21 53 c7 78 f8 bf 50 ed 13 5d |Z.....!S.x..P..]| -000002e0 c3 e7 71 d6 11 04 f1 e4 9d ce 17 99 8d 1a 87 1f |..q.............| -000002f0 cb dd f8 1b ae cd bc 4a 77 ab 7c 50 bf 73 c3 ea |.......Jw.|P.s..| -00000300 d6 df 88 56 f6 b1 03 83 02 41 66 3d fb 4e 7e af |...V.....Af=.N~.| -00000310 4e c1 60 fe 09 fa 7e 74 99 66 7f de b4 b2 74 89 |N.`...~t.f....t.| -00000320 1c a4 cf 74 1a 55 a5 be 74 f9 36 21 3d ae c8 c3 |...t.U..t.6!=...| -00000330 24 8e ad db a3 26 67 8f 98 27 e3 93 ee d9 5c fb |$....&g..'....\.| -00000340 85 82 e2 13 c3 50 ab e9 f6 39 2b 16 03 01 00 0e |.....P...9+.....| -00000350 0d 00 00 06 03 01 02 40 00 00 0e 00 00 00 |.......@......| +00000270 2a 16 03 01 00 d6 0c 00 00 d2 03 00 17 41 04 01 |*............A..| +00000280 74 83 af 3a 65 7a ad 1a 63 1f 13 82 9d f4 de 06 |t..:ez..c.......| +00000290 4e 3a 03 81 61 72 ff f8 58 da 7b f5 81 6d 81 57 |N:..ar..X.{..m.W| +000002a0 d9 d1 b1 6d e3 97 db 86 72 17 15 18 16 d4 ec 04 |...m....r.......| +000002b0 32 7c 38 90 6b a4 3c e9 35 79 2d 4c 39 5e 2d 00 |2|8.k.<.5y-L9^-.| +000002c0 8b 30 81 88 02 42 01 44 78 e1 2a bb 95 f7 45 58 |.0...B.Dx.*...EX| +000002d0 d4 0d b6 e4 4e ff 48 b3 11 14 ee d5 6c bb 5f 0c |....N.H.....l._.| +000002e0 90 b6 ef bc 05 77 f6 05 42 b4 d8 a6 70 e6 8c 90 |.....w..B...p...| +000002f0 f0 4b 3b c9 d3 4e 0c 85 65 b4 e0 fe b5 10 09 9b |.K;..N..e.......| +00000300 e1 08 84 ea 93 96 8e a4 02 42 01 c7 15 ee 9d 98 |.........B......| +00000310 b7 25 eb 07 ff f6 94 7e e7 9d a5 17 9e 37 93 40 |.%.....~.....7.@| +00000320 4c 9f eb 6b a3 7a 57 d8 81 c6 d9 09 34 aa 96 8c |L..k.zW.....4...| +00000330 4d 28 2e 9f f7 0b 1c 09 e1 d1 d8 48 6e 8a 8e 9c |M(.........Hn...| +00000340 01 4c e7 2d 53 8f 8e 71 61 82 ff ff 16 03 01 00 |.L.-S..qa.......| +00000350 0e 0d 00 00 06 03 01 02 40 00 00 0e 00 00 00 |........@......| >>> Flow 3 (client to server) 00000000 16 03 01 02 0a 0b 00 02 06 00 02 03 00 02 00 30 |...............0| 00000010 82 01 fc 30 82 01 5e 02 09 00 9a 30 84 6c 26 35 |...0..^....0.l&5| @@ -100,30 +101,30 @@ 00000220 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd a7 |Q.5uq..T[....g..| 00000230 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e f1 |$ >.V...(^.+-O..| 00000240 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 a6 |..lK[.V.2B.X..I.| -00000250 b5 68 1a 41 03 56 6b dc 5a 89 16 03 01 00 90 0f |.h.A.Vk.Z.......| -00000260 00 00 8c 00 8a 30 81 87 02 42 00 c6 85 8e 06 b7 |.....0...B......| -00000270 04 04 e9 cd 9e 3e cb 66 23 95 b4 42 9c 64 81 39 |.....>.f#..B.d.9| -00000280 05 3f b5 21 f8 28 af 60 6b 4d 3d ba a1 4b 5e 77 |.?.!.(.`kM=..K^w| -00000290 ef e7 59 28 fe 1d c1 27 a2 ff a8 de 33 48 b3 c1 |..Y(...'....3H..| -000002a0 85 6a 42 9b f9 7e 7e 31 c2 e5 bd 66 02 41 4b 49 |.jB..~~1...f.AKI| -000002b0 c6 cd 02 e3 83 f7 03 50 18 6d b4 c9 51 02 c0 ab |.......P.m..Q...| -000002c0 87 bc e0 3e 4b 89 53 3a e2 65 89 97 02 c1 87 f1 |...>K.S:.e......| -000002d0 67 d0 f2 06 28 4e 51 4e fd f0 01 be 41 3c 52 42 |g...(NQN....AD$..w.wo...| -000002f0 03 01 00 01 01 16 03 01 00 30 a3 da 45 22 96 83 |.........0..E"..| -00000300 59 90 e9 6b ec 3b 77 50 05 89 e6 0c 61 d1 1d 2b |Y..k.;wP....a..+| -00000310 da d4 49 bf b9 c6 dd ad c3 9c 82 bd 53 62 e8 57 |..I.........Sb.W| -00000320 a4 6a e7 9f b1 d5 39 77 88 6d |.j....9w.m| +00000250 b5 68 1a 41 03 56 6b dc 5a 89 16 03 01 00 91 0f |.h.A.Vk.Z.......| +00000260 00 00 8d 00 8b 30 81 88 02 42 01 91 2d e9 99 a4 |.....0...B..-...| +00000270 88 5c 03 9c ea 8b 64 07 f2 c9 e7 ad 5b a3 fb 27 |.\....d.....[..'| +00000280 fd 19 9b 78 bd 7b 9d 0a cc 8a 61 c5 83 33 02 29 |...x.{....a..3.)| +00000290 c3 66 24 9d 5f bc 03 d9 2a 49 aa 59 51 83 49 72 |.f$._...*I.YQ.Ir| +000002a0 13 be ea 82 5a 5c 09 2f da 23 bc 18 02 42 01 0d |....Z\./.#...B..| +000002b0 a1 15 4d fe 18 ec 90 d5 4e 9a 75 60 05 67 10 5e |..M.....N.u`.g.^| +000002c0 3c 34 00 e8 18 33 8f 90 26 2e d3 a9 81 6c 43 17 |<4...3..&....lC.| +000002d0 80 9e c5 bd 23 c9 24 96 a1 29 23 a4 13 3f ad d2 |....#.$..)#..?..| +000002e0 45 19 0b 56 56 4b c1 f1 cc 70 c8 af 44 ff 34 96 |E..VVK...p..D.4.| +000002f0 14 03 01 00 01 01 16 03 01 00 30 c4 0c 67 53 06 |..........0..gS.| +00000300 49 b3 c9 5c 2e 72 f6 54 ba ad ac a8 80 55 17 01 |I..\.r.T.....U..| +00000310 5c 44 71 7d ad 15 34 95 9a 7f 7b 95 0e 08 70 ce |\Dq}..4...{...p.| +00000320 5a 33 f4 3b 4e 80 06 43 70 93 17 |Z3.;N..Cp..| >>> Flow 4 (server to client) -00000000 14 03 01 00 01 01 16 03 01 00 30 a4 45 dd 99 df |..........0.E...| -00000010 66 ae f5 c7 bd 1a eb 6a ff ac a6 38 14 81 b5 07 |f......j...8....| -00000020 86 24 80 f1 09 59 ad 33 3d 43 ed 9e 43 b1 1e 9f |.$...Y.3=C..C...| -00000030 bd 8c b3 e0 41 83 a1 34 91 c5 a1 |....A..4...| +00000000 14 03 01 00 01 01 16 03 01 00 30 3b ba 6c 73 ec |..........0;.ls.| +00000010 11 5b 44 46 1d bb 31 1b 1b e8 d8 51 4f 95 b0 40 |.[DF..1....QO..@| +00000020 87 49 33 73 40 98 61 1c 94 02 48 9b 80 d3 6c af |.I3s@.a...H...l.| +00000030 e2 31 63 11 a7 c8 db ed 7a a4 4d |.1c.....z.M| >>> Flow 5 (client to server) -00000000 17 03 01 00 20 ae e3 ae 7f 2d e3 a2 f7 1b 4e 69 |.... ....-....Ni| -00000010 cb 18 c6 68 42 f8 de 61 92 4c fa d6 19 7c 8c 09 |...hB..a.L...|..| -00000020 82 e2 f2 32 19 17 03 01 00 20 2a 77 65 1f c1 fd |...2..... *we...| -00000030 5e 37 b7 15 f6 1f 4c 7f 5f 89 52 b4 32 27 4d 17 |^7....L._.R.2'M.| -00000040 33 c6 e8 50 ac 70 c8 b9 2d 0a 15 03 01 00 20 e0 |3..P.p..-..... .| -00000050 cb ce 07 80 55 a0 46 ca a7 25 4c 5f 9d 7c 73 37 |....U.F..%L_.|s7| -00000060 de 72 6d 36 a8 e4 be fd 2a e7 f8 8d 14 80 b7 |.rm6....*......| +00000000 17 03 01 00 20 2e f7 66 f0 ce 50 d7 38 7a d4 fd |.... ..f..P.8z..| +00000010 e3 66 b1 76 76 59 ad bc b0 0a 75 1d f0 92 6e e3 |.f.vvY....u...n.| +00000020 21 1d 13 dc ad 17 03 01 00 20 f1 b2 0f 3b 26 91 |!........ ...;&.| +00000030 ed ff 9f fc 41 04 7e 47 17 02 af 0c 2b e8 b7 31 |....A.~G....+..1| +00000040 ae 29 71 f9 a8 89 84 f3 e8 da 15 03 01 00 20 1f |.)q........... .| +00000050 26 64 cf 34 c1 48 6b 79 61 e2 77 57 9d 27 14 45 |&d.4.Hkya.wW.'.E| +00000060 46 24 ad 2d 35 57 db 2b 32 03 e2 68 b0 1a 5a |F$.-5W.+2..h..Z| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA b/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA index c0be82491e2..0e420a64804 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA +++ b/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA @@ -1,18 +1,19 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......| +00000000 16 03 01 00 81 01 00 00 7d 03 03 00 00 00 00 00 |........}.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| -00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1a c0 2f |.............../| -00000030 c0 2b c0 11 c0 07 c0 13 c0 09 c0 14 c0 0a 00 05 |.+..............| -00000040 00 2f 00 35 c0 12 00 0a 01 00 00 2e 00 05 00 05 |./.5............| -00000050 01 00 00 00 00 00 0a 00 08 00 06 00 17 00 18 00 |................| -00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................| -00000070 03 02 01 02 03 ff 01 00 01 00 |..........| +00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1e c0 2f |.............../| +00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........| +00000040 c0 0a 00 05 00 2f 00 35 c0 12 00 0a 01 00 00 36 |...../.5.......6| +00000050 00 05 00 05 01 00 00 00 00 00 0a 00 08 00 06 00 |................| +00000060 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| +00000070 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| +00000080 01 00 00 12 00 00 |......| >>> Flow 2 (server to client) -00000000 16 03 01 00 51 02 00 00 4d 03 01 53 04 f1 02 ed |....Q...M..S....| -00000010 86 9c 56 84 5a d3 7d d7 f3 4e 6f 2c 69 0d f0 59 |..V.Z.}..No,i..Y| -00000020 a5 d1 de 2d 03 2f dd 63 c3 ab fa 20 30 d6 5a 24 |...-./.c... 0.Z$| -00000030 5c 31 67 36 8d 4c 43 e1 64 c4 8a 2c a5 fd 39 92 |\1g6.LC.d..,..9.| -00000040 c5 6f 58 47 a3 fe 63 14 98 92 11 90 00 05 00 00 |.oXG..c.........| +00000000 16 03 01 00 51 02 00 00 4d 03 01 b7 de 52 5a 07 |....Q...M....RZ.| +00000010 43 b8 72 1d d9 6f 5c a5 70 da ee 27 b7 a9 50 9d |C.r..o\.p..'..P.| +00000020 e7 75 ad 61 a5 2f 69 47 2a d8 2e 20 a8 b0 64 6b |.u.a./iG*.. ..dk| +00000030 4d 25 ec 50 2b 8e a7 9b 0c f9 f5 3c 62 96 a3 53 |M%.P+.......f#..B.d.9| -000002c0 05 3f b5 21 f8 28 af 60 6b 4d 3d ba a1 4b 5e 77 |.?.!.(.`kM=..K^w| -000002d0 ef e7 59 28 fe 1d c1 27 a2 ff a8 de 33 48 b3 c1 |..Y(...'....3H..| -000002e0 85 6a 42 9b f9 7e 7e 31 c2 e5 bd 66 02 41 4b 49 |.jB..~~1...f.AKI| -000002f0 c6 cd 02 e3 83 f7 03 50 18 6d b4 c9 51 02 c0 ab |.......P.m..Q...| -00000300 87 bc e0 3e 4b 89 53 3a e2 65 89 97 02 c1 87 f1 |...>K.S:.e......| -00000310 67 d0 f2 06 28 4e 51 4e fd f0 01 47 e7 c9 d9 23 |g...(NQN...G...#| -00000320 21 6b 87 d2 55 e3 c9 f7 eb 86 d5 1e 50 df d5 14 |!k..U.......P...| -00000330 03 01 00 01 01 16 03 01 00 24 95 62 42 be 90 39 |.........$.bB..9| -00000340 68 ae f5 77 47 21 14 b9 ac ee 81 2d e3 9e c7 34 |h..wG!.....-...4| -00000350 3a 00 5c c9 12 1d c0 5a 7c e7 ef e0 cd fd |:.\....Z|.....| +00000290 d4 1c 43 d1 30 6f 55 4e 0a 70 16 03 01 00 91 0f |..C.0oUN.p......| +000002a0 00 00 8d 00 8b 30 81 88 02 42 00 b5 1a 9d 48 90 |.....0...B....H.| +000002b0 2f d9 1a 04 66 f7 3b 4d d7 ae d9 1e dd 3c fa 24 |/...f.;M.....<.$| +000002c0 0f 24 97 b2 61 46 16 d9 a0 35 f9 f7 54 45 92 fd |.$..aF...5..TE..| +000002d0 10 56 ab 26 d7 b5 10 80 8b 88 95 ef c6 73 1c d2 |.V.&.........s..| +000002e0 ff e9 20 cd 18 a8 40 c4 4d 83 c2 e2 02 42 01 8c |.. ...@.M....B..| +000002f0 d2 13 4c cc e5 38 37 17 6c 83 d6 ad c1 dc af ec |..L..87.l.......| +00000300 8d 06 75 b8 08 ad 56 4a 8f b9 03 59 80 f8 81 d4 |..u...VJ...Y....| +00000310 f3 91 89 eb 9c 27 5d e1 dc 6d ef d6 20 da e7 9c |.....']..m.. ...| +00000320 71 75 cb 2a f9 e4 05 46 c8 85 ca 7b 9c 97 e8 6d |qu.*...F...{...m| +00000330 14 03 01 00 01 01 16 03 01 00 24 9f 67 4e 22 04 |..........$.gN".| +00000340 10 f4 28 55 3e 50 88 90 61 07 42 29 f5 9b f5 32 |..(U>P..a.B)...2| +00000350 16 3d ea c1 8f aa a1 4c b5 72 26 d8 32 cd 50 |.=.....L.r&.2.P| >>> Flow 4 (server to client) -00000000 14 03 01 00 01 01 16 03 01 00 24 ea 98 c0 fb 86 |..........$.....| -00000010 87 7a 2e e1 c7 68 61 3e 5b cc da 1f d6 7b ab 5a |.z...ha>[....{.Z| -00000020 a0 ae a2 cf d0 54 44 19 12 db 75 2b 8c 73 8c |.....TD...u+.s.| +00000000 14 03 01 00 01 01 16 03 01 00 24 df 8d f1 07 6d |..........$....m| +00000010 63 39 fc ba b1 67 3b 68 85 b9 37 7d d3 67 19 76 |c9...g;h..7}.g.v| +00000020 34 a4 1b 86 31 bd fe 06 72 00 d8 2b f2 65 3d |4...1...r..+.e=| >>> Flow 5 (client to server) -00000000 17 03 01 00 1a f3 28 77 31 33 4c b3 7c 4b 75 61 |......(w13L.|Kua| -00000010 38 69 6b ae c9 36 ab 2e 56 16 29 6a 9a 00 2f 15 |8ik..6..V.)j../.| -00000020 03 01 00 16 6b ed 68 18 ed ff 44 39 9b 4a e4 a2 |....k.h...D9.J..| -00000030 cd 79 ef 2a 3e 5a 4d b1 5d 56 |.y.*>ZM.]V| +00000000 17 03 01 00 1a 60 cc 81 4f 8b 73 b3 7f 34 bf f1 |.....`..O.s..4..| +00000010 7c d8 32 0a ef 2a 26 f9 b8 69 84 83 48 21 ee 15 ||.2..*&..i..H!..| +00000020 03 01 00 16 23 7a 0c 65 3a 66 1a 75 03 e4 85 3f |....#z.e:f.u...?| +00000030 83 cd 55 70 99 f4 44 dc 67 ba |..Up..D.g.| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA b/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA index 3e6dbc271a9..7e33edc1897 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA +++ b/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA @@ -1,18 +1,19 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......| +00000000 16 03 01 00 81 01 00 00 7d 03 03 00 00 00 00 00 |........}.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| -00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1a c0 2f |.............../| -00000030 c0 2b c0 11 c0 07 c0 13 c0 09 c0 14 c0 0a 00 05 |.+..............| -00000040 00 2f 00 35 c0 12 00 0a 01 00 00 2e 00 05 00 05 |./.5............| -00000050 01 00 00 00 00 00 0a 00 08 00 06 00 17 00 18 00 |................| -00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................| -00000070 03 02 01 02 03 ff 01 00 01 00 |..........| +00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1e c0 2f |.............../| +00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........| +00000040 c0 0a 00 05 00 2f 00 35 c0 12 00 0a 01 00 00 36 |...../.5.......6| +00000050 00 05 00 05 01 00 00 00 00 00 0a 00 08 00 06 00 |................| +00000060 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| +00000070 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| +00000080 01 00 00 12 00 00 |......| >>> Flow 2 (server to client) -00000000 16 03 01 00 59 02 00 00 55 03 01 53 04 f1 02 4f |....Y...U..S...O| -00000010 73 06 2d 72 41 36 a1 b2 d3 50 97 55 8c c5 f1 43 |s.-rA6...P.U...C| -00000020 37 1f 1a 2a fe 51 70 0b 2f 25 9e 20 50 61 86 80 |7..*.Qp./%. Pa..| -00000030 9a 9c 6d 6f c9 ea 5c ce 0c b7 7c ce e3 be d0 e5 |..mo..\...|.....| -00000040 be d0 c4 80 78 c3 c7 17 0c 2d 8e c8 c0 09 00 00 |....x....-......| +00000000 16 03 01 00 59 02 00 00 55 03 01 dc a9 22 c2 a2 |....Y...U...."..| +00000010 05 ba c4 66 9a 71 aa 0f 92 6a fc df b0 29 4d 36 |...f.q...j...)M6| +00000020 39 2e f8 39 ed 8e f6 7f 8f 17 13 20 f8 9c f3 3d |9..9....... ...=| +00000030 0a 41 8f 30 c7 5d cd 17 c5 ad 1c 52 45 a3 47 8c |.A.0.].....RE.G.| +00000040 07 4c 48 e1 00 2b 32 38 01 c8 79 b7 c0 09 00 00 |.LH..+28..y.....| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 01 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..| 00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....| @@ -47,21 +48,21 @@ 00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....| 00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.| 00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....| -00000270 2a 16 03 01 00 d6 0c 00 00 d2 03 00 17 41 04 b1 |*............A..| -00000280 0f 0f 4a 18 ed 25 32 b3 a3 19 ed 4b 61 b6 eb e4 |..J..%2....Ka...| -00000290 d3 f7 77 13 ac 9f 60 c7 8d 6d cb f1 ee 99 1a 71 |..w...`..m.....q| -000002a0 68 aa d3 a7 70 7f 38 d0 f6 23 ab 9a f6 dd 19 4f |h...p.8..#.....O| -000002b0 ce 10 ef d5 cf 64 85 2f 75 f6 20 06 4b f0 b9 00 |.....d./u. .K...| -000002c0 8b 30 81 88 02 42 01 00 b9 6b 80 91 59 0a 48 3f |.0...B...k..Y.H?| -000002d0 72 16 96 8f 21 2c 28 e4 6d 03 74 66 35 16 7d ec |r...!,(.m.tf5.}.| -000002e0 c7 08 9b 52 b5 05 d9 38 d8 b7 51 42 a7 4a 9f 9b |...R...8..QB.J..| -000002f0 1a 37 14 de c5 f5 16 96 83 81 58 d3 a6 1e ce 8a |.7........X.....| -00000300 bc 19 47 30 fe c5 85 55 02 42 01 4f 61 59 68 85 |..G0...U.B.OaYh.| -00000310 c7 64 23 22 f6 83 53 cc 58 38 25 b5 ce 74 c1 68 |.d#"..S.X8%..t.h| -00000320 9f 32 72 33 ea c9 62 e0 26 63 92 e3 5f 34 10 0b |.2r3..b.&c.._4..| -00000330 3c d5 83 fe 9f 67 69 ef 33 6b 19 c1 ec d6 6c 35 |<....gi.3k....l5| -00000340 89 33 17 d3 9d 93 e2 e5 6e 89 9a a1 16 03 01 00 |.3......n.......| -00000350 0e 0d 00 00 06 03 01 02 40 00 00 0e 00 00 00 |........@......| +00000270 2a 16 03 01 00 d5 0c 00 00 d1 03 00 17 41 04 89 |*............A..| +00000280 95 9a 90 82 59 ab 29 bf 10 06 8c 6c 0d 67 cf b1 |....Y.)....l.g..| +00000290 66 8b 5e 43 b8 46 56 3a 8d 30 92 35 28 82 f2 38 |f.^C.FV:.0.5(..8| +000002a0 6e 19 5d 37 f0 ab fc 78 15 6a 6a 73 ca dc a6 f2 |n.]7...x.jjs....| +000002b0 68 5d b3 ab 6d 68 44 3b 80 d2 d9 cd 78 0a ed 00 |h]..mhD;....x...| +000002c0 8a 30 81 87 02 42 01 80 63 4a 22 4c 8e 66 4e 25 |.0...B..cJ"L.fN%| +000002d0 e1 86 27 81 de eb b3 a0 c4 dc dc e2 a0 94 2a b6 |..'...........*.| +000002e0 b3 e9 e7 42 e1 1d 1a c0 43 8d a1 d6 8d 77 84 06 |...B....C....w..| +000002f0 ba 95 99 e3 54 80 59 4e 3c fb 0c f3 b7 d3 a8 d2 |....T.YN<.......| +00000300 ce 49 97 fb e2 79 91 93 02 41 2b 2c b7 9f 81 ea |.I...y...A+,....| +00000310 de 17 12 af 4d 20 bc a1 43 1d 60 a0 37 52 a2 7b |....M ..C.`.7R.{| +00000320 a8 4c de fd 1d fe 37 3b 00 23 61 ce d2 80 47 43 |.L....7;.#a...GC| +00000330 b0 3a f3 1f aa c7 07 b1 68 5b d8 f3 03 a9 56 5c |.:......h[....V\| +00000340 63 ef 83 1d 9c 9c 8d 29 81 e9 3b 16 03 01 00 0e |c......)..;.....| +00000350 0d 00 00 06 03 01 02 40 00 00 0e 00 00 00 |.......@......| >>> Flow 3 (client to server) 00000000 16 03 01 01 fb 0b 00 01 f7 00 01 f4 00 01 f1 30 |...............0| 00000010 82 01 ed 30 82 01 58 a0 03 02 01 02 02 01 00 30 |...0..X........0| @@ -100,29 +101,29 @@ 00000220 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.| 00000230 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I| 00000240 a6 b5 68 1a 41 03 56 6b dc 5a 89 16 03 01 00 86 |..h.A.Vk.Z......| -00000250 0f 00 00 82 00 80 20 2c 5a 08 3a 00 33 50 19 b2 |...... ,Z.:.3P..| -00000260 0f ba 6c 76 7f 5c 92 e2 78 55 3e 32 32 bb 33 bc |..lv.\..xU>22.3.| -00000270 ab a9 34 e0 83 cf 82 cd 9e 6b 3f 9d e6 49 61 29 |..4......k?..Ia)| -00000280 8b b4 ed e8 12 cd a9 52 86 11 48 64 08 61 72 8d |.......R..Hd.ar.| -00000290 d6 6a ac 42 cc e4 07 5f 08 56 9f 2f c5 35 d3 9b |.j.B..._.V./.5..| -000002a0 e9 0d 91 82 c0 e9 bb 9f a9 8f df 96 85 08 9a 69 |...............i| -000002b0 a4 93 b3 72 37 ba f9 b1 a4 0b b0 9f 43 6a 15 ec |...r7.......Cj..| -000002c0 79 b8 fd 9c 1f 5f 0d 2c 56 33 c7 15 d5 4a b7 82 |y...._.,V3...J..| -000002d0 ea 44 80 20 c5 80 14 03 01 00 01 01 16 03 01 00 |.D. ............| -000002e0 30 c9 c0 7c d7 57 d3 00 ab 87 eb 78 56 6b a1 69 |0..|.W.....xVk.i| -000002f0 1d fa ec ae 38 f3 ef 5d 49 19 0d 4b f0 73 63 af |....8..]I..K.sc.| -00000300 89 b6 cb 76 cf fb b9 c1 99 98 06 0a 54 67 a0 6e |...v........Tg.n| -00000310 e7 |.| +00000250 0f 00 00 82 00 80 0e 80 9c 3a 6e 40 51 09 39 d4 |.........:n@Q.9.| +00000260 40 58 10 da 7f 32 12 08 9e f0 4d 9a d7 20 a2 9c |@X...2....M.. ..| +00000270 b0 95 3a 33 4e f8 b1 a3 74 62 ab 51 7d 23 d4 32 |..:3N...tb.Q}#.2| +00000280 a2 af b8 5a 3b b0 23 e4 7a f1 eb 4d b7 bb 23 d5 |...Z;.#.z..M..#.| +00000290 a9 0d b4 81 d2 b4 45 bd 15 52 ad 58 da 92 a2 c4 |......E..R.X....| +000002a0 30 66 87 f2 ae c5 e4 8c fa ba a0 40 76 b8 3f 72 |0f.........@v.?r| +000002b0 2a d9 95 2a 2d c6 05 3c 1e 2f 11 ef c5 3c 11 e4 |*..*-..<./...<..| +000002c0 be 5a de 37 43 7f 74 52 6e ee 3c 39 cc f1 14 05 |.Z.7C.tRn.<9....| +000002d0 2d 91 c2 3d c4 7c 14 03 01 00 01 01 16 03 01 00 |-..=.|..........| +000002e0 30 cd 3c 92 f8 b9 36 7a e7 8a fb 0f 2f b8 2c 7b |0.<...6z..../.,{| +000002f0 10 59 45 14 0a b0 6a 8c 31 b2 89 5b ac 19 dc 12 |.YE...j.1..[....| +00000300 73 8c 8c 10 49 5a bf 9f bc 58 82 32 11 ba c5 38 |s...IZ...X.2...8| +00000310 ff |.| >>> Flow 4 (server to client) -00000000 14 03 01 00 01 01 16 03 01 00 30 20 db fd ed ed |..........0 ....| -00000010 7c d5 bf 8f 06 3b 86 1b c1 60 7d a4 74 e9 a6 c9 ||....;...`}.t...| -00000020 f5 7c c7 f4 65 91 06 d5 53 88 d7 57 a4 22 b6 1f |.|..e...S..W."..| -00000030 f1 02 e9 79 36 e6 a1 22 51 3a 4c |...y6.."Q:L| +00000000 14 03 01 00 01 01 16 03 01 00 30 da 45 99 fe 52 |..........0.E..R| +00000010 4f cd d0 e6 30 19 f4 bd 80 6d 5c 8a 72 03 d3 88 |O...0....m\.r...| +00000020 38 63 e9 c9 39 ee ab 3f 52 26 84 b0 4d cb 5c a4 |8c..9..?R&..M.\.| +00000030 0d 51 c7 47 48 43 3a bf 89 c7 13 |.Q.GHC:....| >>> Flow 5 (client to server) -00000000 17 03 01 00 20 00 66 51 6a 14 ca ea e2 21 48 74 |.... .fQj....!Ht| -00000010 c4 c1 6e b9 8b 23 af 7c 33 c9 00 f8 0b ec ab 35 |..n..#.|3......5| -00000020 e7 42 0a d1 ae 17 03 01 00 20 00 1c 6d 60 75 5d |.B....... ..m`u]| -00000030 b3 fb 40 2e e0 b7 0d 48 f4 87 ac d4 bf ea 01 0d |..@....H........| -00000040 fe 10 0d 05 04 43 6b 19 ed f2 15 03 01 00 20 f8 |.....Ck....... .| -00000050 03 ac 62 4b 1f db 2e d2 4e 00 c3 a4 57 3c 0a 62 |..bK....N...W<.b| -00000060 05 a0 ef bd 2b 9b 9a 63 27 72 d7 d8 f1 8d 84 |....+..c'r.....| +00000000 17 03 01 00 20 4d d9 1d 0d 3d 8b 73 91 b9 4e 5e |.... M...=.s..N^| +00000010 35 71 4f 67 79 d2 f7 39 35 ea 23 d0 6d 64 de a5 |5qOgy..95.#.md..| +00000020 59 fb 75 1f c9 17 03 01 00 20 ba bd 3c b4 d7 be |Y.u...... ..<...| +00000030 24 64 68 1e 8c b2 bf 6f 78 9f ad 7f fa dd 89 a6 |$dh....ox.......| +00000040 f9 e7 5e 70 db e9 db 3a 62 b2 15 03 01 00 20 2a |..^p...:b..... *| +00000050 82 f4 8b 45 fc 76 35 6c 54 48 62 2f 52 55 f2 d9 |...E.v5lTHb/RU..| +00000060 99 b2 b5 2d 5f a0 05 ab f1 93 58 75 4a 87 35 |...-_.....XuJ.5| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA b/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA index 94e686004f9..9b1a5533acf 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA +++ b/libgo/go/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA @@ -1,18 +1,19 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......| +00000000 16 03 01 00 81 01 00 00 7d 03 03 00 00 00 00 00 |........}.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| -00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1a c0 2f |.............../| -00000030 c0 2b c0 11 c0 07 c0 13 c0 09 c0 14 c0 0a 00 05 |.+..............| -00000040 00 2f 00 35 c0 12 00 0a 01 00 00 2e 00 05 00 05 |./.5............| -00000050 01 00 00 00 00 00 0a 00 08 00 06 00 17 00 18 00 |................| -00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................| -00000070 03 02 01 02 03 ff 01 00 01 00 |..........| +00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1e c0 2f |.............../| +00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........| +00000040 c0 0a 00 05 00 2f 00 35 c0 12 00 0a 01 00 00 36 |...../.5.......6| +00000050 00 05 00 05 01 00 00 00 00 00 0a 00 08 00 06 00 |................| +00000060 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| +00000070 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| +00000080 01 00 00 12 00 00 |......| >>> Flow 2 (server to client) -00000000 16 03 01 00 51 02 00 00 4d 03 01 53 04 f1 02 73 |....Q...M..S...s| -00000010 ee 5f 70 a4 aa 0d be d7 46 a3 25 3f e3 5d ef 7b |._p.....F.%?.].{| -00000020 73 49 7c b6 82 4d 99 2f 31 fc 8b 20 2d a3 33 7c |sI|..M./1.. -.3|| -00000030 a5 c3 85 86 ba 61 4d 05 b0 5e d3 5e 88 6e c3 4b |.....aM..^.^.n.K| -00000040 95 d3 e9 67 f1 96 24 58 7a 6f e6 c5 00 05 00 00 |...g..$Xzo......| +00000000 16 03 01 00 51 02 00 00 4d 03 01 90 e6 e1 c6 bd |....Q...M.......| +00000010 86 08 db 33 94 f3 bd 0b 2d fc e0 ba 89 a7 c5 66 |...3....-......f| +00000020 a5 19 78 33 2b b9 c4 22 d8 e0 63 20 2e 85 53 25 |..x3+.."..c ..S%| +00000030 f2 22 e3 ca 79 94 9e 50 00 13 da 9d 21 33 49 27 |."..y..P....!3I'| +00000040 9b 44 c5 10 bc e8 44 01 04 31 02 81 00 05 00 00 |.D....D..1......| 00000050 05 ff 01 00 01 00 16 03 01 02 be 0b 00 02 ba 00 |................| 00000060 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......| 00000070 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..| @@ -101,24 +102,24 @@ 00000260 e6 bd 77 82 6f 23 b6 e0 bd a2 92 b7 3a ac e8 56 |..w.o#......:..V| 00000270 f1 af 54 5e 46 87 e9 3b 33 e7 b8 28 b7 d6 c8 90 |..T^F..;3..(....| 00000280 35 d4 1c 43 d1 30 6f 55 4e 0a 70 16 03 01 00 86 |5..C.0oUN.p.....| -00000290 0f 00 00 82 00 80 0f 4c d2 b2 f0 94 6d 61 d1 2c |.......L....ma.,| -000002a0 db 6f 79 03 bd 40 b2 d2 1d 61 ef 83 1b 4a 0c 7b |.oy..@...a...J.{| -000002b0 c5 73 1e 1a 81 e7 67 0a d6 aa 2d 04 04 cc 0e 4b |.s....g...-....K| -000002c0 2e da 96 7f 15 6c 05 ee c4 53 7e 33 89 28 7d db |.....l...S~3.(}.| -000002d0 a1 77 43 ba a3 51 a9 1c b9 f5 ec 9a 8d eb 2c 46 |.wC..Q........,F| -000002e0 5c 33 59 6b 16 af de f4 9b 80 76 a3 22 30 5d bb |\3Yk......v."0].| -000002f0 02 b9 77 96 8a db 36 9f 54 95 00 d8 58 e1 aa 04 |..w...6.T...X...| -00000300 98 c9 0c 32 ae 62 81 12 0c f6 1b 76 c6 58 a7 8c |...2.b.....v.X..| -00000310 0e d8 b7 8e ed 0f 14 03 01 00 01 01 16 03 01 00 |................| -00000320 24 1d c0 20 02 2d da 69 54 29 8c ff af 5c 56 a8 |$.. .-.iT)...\V.| -00000330 eb d0 09 95 29 8f 52 8c e2 7b 9f 36 3e 47 a0 33 |....).R..{.6>G.3| -00000340 2e 63 a2 24 93 |.c.$.| +00000290 0f 00 00 82 00 80 10 19 57 14 c3 ee 2d da cb de |........W...-...| +000002a0 f3 70 c5 62 91 2f ad 62 dd 10 f1 65 20 a2 cf d5 |.p.b./.b...e ...| +000002b0 cd 6d 5f e4 b3 3e 38 e8 d0 1a f7 f0 e7 7e b6 5d |.m_..>8......~.]| +000002c0 c3 6c ad f6 0d 05 1e 41 35 2d 04 15 3c 36 96 00 |.l.....A5-..<6..| +000002d0 e8 02 b2 01 b8 9f 21 4b 34 85 ef 5e 4c 87 ef 49 |......!K4..^L..I| +000002e0 df d1 9a b6 b2 bd b8 90 fd 3f 31 93 0c dc c7 18 |.........?1.....| +000002f0 ff f6 76 bd 5b 74 76 b3 62 87 6a df ff 63 15 d5 |..v.[tv.b.j..c..| +00000300 94 d5 fe fd 4c 12 df f1 35 07 f1 8a f1 77 7a 35 |....L...5....wz5| +00000310 cd 99 1d 2a d7 9a 14 03 01 00 01 01 16 03 01 00 |...*............| +00000320 24 8d db 0c 87 b5 df fd 68 de fe 46 3e e4 41 b5 |$.......h..F>.A.| +00000330 19 64 68 3c c4 e2 2b 43 50 e4 ee 52 75 34 d3 c1 |.dh<..+CP..Ru4..| +00000340 51 18 c0 b2 5f |Q..._| >>> Flow 4 (server to client) -00000000 14 03 01 00 01 01 16 03 01 00 24 99 e8 fb 65 f4 |..........$...e.| -00000010 95 ae 8b 71 cc 5d a4 95 a7 27 98 fd 16 3f 7a 1a |...q.]...'...?z.| -00000020 b6 bd bf 0a 58 72 77 97 1f 8e b1 dd 4b 12 12 |....Xrw.....K..| +00000000 14 03 01 00 01 01 16 03 01 00 24 0b a4 04 46 60 |..........$...F`| +00000010 15 fb 9a 9f 47 51 6d b4 4b c6 e7 2a 1b 98 b4 8a |....GQm.K..*....| +00000020 8a 1a 03 cf f4 16 7d 80 70 27 e5 e8 d5 9f ad |......}.p'.....| >>> Flow 5 (client to server) -00000000 17 03 01 00 1a 42 70 c0 89 78 12 5c 91 7e 88 2d |.....Bp..x.\.~.-| -00000010 2f 8f be f2 f2 12 9d 81 ae 78 08 38 5e 6d 1b 15 |/........x.8^m..| -00000020 03 01 00 16 1a 64 b1 6f 8a ff d3 63 6a c7 b8 95 |.....d.o...cj...| -00000030 3d b0 87 bc 62 e9 88 5b 26 bd |=...b..[&.| +00000000 17 03 01 00 1a 6f 84 50 27 c7 f1 aa b0 04 7d 80 |.....o.P'.....}.| +00000010 6d a7 20 8a 73 cf d9 de 9a d6 f5 e9 36 13 7c 15 |m. .s.......6.|.| +00000020 03 01 00 16 e8 0b e0 a6 3b 1e 21 24 65 4e 49 b2 |........;.!$eNI.| +00000030 2d a3 41 2b 98 23 4e d5 4b fd |-.A+.#N.K.| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES b/libgo/go/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES index 30c4c6b831a..937c2909f90 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES +++ b/libgo/go/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES @@ -1,18 +1,19 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......| +00000000 16 03 01 00 81 01 00 00 7d 03 03 00 00 00 00 00 |........}.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| -00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1a c0 2f |.............../| -00000030 c0 2b c0 11 c0 07 c0 13 c0 09 c0 14 c0 0a 00 05 |.+..............| -00000040 00 2f 00 35 c0 12 00 0a 01 00 00 2e 00 05 00 05 |./.5............| -00000050 01 00 00 00 00 00 0a 00 08 00 06 00 17 00 18 00 |................| -00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................| -00000070 03 02 01 02 03 ff 01 00 01 00 |..........| +00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1e c0 2f |.............../| +00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........| +00000040 c0 0a 00 05 00 2f 00 35 c0 12 00 0a 01 00 00 36 |...../.5.......6| +00000050 00 05 00 05 01 00 00 00 00 00 0a 00 08 00 06 00 |................| +00000060 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| +00000070 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| +00000080 01 00 00 12 00 00 |......| >>> Flow 2 (server to client) -00000000 16 03 01 00 59 02 00 00 55 03 01 53 04 f1 02 b2 |....Y...U..S....| -00000010 e0 f6 f6 b5 c9 5b 28 d0 5d 58 1b 6f 4e 2b 9d 05 |.....[(.]X.oN+..| -00000020 2a b9 b4 da 45 cf f3 10 b2 23 44 20 f8 4d 59 05 |*...E....#D .MY.| -00000030 ad 27 f2 a0 ee 7f ec cc 20 dc e7 a2 1b 07 b3 a5 |.'...... .......| -00000040 37 7e 61 3d d6 5c 03 cf cc f5 9b ca c0 09 00 00 |7~a=.\..........| +00000000 16 03 01 00 59 02 00 00 55 03 01 f5 8f 8d 8e ca |....Y...U.......| +00000010 30 6b fe 63 c9 84 57 c0 f1 c8 a5 d8 10 56 14 62 |0k.c..W......V.b| +00000020 c8 02 b2 89 21 5c 09 67 86 d8 9b 20 dc 3f 55 54 |....!\.g... .?UT| +00000030 33 29 47 45 d3 e0 87 1a 4b 1b 75 30 89 e0 4d 01 |3)GE....K.u0..M.| +00000040 a1 6a 46 f7 8f 23 d6 74 fd 90 2f 53 c0 09 00 00 |.jF..#.t../S....| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 01 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..| 00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....| @@ -47,20 +48,20 @@ 00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....| 00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.| 00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....| -00000270 2a 16 03 01 00 d5 0c 00 00 d1 03 00 17 41 04 da |*............A..| -00000280 5a fd 09 e5 d6 c0 70 41 5e 3a 87 eb df 0c ad 90 |Z.....pA^:......| -00000290 22 8a 2f 90 81 0c 24 00 68 92 f3 d5 95 2f 93 43 |"./...$.h..../.C| -000002a0 e9 58 2d 18 28 62 ee 33 5b 21 2e 49 87 21 4d 32 |.X-.(b.3[!.I.!M2| -000002b0 32 19 b3 ba fe 2d 9a 85 12 0e a1 77 08 06 75 00 |2....-.....w..u.| -000002c0 8a 30 81 87 02 42 01 91 14 fc 68 74 95 10 4b d4 |.0...B....ht..K.| -000002d0 67 60 12 46 bb b0 f6 98 77 a3 41 b8 01 5c 49 54 |g`.F....w.A..\IT| -000002e0 9e 3e 81 e7 97 a3 b9 73 6e 15 74 67 be e5 d9 eb |.>.....sn.tg....| -000002f0 8b 87 c5 22 ab ab 58 28 4f d1 b6 80 94 1b f5 f7 |..."..X(O.......| -00000300 12 43 ef 0a c7 3e 1a 76 02 41 7a 00 49 cb 9f 3b |.C...>.v.Az.I..;| -00000310 91 6e 38 58 0a d3 d0 d1 ee 67 f0 b6 5d cd fa 23 |.n8X.....g..]..#| -00000320 b6 98 43 af 9c 71 90 1e 1d 50 a2 6e 61 5b f2 92 |..C..q...P.na[..| -00000330 b4 69 73 f2 3b 54 bf 1c 9d 05 19 97 e4 4e 41 9e |.is.;T.......NA.| -00000340 f2 9a 76 77 9a 86 43 1f 1f 30 a2 16 03 01 00 04 |..vw..C..0......| +00000270 2a 16 03 01 00 d5 0c 00 00 d1 03 00 17 41 04 22 |*............A."| +00000280 8a 47 c6 d3 7a c4 30 a4 8e 41 11 ac b3 2d 2f 45 |.G..z.0..A...-/E| +00000290 61 54 9b 1f 2e 03 5d 50 eb fc 5b 44 a0 a7 48 78 |aT....]P..[D..Hx| +000002a0 ce 14 d5 39 a7 c4 ed f5 4d 8f da 9d 71 52 69 70 |...9....M...qRip| +000002b0 7e 52 29 ad 80 8a 19 ad 4c 5d 1c f1 22 7e 1a 00 |~R).....L].."~..| +000002c0 8a 30 81 87 02 42 00 97 8b 6d f7 87 c1 a9 a6 55 |.0...B...m.....U| +000002d0 0f 61 c2 f2 e1 05 26 a8 83 16 1c 0b 69 3b 95 57 |.a....&.....i;.W| +000002e0 76 5b eb 45 7a bd 6a f1 3e a0 93 49 fa 74 32 fd |v[.Ez.j.>..I.t2.| +000002f0 dc 20 3a bb e3 ee 6d b8 56 aa e9 d2 7d 6a ec b7 |. :...m.V...}j..| +00000300 0a bd aa dc d7 b0 69 65 02 41 4d 19 61 16 d8 5f |......ie.AM.a.._| +00000310 1d c1 32 25 15 26 eb 88 5b c1 dd 9a 12 40 fa f1 |..2%.&..[....@..| +00000320 81 5e 7d b8 2b 6e 60 63 1a 9e 86 cb d5 64 96 d4 |.^}.+n`c.....d..| +00000330 75 fc 02 33 e0 66 60 b2 40 47 cf e6 6d 25 9c 83 |u..3.f`.@G..m%..| +00000340 23 d3 4b e2 eb ac f1 56 44 f8 3f 16 03 01 00 04 |#.K....VD.?.....| 00000350 0e 00 00 00 |....| >>> Flow 3 (client to server) 00000000 16 03 01 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..| @@ -68,20 +69,20 @@ 00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.| 00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I| 00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 01 00 01 |..h.A.Vk.Z......| -00000050 01 16 03 01 00 30 88 60 65 b2 d7 51 1f ad 96 56 |.....0.`e..Q...V| -00000060 4e 0a 20 eb b5 b0 1a dd 4c f6 1a cf d4 5c 47 c4 |N. .....L....\G.| -00000070 9c 7c a0 36 dd d1 1b 96 91 99 c0 a7 2d 9a 7c 42 |.|.6........-.|B| -00000080 51 d1 de 87 2b a4 |Q...+.| +00000050 01 16 03 01 00 30 cc 86 f1 7e 6e a8 c9 b5 02 5f |.....0...~n...._| +00000060 fb b2 3b ea 74 bf a8 da e4 6a 69 50 a2 5a 78 4f |..;.t....jiP.ZxO| +00000070 35 e1 cc 87 c3 fb 1f 5e f6 a4 5c 63 cc 59 12 3e |5......^..\c.Y.>| +00000080 07 c3 a8 d7 87 ba |......| >>> Flow 4 (server to client) -00000000 14 03 01 00 01 01 16 03 01 00 30 86 6c b5 94 69 |..........0.l..i| -00000010 2e e0 55 a2 4d a8 63 f2 5b 1f ae 34 21 c8 21 6a |..U.M.c.[..4!.!j| -00000020 00 b6 56 ed 4e 2a b0 ff 01 2f da ce a1 c0 41 03 |..V.N*.../....A.| -00000030 a9 1b 6e 2e e1 88 50 ba 62 14 88 |..n...P.b..| +00000000 14 03 01 00 01 01 16 03 01 00 30 e8 b6 20 b9 c1 |..........0.. ..| +00000010 07 38 38 bb 42 b2 b2 a1 c5 8d 92 62 db 67 ab fc |.88.B......b.g..| +00000020 f6 64 3f 71 83 1d a0 86 bb 2d e3 4f 65 d5 44 52 |.d?q.....-.Oe.DR| +00000030 4d f5 62 80 3c af 95 87 19 7c 20 |M.b.<....| | >>> Flow 5 (client to server) -00000000 17 03 01 00 20 a6 63 0a 2f a5 dc e1 fb cb 7b 1f |.... .c./.....{.| -00000010 f2 da 74 c3 ff e9 f5 8b 9c 5f 0c d3 f7 1f 44 e6 |..t......_....D.| -00000020 90 13 5c 48 50 17 03 01 00 20 c7 75 b5 ff bc 09 |..\HP.... .u....| -00000030 34 f2 45 db 0d 22 08 8e f1 35 cd b6 0f b0 eb 2a |4.E.."...5.....*| -00000040 b7 1a d0 8e 14 a4 54 84 f9 dc 15 03 01 00 20 e0 |......T....... .| -00000050 36 3d aa b3 a9 b4 20 23 ca 9e 8c 5d fc a8 c8 b7 |6=.... #...]....| -00000060 f5 c2 b6 d0 5a e2 ce a5 7b 68 a0 48 86 95 6a |....Z...{h.H..j| +00000000 17 03 01 00 20 bd 65 61 28 e5 ea 1b 81 db 75 92 |.... .ea(.....u.| +00000010 ad a7 3b 01 a3 23 0e 3b 60 10 8a 1e 04 91 fb 9e |..;..#.;`.......| +00000020 7a cf 1f cf 9c 17 03 01 00 20 87 9c dc ed 0d 08 |z........ ......| +00000030 56 40 23 8b c5 2c d8 7e 42 82 3c 0a c9 f3 77 6d |V@#..,.~B.<...wm| +00000040 8d 9a 30 d1 9c c4 ae 04 fb b7 15 03 01 00 20 f7 |..0........... .| +00000050 f0 12 0d e5 03 c1 80 4e 7e 21 d7 75 55 1c 91 89 |.......N~!.uU...| +00000060 e7 e1 45 fc 7d d8 fc b1 d0 e7 dc e2 4c ba f4 |..E.}.......L..| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES b/libgo/go/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES index 868f0ceb0e5..f8183f10353 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES +++ b/libgo/go/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES @@ -1,18 +1,19 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......| +00000000 16 03 01 00 81 01 00 00 7d 03 03 00 00 00 00 00 |........}.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| -00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1a c0 2f |.............../| -00000030 c0 2b c0 11 c0 07 c0 13 c0 09 c0 14 c0 0a 00 05 |.+..............| -00000040 00 2f 00 35 c0 12 00 0a 01 00 00 2e 00 05 00 05 |./.5............| -00000050 01 00 00 00 00 00 0a 00 08 00 06 00 17 00 18 00 |................| -00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................| -00000070 03 02 01 02 03 ff 01 00 01 00 |..........| +00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1e c0 2f |.............../| +00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........| +00000040 c0 0a 00 05 00 2f 00 35 c0 12 00 0a 01 00 00 36 |...../.5.......6| +00000050 00 05 00 05 01 00 00 00 00 00 0a 00 08 00 06 00 |................| +00000060 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| +00000070 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| +00000080 01 00 00 12 00 00 |......| >>> Flow 2 (server to client) -00000000 16 03 01 00 59 02 00 00 55 03 01 53 04 f1 02 21 |....Y...U..S...!| -00000010 67 b5 2b 34 fb 62 d7 36 4f cf 68 2e 29 39 d0 28 |g.+4.b.6O.h.)9.(| -00000020 3a 02 32 82 8f 95 de 62 d6 03 77 20 e6 98 56 cd |:.2....b..w ..V.| -00000030 96 24 d1 b9 4d eb 51 19 bb b7 71 f4 9c 29 32 d4 |.$..M.Q...q..)2.| -00000040 e5 c6 0a 54 e0 4a 20 29 3e bd 06 0d c0 13 00 00 |...T.J )>.......| +00000000 16 03 01 00 59 02 00 00 55 03 01 5c 69 d0 60 d6 |....Y...U..\i.`.| +00000010 b3 f4 23 19 5e 3e 26 d8 29 ea c3 94 e4 ed 51 f6 |..#.^>&.).....Q.| +00000020 58 a2 e3 9c 79 a1 0b 6d 29 90 32 20 23 5b 47 b1 |X...y..m).2 #[G.| +00000030 8f 22 bc 06 aa ee f7 c3 97 ca 93 df b1 90 7d b4 |."............}.| +00000040 8c c0 d9 54 35 ca 5b 11 98 37 84 ea c0 13 00 00 |...T5.[..7......| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 01 02 be 0b 00 02 ba 00 02 b7 00 02 b4 30 82 02 |.............0..| 00000070 b0 30 82 02 19 a0 03 02 01 02 02 09 00 85 b0 bb |.0..............| @@ -58,40 +59,40 @@ 000002f0 5f 33 c4 b6 d8 c9 75 90 96 8c 0f 52 98 b5 cd 98 |_3....u....R....| 00000300 1f 89 20 5f f2 a0 1c a3 1b 96 94 dd a9 fd 57 e9 |.. _..........W.| 00000310 70 e8 26 6d 71 99 9b 26 6e 38 50 29 6c 90 a7 bd |p.&mq..&n8P)l...| -00000320 d9 16 03 01 00 cb 0c 00 00 c7 03 00 17 41 04 05 |.............A..| -00000330 45 33 f8 4b e9 96 0e 4a fd ec 54 76 21 9b 24 8a |E3.K...J..Tv!.$.| -00000340 75 0b 80 84 c7 30 2b 22 f0 85 57 a4 a9 79 d6 f6 |u....0+"..W..y..| -00000350 6d 80 b0 71 d9 66 c9 6c dd 76 fc 32 d0 c6 bc 52 |m..q.f.l.v.2...R| -00000360 2f f1 c9 62 17 53 76 ec be a6 1c 93 f2 b4 5d 00 |/..b.Sv.......].| -00000370 80 72 d9 20 52 70 7c 03 b1 33 fa 51 23 cd 05 97 |.r. Rp|..3.Q#...| -00000380 6f d6 89 2f 8d 2e 3a 17 32 eb f2 ff 6b 39 70 5e |o../..:.2...k9p^| -00000390 21 41 8d 69 02 c8 9a 17 19 e4 48 9b 51 c3 7f 9b |!A.i......H.Q...| -000003a0 8d 4a 83 97 07 0e 30 f1 8b 6b e9 92 12 01 d6 96 |.J....0..k......| -000003b0 f2 1a a2 10 7f 59 87 16 1a fb 55 67 68 fc 78 c6 |.....Y....Ugh.x.| -000003c0 57 ac 05 dd f3 6f 77 84 eb ae b0 33 2d 19 2c ba |W....ow....3-.,.| -000003d0 b8 ae 9f 95 69 85 95 45 5e 37 f4 17 17 9b 03 c1 |....i..E^7......| -000003e0 50 b1 36 42 bd 60 5c 8b d8 b6 f3 c8 34 c8 9d 9d |P.6B.`\.....4...| -000003f0 75 16 03 01 00 04 0e 00 00 00 |u.........| +00000320 d9 16 03 01 00 cb 0c 00 00 c7 03 00 17 41 04 a6 |.............A..| +00000330 57 60 8d 63 4e 4d 3f 48 e0 5d ad 9a 9c f7 e6 8c |W`.cNM?H.]......| +00000340 00 18 9c eb 34 ea f0 5c d5 77 3f af 81 a9 50 d9 |....4..\.w?...P.| +00000350 05 cf b9 bf 88 5c 70 29 24 61 6f d8 77 11 21 57 |.....\p)$ao.w.!W| +00000360 a0 4d e1 4b 8e 55 06 50 7f a2 30 c1 c2 b9 c6 00 |.M.K.U.P..0.....| +00000370 80 68 7c e4 1a bc a4 1e 16 b9 3e 4a 59 39 a9 54 |.h|.......>JY9.T| +00000380 6f c7 17 b2 f5 af b5 73 5b db cc 71 f2 1b aa dc |o......s[..q....| +00000390 9d 64 3c 0f 82 e6 da 1a 6b 96 19 e2 f0 15 b0 df |.d<.....k.......| +000003a0 8a 2d 96 09 63 52 f6 53 ef 12 d4 3b 35 b7 0b 43 |.-..cR.S...;5..C| +000003b0 2c 6e 58 4c c8 2f b8 55 84 89 c9 39 81 7a 7a 7d |,nXL./.U...9.zz}| +000003c0 88 68 db eb d7 81 aa 2e b2 25 ba 98 6c 46 b7 85 |.h.......%..lF..| +000003d0 8a 21 17 b9 36 23 c0 84 94 af 3b 9b 04 5d ec 31 |.!..6#....;..].1| +000003e0 f5 75 84 d8 77 d7 80 37 ae c3 5c 26 41 f6 72 af |.u..w..7..\&A.r.| +000003f0 88 16 03 01 00 04 0e 00 00 00 |..........| >>> Flow 3 (client to server) 00000000 16 03 01 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..| 00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.| 00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.| 00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I| 00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 01 00 01 |..h.A.Vk.Z......| -00000050 01 16 03 01 00 30 ca d1 1b 08 27 9b 44 e7 e9 b4 |.....0....'.D...| -00000060 90 16 4d 30 4e 65 5c 0d 47 ba 46 86 cf c9 80 e7 |..M0Ne\.G.F.....| -00000070 64 31 f5 a1 9e dc 39 15 d3 be 16 4f c7 90 b6 62 |d1....9....O...b| -00000080 5d 6d 7f 41 4e 3e |]m.AN>| +00000050 01 16 03 01 00 30 d2 5b 27 5a f5 64 49 31 d5 aa |.....0.['Z.dI1..| +00000060 a3 72 ae c9 af 0b aa 75 af ac f3 45 f4 e3 03 fa |.r.....u...E....| +00000070 e8 97 88 7b 51 a9 ae 61 40 c8 11 74 3e d8 9a b6 |...{Q..a@..t>...| +00000080 e7 6a 5e 71 84 7e |.j^q.~| >>> Flow 4 (server to client) -00000000 14 03 01 00 01 01 16 03 01 00 30 98 81 24 8e cd |..........0..$..| -00000010 b6 48 2f 80 de 8e 24 3c cd 02 67 80 34 97 d7 92 |.H/...$<..g.4...| -00000020 78 c2 44 3d 5d 05 eb 88 76 79 46 7a c3 fa ca 73 |x.D=]...vyFz...s| -00000030 45 82 ad c1 81 00 ca 40 c1 2f 13 |E......@./.| +00000000 14 03 01 00 01 01 16 03 01 00 30 8d 63 fc 58 2e |..........0.c.X.| +00000010 50 f7 60 2c 9f 5a 8e 58 29 6c a6 3a 8d 2b a7 2b |P.`,.Z.X)l.:.+.+| +00000020 1c 12 8a 53 3f d5 60 79 12 c3 78 e3 aa 50 15 45 |...S?.`y..x..P.E| +00000030 07 da 2d c7 a9 c3 45 07 48 00 78 |..-...E.H.x| >>> Flow 5 (client to server) -00000000 17 03 01 00 20 ee 19 59 67 67 a9 8b db 99 87 50 |.... ..Ygg.....P| -00000010 01 e2 02 c1 d5 6d 36 79 af aa ec 1b 80 0e b6 5e |.....m6y.......^| -00000020 5f fa 03 01 cc 17 03 01 00 20 ec e2 04 b7 3b a5 |_........ ....;.| -00000030 f2 e0 13 1f 17 48 e7 6e d3 eb f0 fa 36 ef 6e 2e |.....H.n....6.n.| -00000040 fb ea c8 39 c4 5f 4b 28 d4 50 15 03 01 00 20 c7 |...9._K(.P.... .| -00000050 45 ff fb c7 07 0c d8 0e 35 a3 c5 31 47 b7 03 0e |E.......5..1G...| -00000060 14 c8 29 fd 53 70 5f 15 ac d2 1c 4c 69 fb d6 |..).Sp_....Li..| +00000000 17 03 01 00 20 40 91 8d e6 95 2f 97 c8 0c 94 5c |.... @..../....\| +00000010 46 a7 d3 31 82 3d dc 7e 86 5b dd df 3f 3b 5b 9c |F..1.=.~.[..?;[.| +00000020 d5 0d 52 5a 53 17 03 01 00 20 1d 18 da 6b e8 66 |..RZS.... ...k.f| +00000030 ce 58 18 81 4b 69 8c f6 db 1a ee d0 78 fb f5 68 |.X..Ki......x..h| +00000040 2c 99 48 47 65 15 2a ae ff 4e 15 03 01 00 20 68 |,.HGe.*..N.... h| +00000050 aa 7f 75 33 45 7a 1a 33 18 35 5a 5b 14 b0 f6 83 |..u3Ez.3.5Z[....| +00000060 97 85 3f b2 dc 78 68 eb 43 ef 92 7f 38 bd f8 |..?..xh.C...8..| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv10-RSA-RC4 b/libgo/go/crypto/tls/testdata/Client-TLSv10-RSA-RC4 index 395d53bbabb..b5deaeb011a 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv10-RSA-RC4 +++ b/libgo/go/crypto/tls/testdata/Client-TLSv10-RSA-RC4 @@ -1,18 +1,19 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......| +00000000 16 03 01 00 81 01 00 00 7d 03 03 00 00 00 00 00 |........}.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| -00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1a c0 2f |.............../| -00000030 c0 2b c0 11 c0 07 c0 13 c0 09 c0 14 c0 0a 00 05 |.+..............| -00000040 00 2f 00 35 c0 12 00 0a 01 00 00 2e 00 05 00 05 |./.5............| -00000050 01 00 00 00 00 00 0a 00 08 00 06 00 17 00 18 00 |................| -00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................| -00000070 03 02 01 02 03 ff 01 00 01 00 |..........| +00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1e c0 2f |.............../| +00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........| +00000040 c0 0a 00 05 00 2f 00 35 c0 12 00 0a 01 00 00 36 |...../.5.......6| +00000050 00 05 00 05 01 00 00 00 00 00 0a 00 08 00 06 00 |................| +00000060 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| +00000070 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| +00000080 01 00 00 12 00 00 |......| >>> Flow 2 (server to client) -00000000 16 03 01 00 51 02 00 00 4d 03 01 53 04 f1 02 76 |....Q...M..S...v| -00000010 e8 45 7f 57 f3 42 4b 33 0b 06 fa a6 fa c4 3d 84 |.E.W.BK3......=.| -00000020 5a 45 dc 93 41 a5 8d 79 6e 8f 11 20 e7 c6 29 2b |ZE..A..yn.. ..)+| -00000030 ff 4a 6e 63 67 a6 10 cb 49 19 46 1e 5e 0a d5 70 |.Jncg...I.F.^..p| -00000040 96 88 9a 32 48 ef c3 4a 45 4c 6d e0 00 05 00 00 |...2H..JELm.....| +00000000 16 03 01 00 51 02 00 00 4d 03 01 a9 b0 bf 24 3f |....Q...M.....$?| +00000010 98 c6 0f 83 23 2b b6 e4 3f d5 5b 10 9a 6f b8 63 |....#+..?.[..o.c| +00000020 4c 3c d6 4d 05 c0 08 85 f7 72 72 20 ab 85 8c ff |L<.M.....rr ....| +00000030 f7 bb 95 ab 69 37 3d b6 79 cb 46 ad 4e 22 e7 c6 |....i7=.y.F.N"..| +00000040 a5 9b 72 92 32 ff a5 f7 ed dc 30 41 00 05 00 00 |..r.2.....0A....| 00000050 05 ff 01 00 01 00 16 03 01 02 be 0b 00 02 ba 00 |................| 00000060 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......| 00000070 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..| @@ -69,15 +70,15 @@ 00000060 e6 bd 77 82 6f 23 b6 e0 bd a2 92 b7 3a ac e8 56 |..w.o#......:..V| 00000070 f1 af 54 5e 46 87 e9 3b 33 e7 b8 28 b7 d6 c8 90 |..T^F..;3..(....| 00000080 35 d4 1c 43 d1 30 6f 55 4e 0a 70 14 03 01 00 01 |5..C.0oUN.p.....| -00000090 01 16 03 01 00 24 cd c0 68 dc 2e 69 cc c7 5b c5 |.....$..h..i..[.| -000000a0 3f bd 40 cf a0 0f 41 34 ce 16 37 10 26 c8 3f d1 |?.@...A4..7.&.?.| -000000b0 46 3b ad 7b b0 31 f3 c5 36 e7 |F;.{.1..6.| +00000090 01 16 03 01 00 24 4d 1d d7 8c d6 c7 65 a6 ce af |.....$M.....e...| +000000a0 e7 59 0d 7e dc d9 96 1c ed 9c 57 94 84 b8 3f b5 |.Y.~......W...?.| +000000b0 34 e1 61 a5 61 f3 5d 09 bc ff |4.a.a.]...| >>> Flow 4 (server to client) -00000000 14 03 01 00 01 01 16 03 01 00 24 ea 77 6f 3c 42 |..........$.wo....]| +00000000 14 03 01 00 01 01 16 03 01 00 24 13 81 89 61 5c |..........$...a\| +00000010 fb 0a 9c a1 4b db 94 6b 8b 41 6e 63 d6 aa db 88 |....K..k.Anc....| +00000020 03 b7 b5 19 b8 12 cf 5e 17 54 79 2f 03 91 7e |.......^.Ty/..~| >>> Flow 5 (client to server) -00000000 17 03 01 00 1a 9e ae ca 55 df c4 d9 47 04 55 dd |........U...G.U.| -00000010 3b 33 e1 a6 16 6f a1 94 b1 9b 4d 0d cb 6c 3b 15 |;3...o....M..l;.| -00000020 03 01 00 16 92 5d 76 07 e9 b7 31 29 09 c5 b1 09 |.....]v...1)....| -00000030 2d 64 3d 85 8d f1 d1 40 54 b8 |-d=....@T.| +00000000 17 03 01 00 1a b3 2b da ce 45 ec b2 9d 3b 18 d9 |......+..E...;..| +00000010 7a cb 99 ea ff 4d 91 b5 48 df 6f 8b 2f 85 c7 15 |z....M..H.o./...| +00000020 03 01 00 16 19 1c 72 74 36 cf 22 0f a0 a7 18 96 |......rt6.".....| +00000030 3a 67 cb 22 16 f1 a8 7b 57 37 |:g."...{W7| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES b/libgo/go/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES index 9f941f8ef18..a4a29306cb7 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES +++ b/libgo/go/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES @@ -1,18 +1,19 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......| +00000000 16 03 01 00 81 01 00 00 7d 03 03 00 00 00 00 00 |........}.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| -00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1a c0 2f |.............../| -00000030 c0 2b c0 11 c0 07 c0 13 c0 09 c0 14 c0 0a 00 05 |.+..............| -00000040 00 2f 00 35 c0 12 00 0a 01 00 00 2e 00 05 00 05 |./.5............| -00000050 01 00 00 00 00 00 0a 00 08 00 06 00 17 00 18 00 |................| -00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................| -00000070 03 02 01 02 03 ff 01 00 01 00 |..........| +00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1e c0 2f |.............../| +00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........| +00000040 c0 0a 00 05 00 2f 00 35 c0 12 00 0a 01 00 00 36 |...../.5.......6| +00000050 00 05 00 05 01 00 00 00 00 00 0a 00 08 00 06 00 |................| +00000060 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| +00000070 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| +00000080 01 00 00 12 00 00 |......| >>> Flow 2 (server to client) -00000000 16 03 02 00 59 02 00 00 55 03 02 53 04 f1 02 1c |....Y...U..S....| -00000010 d1 1c 6a 5f 7a 5c 26 69 92 cd ee c3 57 ed 96 90 |..j_z\&i....W...| -00000020 e3 c5 f1 ee 8b ee 99 5f 46 2c e6 20 c8 50 6a a4 |......._F,. .Pj.| -00000030 4b 93 e6 da ba 6d d4 87 f6 75 a8 9d 44 db b5 43 |K....m...u..D..C| -00000040 df 12 57 de a4 f1 bc fb b8 7a 3f 6a c0 09 00 00 |..W......z?j....| +00000000 16 03 02 00 59 02 00 00 55 03 02 5a 52 92 23 05 |....Y...U..ZR.#.| +00000010 58 68 b2 1e 77 a2 a8 16 e9 88 85 ea 38 b3 63 c2 |Xh..w.......8.c.| +00000020 40 f8 de 37 3c d4 b9 51 11 2d d1 20 12 fd 95 b3 |@..7<..Q.-. ....| +00000030 2a 54 40 c0 23 3a 4e 4e f6 7b f8 77 04 6e e7 d7 |*T@.#:NN.{.w.n..| +00000040 3b 9a 45 32 e0 af df aa ff bf 78 8b c0 09 00 00 |;.E2......x.....| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 02 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..| 00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....| @@ -47,21 +48,21 @@ 00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....| 00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.| 00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....| -00000270 2a 16 03 02 00 d4 0c 00 00 d0 03 00 17 41 04 7b |*............A.{| -00000280 c4 00 37 35 51 de c3 f2 a4 95 2c 19 21 3e a6 94 |..75Q.....,.!>..| -00000290 7b fd 04 d7 b7 1c 56 e6 af 3c ee 36 cb 55 e6 f0 |{.....V..<.6.U..| -000002a0 e6 24 34 6b 8a 02 66 71 f9 e2 f5 a6 c9 d7 6c dc |.$4k..fq......l.| -000002b0 65 59 ff 1c c9 ec a9 8b 07 d6 52 2c 01 3c c3 00 |eY........R,.<..| -000002c0 89 30 81 86 02 41 74 89 1a 31 72 e6 8b c0 4a ce |.0...At..1r...J.| -000002d0 8f 5a 49 a7 52 2d 6d b9 8b 50 17 62 2a 99 d6 3b |.ZI.R-m..P.b*..;| -000002e0 02 85 41 4d 34 53 b5 09 bd e3 ac 16 c1 9b e9 83 |..AM4S..........| -000002f0 cc 83 e3 9c 23 34 67 71 72 d4 05 a2 34 f7 08 29 |....#4gqr...4..)| -00000300 62 43 2e cc bc 08 01 02 41 59 de 5a d0 dd d7 6b |bC......AY.Z...k| -00000310 db 9c 35 29 79 f8 96 91 56 74 1f 18 7b ee 25 83 |..5)y...Vt..{.%.| -00000320 f2 37 0e 77 ab 38 fb 5e 04 0b 09 d9 b4 1f 3f be |.7.w.8.^......?.| -00000330 2e e3 60 e3 96 f3 29 c1 6d 8f 56 1b fd 62 14 48 |..`...).m.V..b.H| -00000340 e3 d9 2a ea 2f be 93 d0 8b 31 16 03 02 00 04 0e |..*./....1......| -00000350 00 00 00 |...| +00000270 2a 16 03 02 00 d5 0c 00 00 d1 03 00 17 41 04 c3 |*............A..| +00000280 55 86 65 95 83 02 4b 69 6e 95 f4 52 46 83 21 86 |U.e...Kin..RF.!.| +00000290 9e 99 cf 81 d9 b8 20 7a 87 b3 07 48 14 04 20 d9 |...... z...H.. .| +000002a0 6c 2e 22 5a b5 b4 ef de 15 b3 08 ef 1e 18 ea 67 |l."Z...........g| +000002b0 eb 45 fd e1 27 43 ed 41 ea 05 7e f3 f9 ee 23 00 |.E..'C.A..~...#.| +000002c0 8a 30 81 87 02 42 00 b0 9c 06 85 83 b2 bf 42 22 |.0...B........B"| +000002d0 6e 57 7a 31 fe a9 d9 28 be 0a a9 80 49 a2 14 c1 |nWz1...(....I...| +000002e0 a9 99 76 b7 f9 76 d0 3c d3 0c c7 42 34 d7 94 a9 |..v..v.<...B4...| +000002f0 15 66 7e 6b 83 6e b2 b4 5b 22 c9 4e a0 96 db 2b |.f~k.n..[".N...+| +00000300 ad 77 33 1e 4a 5c 2f 2e 02 41 26 0c 1a 5a b4 07 |.w3.J\/..A&..Z..| +00000310 95 99 ec 0b 5b 2e bb db 0e d5 26 c4 b3 eb c2 30 |....[.....&....0| +00000320 b0 7b c1 07 97 a0 99 3f db 4e b0 c4 b8 bb 5e be |.{.....?.N....^.| +00000330 2a e4 b3 a4 5c ad d1 d7 7a 2d fb ae 73 ee 0c 1e |*...\...z-..s...| +00000340 3b 64 e1 74 14 bc c0 1e 8b f3 26 16 03 02 00 04 |;d.t......&.....| +00000350 0e 00 00 00 |....| >>> Flow 3 (client to server) 00000000 16 03 02 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..| 00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.| @@ -69,21 +70,21 @@ 00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I| 00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 02 00 01 |..h.A.Vk.Z......| 00000050 01 16 03 02 00 40 00 00 00 00 00 00 00 00 00 00 |.....@..........| -00000060 00 00 00 00 00 00 b6 98 a2 a9 48 34 12 6b 0a 94 |..........H4.k..| -00000070 89 fc 38 04 63 5a 6f 63 36 3e d9 35 12 64 8c 28 |..8.cZoc6>.5.d.(| -00000080 99 a6 cf 2e 57 e3 14 6d 0a 8a ab f0 a6 58 37 7c |....W..m.....X7|| -00000090 96 04 d3 71 bc d4 |...q..| +00000060 00 00 00 00 00 00 33 07 8a af e1 94 ef f9 08 3a |......3........:| +00000070 33 5f b3 e6 42 07 85 af 40 e2 8b 34 53 62 1a 10 |3_..B...@..4Sb..| +00000080 bb 08 7e 75 d4 21 12 2d 54 87 33 1c 4e 13 27 72 |..~u.!.-T.3.N.'r| +00000090 3f 9e 9f cc de 47 |?....G| >>> Flow 4 (server to client) -00000000 14 03 02 00 01 01 16 03 02 00 40 c5 01 c9 0a b0 |..........@.....| -00000010 d8 ca 5e c1 19 dc 37 6c 2e a0 b3 11 a8 87 65 5a |..^...7l......eZ| -00000020 09 41 b9 fe 53 c4 c9 76 97 6d 7f ac c0 be d2 07 |.A..S..v.m......| -00000030 84 e5 5b 78 37 34 ee da 3b cb 3e 82 52 79 91 44 |..[x74..;.>.Ry.D| -00000040 b4 e4 1c ec 3a c0 c0 9d cd ff 13 |....:......| +00000000 14 03 02 00 01 01 16 03 02 00 40 4f 47 0d 43 54 |..........@OG.CT| +00000010 50 69 3a c8 21 a6 6e 28 78 cc 01 b4 5d eb f7 2b |Pi:.!.n(x...]..+| +00000020 8b 7e 26 6e cf 56 98 65 ad bf 0f a0 b4 67 13 70 |.~&n.V.e.....g.p| +00000030 de b5 b5 91 df d6 df 8c 53 c6 54 3d 5d 98 e4 25 |........S.T=]..%| +00000040 47 a0 0f 91 c7 08 96 17 48 bd 0f |G.......H..| >>> Flow 5 (client to server) 00000000 17 03 02 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........| -00000010 00 00 00 00 00 46 60 13 39 2b 2f 72 95 ed 0e aa |.....F`.9+/r....| -00000020 69 6e b4 64 3e 83 43 d0 f9 7f 37 7c 1d b9 ce 11 |in.d>.C...7|....| -00000030 d9 41 66 60 6d 15 03 02 00 30 00 00 00 00 00 00 |.Af`m....0......| -00000040 00 00 00 00 00 00 00 00 00 00 b1 26 d0 5d 08 98 |...........&.]..| -00000050 eb 28 42 74 31 58 42 95 c5 ad 1a 92 0a f5 5f ed |.(Bt1XB......._.| -00000060 45 98 e0 90 e5 a3 b6 8b 8d 18 |E.........| +00000010 00 00 00 00 00 4e fe 12 d7 4b d7 3f 86 5a 2c f6 |.....N...K.?.Z,.| +00000020 86 03 2a bd 1a 98 d7 bb 9f 59 6c 6d 4d 57 b0 50 |..*......YlmMW.P| +00000030 d6 97 7e d4 b6 15 03 02 00 30 00 00 00 00 00 00 |..~......0......| +00000040 00 00 00 00 00 00 00 00 00 00 65 8b b5 ae 86 90 |..........e.....| +00000050 00 4e 1e 3f bc ac ed 49 f4 5e 73 49 e6 d8 37 83 |.N.?...I.^sI..7.| +00000060 cf 4f e5 7b 5e c9 1d c8 c9 dc |.O.{^.....| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES b/libgo/go/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES index fc723396a4f..103f1d8a11d 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES +++ b/libgo/go/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES @@ -1,18 +1,19 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......| +00000000 16 03 01 00 81 01 00 00 7d 03 03 00 00 00 00 00 |........}.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| -00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1a c0 2f |.............../| -00000030 c0 2b c0 11 c0 07 c0 13 c0 09 c0 14 c0 0a 00 05 |.+..............| -00000040 00 2f 00 35 c0 12 00 0a 01 00 00 2e 00 05 00 05 |./.5............| -00000050 01 00 00 00 00 00 0a 00 08 00 06 00 17 00 18 00 |................| -00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................| -00000070 03 02 01 02 03 ff 01 00 01 00 |..........| +00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1e c0 2f |.............../| +00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........| +00000040 c0 0a 00 05 00 2f 00 35 c0 12 00 0a 01 00 00 36 |...../.5.......6| +00000050 00 05 00 05 01 00 00 00 00 00 0a 00 08 00 06 00 |................| +00000060 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| +00000070 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| +00000080 01 00 00 12 00 00 |......| >>> Flow 2 (server to client) -00000000 16 03 02 00 59 02 00 00 55 03 02 53 04 f1 02 fe |....Y...U..S....| -00000010 17 8b 79 ad 93 2e d3 89 66 9b 5d 9b b4 03 3e ba |..y.....f.]...>.| -00000020 65 2a f1 55 f9 3c 33 de 2c a7 47 20 fa 4f 82 11 |e*.U.<3.,.G .O..| -00000030 96 81 d0 70 2e 65 b3 68 2e 3a 6d d7 6c 74 22 33 |...p.e.h.:m.lt"3| -00000040 d4 ae 6c aa c8 f0 c7 20 8b 10 21 e7 c0 13 00 00 |..l.... ..!.....| +00000000 16 03 02 00 59 02 00 00 55 03 02 e3 ed 49 27 a3 |....Y...U....I'.| +00000010 28 c5 8c 30 27 c2 ed 57 9b f7 37 a1 6d 2b 88 c2 |(..0'..W..7.m+..| +00000020 df a7 2d 01 01 00 9a 09 da c2 1f 20 ee 33 87 03 |..-........ .3..| +00000030 28 93 1c 16 99 5b b1 e0 bf 87 e8 77 4a 72 c9 92 |(....[.....wJr..| +00000040 8a bc b2 3e 24 e1 f6 e8 f4 3f a2 24 c0 13 00 00 |...>$....?.$....| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 02 02 be 0b 00 02 ba 00 02 b7 00 02 b4 30 82 02 |.............0..| 00000070 b0 30 82 02 19 a0 03 02 01 02 02 09 00 85 b0 bb |.0..............| @@ -58,20 +59,20 @@ 000002f0 5f 33 c4 b6 d8 c9 75 90 96 8c 0f 52 98 b5 cd 98 |_3....u....R....| 00000300 1f 89 20 5f f2 a0 1c a3 1b 96 94 dd a9 fd 57 e9 |.. _..........W.| 00000310 70 e8 26 6d 71 99 9b 26 6e 38 50 29 6c 90 a7 bd |p.&mq..&n8P)l...| -00000320 d9 16 03 02 00 cb 0c 00 00 c7 03 00 17 41 04 26 |.............A.&| -00000330 56 18 02 e5 66 d4 aa 24 7e ae 39 e5 ca 78 6c c1 |V...f..$~.9..xl.| -00000340 90 02 c3 c4 ad 79 2c 47 a8 bf 54 e2 8a 22 b6 ef |.....y,G..T.."..| -00000350 99 d4 7a 7f 8f 78 6a 78 4e 14 2a 16 0d bb 54 38 |..z..xjxN.*...T8| -00000360 59 1f 7a 53 1b c7 73 10 89 4b de c3 66 39 7a 00 |Y.zS..s..K..f9z.| -00000370 80 3a 88 38 c8 15 07 ab 2f 0f 0d cb 19 07 84 ac |.:.8..../.......| -00000380 24 fd 8b d2 9d 05 45 c6 11 c3 d6 84 58 95 5a 08 |$.....E.....X.Z.| -00000390 b9 a4 2c c0 41 4e 34 e0 b2 24 98 94 b7 67 27 50 |..,.AN4..$...g'P| -000003a0 ba 82 35 28 a9 bf 16 ee e3 7b 49 9c 4c 81 80 69 |..5(.....{I.L..i| -000003b0 d7 aa ed 46 ea 9a 68 c4 97 b7 11 d4 35 91 74 5e |...F..h.....5.t^| -000003c0 54 10 34 83 cd c4 06 18 49 7d 7a 28 c9 53 06 73 |T.4.....I}z(.S.s| -000003d0 00 7b 04 b6 d8 36 a7 4b 67 7f 81 30 94 de 40 4d |.{...6.Kg..0..@M| -000003e0 18 f8 c4 b7 02 00 44 8e bc 72 06 24 53 15 74 72 |......D..r.$S.tr| -000003f0 8d 16 03 02 00 04 0e 00 00 00 |..........| +00000320 d9 16 03 02 00 cb 0c 00 00 c7 03 00 17 41 04 f7 |.............A..| +00000330 75 c1 b9 58 a0 7d 50 48 e9 85 79 db 89 76 4c d7 |u..X.}PH..y..vL.| +00000340 84 5b 94 9a 15 d8 92 32 74 d2 3e ce 76 5a bd 0e |.[.....2t.>.vZ..| +00000350 24 e7 a6 d0 77 5d 8e 3d 9f 94 7a ea 15 46 3c 5c |$...w].=..z..F<\| +00000360 61 28 76 4a ff 81 97 2b 3a 0c b7 aa b4 0e cb 00 |a(vJ...+:.......| +00000370 80 19 00 a8 fe 0a ea 35 30 51 a3 77 37 08 68 10 |.......50Q.w7.h.| +00000380 5a e9 07 2d 83 67 77 4c 3a 25 14 1c 5b c1 2e 80 |Z..-.gwL:%..[...| +00000390 30 6d ba 26 c1 f9 c6 3e fc 55 34 8c d2 9f 2b a6 |0m.&...>.U4...+.| +000003a0 46 0c 9d 58 2c 9c 2b ce 6f 03 d7 49 4e df 21 ce |F..X,.+.o..IN.!.| +000003b0 3f 8b 19 fe 3e 71 23 51 c3 ec 30 c8 3e 3c 3c 50 |?...>q#Q..0.><>> Flow 3 (client to server) 00000000 16 03 02 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..| 00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.| @@ -79,21 +80,21 @@ 00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I| 00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 02 00 01 |..h.A.Vk.Z......| 00000050 01 16 03 02 00 40 00 00 00 00 00 00 00 00 00 00 |.....@..........| -00000060 00 00 00 00 00 00 8a 87 81 38 35 c0 4c bb f8 12 |.........85.L...| -00000070 fa 75 04 cd 1e 3a 61 96 93 c8 fb 07 d1 6d b4 55 |.u...:a......m.U| -00000080 0f b5 0f 07 35 0a 96 ce 5c 6f 24 62 d3 68 e4 b0 |....5...\o$b.h..| -00000090 5d be 81 37 c2 9c |]..7..| +00000060 00 00 00 00 00 00 1e 0b cd 40 fa 0f ed fa 55 74 |.........@....Ut| +00000070 4e ad 10 d1 b5 e1 41 8c c0 93 81 38 f3 83 f1 37 |N.....A....8...7| +00000080 6a d4 6c ea ba 5b 9e 38 d3 c1 bb 41 45 fb f0 48 |j.l..[.8...AE..H| +00000090 c1 06 31 64 e0 65 |..1d.e| >>> Flow 4 (server to client) -00000000 14 03 02 00 01 01 16 03 02 00 40 66 36 8d f8 8c |..........@f6...| -00000010 7f db 38 e8 39 df f8 2f cb 88 9c 14 d9 89 10 b4 |..8.9../........| -00000020 be 59 88 d7 f3 73 62 af a3 42 66 6e 74 38 64 9f |.Y...sb..Bfnt8d.| -00000030 16 79 09 d7 14 7e 91 8a 70 73 63 28 30 58 fe cc |.y...~..psc(0X..| -00000040 42 45 d6 37 fb 9e 8c c1 01 af 34 |BE.7......4| +00000000 14 03 02 00 01 01 16 03 02 00 40 17 d1 79 f8 e0 |..........@..y..| +00000010 d4 40 15 85 df 4d a6 d5 60 90 1f d6 52 58 e7 ae |.@...M..`...RX..| +00000020 05 eb a2 ea ed c9 be ae b5 54 39 de 05 66 27 67 |.........T9..f'g| +00000030 59 07 03 e7 10 f9 3f da d8 85 8b 2f 7b 33 9f f5 |Y.....?..../{3..| +00000040 43 50 b9 9c 6e dd 01 ae d8 c9 1d |CP..n......| >>> Flow 5 (client to server) 00000000 17 03 02 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........| -00000010 00 00 00 00 00 31 0b e3 9d 2a 05 83 19 7d 10 36 |.....1...*...}.6| -00000020 23 dc da fe 00 ab d3 aa 8f ce 28 5f 08 fd b7 59 |#.........(_...Y| -00000030 1e 00 2e 25 5a 15 03 02 00 30 00 00 00 00 00 00 |...%Z....0......| -00000040 00 00 00 00 00 00 00 00 00 00 10 91 fd fa 59 07 |..............Y.| -00000050 df 2c 92 25 15 7b 7c 83 44 89 0d 4f 65 43 99 2e |.,.%.{|.D..OeC..| -00000060 41 5d 51 c9 09 89 ed 02 08 bc |A]Q.......| +00000010 00 00 00 00 00 65 81 63 71 55 1c 46 8a 60 46 d9 |.....e.cqU.F.`F.| +00000020 7d 71 a2 62 b8 a8 3b 06 3d a2 f4 53 a4 46 a8 9e |}q.b..;.=..S.F..| +00000030 b7 89 8a 42 ce 15 03 02 00 30 00 00 00 00 00 00 |...B.....0......| +00000040 00 00 00 00 00 00 00 00 00 00 7a 78 a4 e7 2f 40 |..........zx../@| +00000050 df 42 9b 76 7a 45 0a 86 40 af 3c 40 c6 69 ba e1 |.B.vzE..@.<@.i..| +00000060 23 82 fa 44 fd 73 fc 5b f7 b9 |#..D.s.[..| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv11-RSA-RC4 b/libgo/go/crypto/tls/testdata/Client-TLSv11-RSA-RC4 index f7be3f7e93a..729391f68ca 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv11-RSA-RC4 +++ b/libgo/go/crypto/tls/testdata/Client-TLSv11-RSA-RC4 @@ -1,18 +1,19 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......| +00000000 16 03 01 00 81 01 00 00 7d 03 03 00 00 00 00 00 |........}.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| -00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1a c0 2f |.............../| -00000030 c0 2b c0 11 c0 07 c0 13 c0 09 c0 14 c0 0a 00 05 |.+..............| -00000040 00 2f 00 35 c0 12 00 0a 01 00 00 2e 00 05 00 05 |./.5............| -00000050 01 00 00 00 00 00 0a 00 08 00 06 00 17 00 18 00 |................| -00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................| -00000070 03 02 01 02 03 ff 01 00 01 00 |..........| +00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1e c0 2f |.............../| +00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........| +00000040 c0 0a 00 05 00 2f 00 35 c0 12 00 0a 01 00 00 36 |...../.5.......6| +00000050 00 05 00 05 01 00 00 00 00 00 0a 00 08 00 06 00 |................| +00000060 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| +00000070 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| +00000080 01 00 00 12 00 00 |......| >>> Flow 2 (server to client) -00000000 16 03 02 00 51 02 00 00 4d 03 02 53 04 f1 02 d4 |....Q...M..S....| -00000010 69 65 aa 96 3d 42 96 eb 9e 7d 8a 18 af 4c 7c 5d |ie..=B...}...L|]| -00000020 fb 97 5f da 94 62 13 69 1f 66 06 20 aa 52 e3 08 |.._..b.i.f. .R..| -00000030 35 0a 87 d5 ef 93 49 ab 1a 74 dd 90 bd 69 70 d1 |5.....I..t...ip.| -00000040 e9 f1 44 17 3a dc 33 98 f5 e5 ab 93 00 05 00 00 |..D.:.3.........| +00000000 16 03 02 00 51 02 00 00 4d 03 02 7e 38 ae 3c 50 |....Q...M..~8.>> Flow 4 (server to client) -00000000 14 03 02 00 01 01 16 03 02 00 24 81 72 75 80 d4 |..........$.ru..| -00000010 1b 1a 32 00 89 bf 9e 79 30 b9 6b 67 e0 8e c7 eb |..2....y0.kg....| -00000020 73 f2 e4 93 51 65 9b 5f 91 b1 b4 b1 f7 44 76 |s...Qe._.....Dv| +00000000 14 03 02 00 01 01 16 03 02 00 24 a3 f3 22 a8 32 |..........$..".2| +00000010 63 c3 88 5c 0f fb 2d 47 21 0d 62 e2 db aa ed ae |c..\..-G!.b.....| +00000020 b6 5f e3 c8 98 fc 91 5e 04 83 cf c3 21 17 ce |._.....^....!..| >>> Flow 5 (client to server) -00000000 17 03 02 00 1a b2 91 39 63 c0 38 3c 4d 25 fd 14 |.......9c.8>> Flow 1 (client to server) -00000000 16 03 01 00 8d 01 00 00 89 03 03 00 00 00 00 00 |................| +00000000 16 03 01 00 99 01 00 00 95 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| -00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1a c0 2f |.............../| -00000030 c0 2b c0 11 c0 07 c0 13 c0 09 c0 14 c0 0a 00 05 |.+..............| -00000040 00 2f 00 35 c0 12 00 0a 01 00 00 46 33 74 00 00 |./.5.......F3t..| -00000050 00 05 00 05 01 00 00 00 00 00 0a 00 08 00 06 00 |................| -00000060 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0a 00 |................| -00000070 08 04 01 04 03 02 01 02 03 ff 01 00 01 00 00 10 |................| -00000080 00 10 00 0e 06 70 72 6f 74 6f 32 06 70 72 6f 74 |.....proto2.prot| -00000090 6f 31 |o1| +00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1e c0 2f |.............../| +00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........| +00000040 c0 0a 00 05 00 2f 00 35 c0 12 00 0a 01 00 00 4e |...../.5.......N| +00000050 33 74 00 00 00 05 00 05 01 00 00 00 00 00 0a 00 |3t..............| +00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................| +00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................| +00000080 03 ff 01 00 01 00 00 10 00 10 00 0e 06 70 72 6f |.............pro| +00000090 74 6f 32 06 70 72 6f 74 6f 31 00 12 00 00 |to2.proto1....| >>> Flow 2 (server to client) -00000000 16 03 03 00 66 02 00 00 62 03 03 77 a9 7d 9c 4b |....f...b..w.}.K| -00000010 69 65 aa dc 95 cb 78 08 3d d2 1a 0a 45 69 23 73 |ie....x.=...Ei#s| -00000020 4f 41 4f 24 12 2e 57 47 b7 53 64 20 82 9a f8 e7 |OAO$..WG.Sd ....| -00000030 79 f8 13 2c 9d cd b5 cb cb 9a 95 56 0e e9 cb a8 |y..,.......V....| -00000040 e4 a2 8a d6 bc dc fa 25 b3 57 cc cf c0 2f 00 00 |.......%.W.../..| +00000000 16 03 03 00 66 02 00 00 62 03 03 56 83 34 0f 9e |....f...b..V.4..| +00000010 dd 02 1c 4f 4f 09 d0 2c df e6 c1 d2 4a c0 6a e7 |...OO..,....J.j.| +00000020 1e 65 51 c2 42 01 05 70 4a 6c 97 20 0f a8 fb d8 |.eQ.B..pJl. ....| +00000030 2f 0f 75 21 17 f8 dd 63 28 4a 18 f6 b1 e5 6f 7c |/.u!...c(J....o|| +00000040 1d 09 d4 13 bf 66 3a bd c5 48 14 fc c0 2f 00 00 |.....f:..H.../..| 00000050 1a ff 01 00 01 00 00 0b 00 04 03 00 01 02 00 10 |................| 00000060 00 09 00 07 06 70 72 6f 74 6f 31 16 03 03 02 be |.....proto1.....| 00000070 0b 00 02 ba 00 02 b7 00 02 b4 30 82 02 b0 30 82 |..........0...0.| @@ -61,19 +61,19 @@ 00000300 b6 d8 c9 75 90 96 8c 0f 52 98 b5 cd 98 1f 89 20 |...u....R...... | 00000310 5f f2 a0 1c a3 1b 96 94 dd a9 fd 57 e9 70 e8 26 |_..........W.p.&| 00000320 6d 71 99 9b 26 6e 38 50 29 6c 90 a7 bd d9 16 03 |mq..&n8P)l......| -00000330 03 00 cd 0c 00 00 c9 03 00 17 41 04 1b 42 c3 ae |..........A..B..| -00000340 44 19 d3 84 7c 6c 98 cb b9 22 a2 67 63 95 aa cc |D...|l...".gc...| -00000350 bd e4 1e f8 08 e6 60 f3 bc 83 9f 81 da 9c 1c 8c |......`.........| -00000360 ff 6f f4 3e 1e e5 3b f6 49 61 f9 70 43 7f c1 69 |.o.>..;.Ia.pC..i| -00000370 de 73 98 4b bd 5c c3 78 24 18 a8 ec 04 01 00 80 |.s.K.\.x$.......| -00000380 70 d2 5b e1 39 cf 4d 54 de d2 74 4e 5e a8 b3 ca |p.[.9.MT..tN^...| -00000390 e1 f2 4e 76 3c 77 8b ef f7 d1 df b9 ad c1 70 39 |..Nv.....R..q..| +00000370 4e a6 88 0e 54 35 e0 8b 50 91 e1 c4 04 01 00 80 |N...T5..P.......| +00000380 51 eb f8 d6 52 ba f5 b5 0a 22 5f 91 fe f7 ee 43 |Q...R...."_....C| +00000390 f8 af 52 b6 27 2c fc 14 e2 fb 41 61 ff 7c b9 be |..R.',....Aa.|..| +000003a0 f9 78 be dc 18 32 8c 4d ef 46 c0 5a a7 91 6a 1b |.x...2.M.F.Z..j.| +000003b0 47 78 46 39 47 81 8a 2d b4 cb fd bb 44 3e a7 b7 |GxF9G..-....D>..| +000003c0 cc 4e df 17 7b 2b 38 49 fa 9d 9f 4e cd ed f2 16 |.N..{+8I...N....| +000003d0 03 d9 68 cf c9 5a 08 32 f8 ed 02 30 54 61 f6 c0 |..h..Z.2...0Ta..| +000003e0 f6 78 bc ad 04 9c 8e 90 7d 3d f5 35 86 aa 6e e9 |.x......}=.5..n.| +000003f0 a2 9a d3 86 27 9f 2d 6e ea 6e ad 82 0e aa ef 97 |....'.-n.n......| 00000400 16 03 03 00 04 0e 00 00 00 |.........| >>> Flow 3 (client to server) 00000000 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..| @@ -81,17 +81,17 @@ 00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.| 00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I| 00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 03 00 01 |..h.A.Vk.Z......| -00000050 01 16 03 03 00 28 00 00 00 00 00 00 00 00 35 9d |.....(........5.| -00000060 92 e8 bf df 7f a7 77 1b cf 03 2a bf e2 6c 62 2b |......w...*..lb+| -00000070 26 f0 fb 93 d3 df fd 55 84 d3 ed 88 31 cb |&......U....1.| +00000050 01 16 03 03 00 28 00 00 00 00 00 00 00 00 47 18 |.....(........G.| +00000060 39 03 93 d9 5b 27 29 70 52 68 15 79 f2 60 e6 58 |9...[')pRh.y.`.X| +00000070 d9 98 cd ce a1 8f 4d ee 2c f0 34 9f fa 73 |......M.,.4..s| >>> Flow 4 (server to client) -00000000 14 03 03 00 01 01 16 03 03 00 28 c8 c0 78 09 73 |..........(..x.s| -00000010 58 41 73 66 88 cf db f3 fe c6 57 ab 45 be 2e d8 |XAsf......W.E...| -00000020 4e e5 ff 42 57 13 74 d2 cc c2 62 07 39 8b 06 46 |N..BW.t...b.9..F| -00000030 1d 8f 88 |...| +00000000 14 03 03 00 01 01 16 03 03 00 28 39 76 15 70 f1 |..........(9v.p.| +00000010 73 c9 9a 1e 76 40 bc de de 49 be 3e 10 4d 6a 42 |s...v@...I.>.MjB| +00000020 1b 9b bd 07 6b 19 ff f9 2c 19 3c c8 e7 06 fa c8 |....k...,.<.....| +00000030 3d 52 b4 |=R.| >>> Flow 5 (client to server) -00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 10 c3 5f |..............._| -00000010 3f c8 92 6c 7a a7 23 05 f3 d8 31 20 01 52 f1 99 |?..lz.#...1 .R..| -00000020 33 c1 2a 15 03 03 00 1a 00 00 00 00 00 00 00 02 |3.*.............| -00000030 cc ef eb 78 e4 e1 9d 90 05 6d 95 ac f2 49 ba 8e |...x.....m...I..| -00000040 6b 8d |k.| +00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 14 96 ec |................| +00000010 f4 bb ae 45 81 0c 39 10 e2 3a 91 51 04 2c 01 a8 |...E..9..:.Q.,..| +00000020 8b a3 25 15 03 03 00 1a 00 00 00 00 00 00 00 02 |..%.............| +00000030 fe 1a 53 01 17 ad a1 30 0a 73 17 9f 39 b4 30 ac |..S....0.s..9.0.| +00000040 91 ee |..| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ALPN-NoMatch b/libgo/go/crypto/tls/testdata/Client-TLSv12-ALPN-NoMatch index f24a70cc828..a22ffaeb499 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv12-ALPN-NoMatch +++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ALPN-NoMatch @@ -1,19 +1,20 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 86 01 00 00 82 03 03 00 00 00 00 00 |................| +00000000 16 03 01 00 92 01 00 00 8e 03 03 00 00 00 00 00 |................| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| -00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1a c0 2f |.............../| -00000030 c0 2b c0 11 c0 07 c0 13 c0 09 c0 14 c0 0a 00 05 |.+..............| -00000040 00 2f 00 35 c0 12 00 0a 01 00 00 3f 33 74 00 00 |./.5.......?3t..| -00000050 00 05 00 05 01 00 00 00 00 00 0a 00 08 00 06 00 |................| -00000060 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0a 00 |................| -00000070 08 04 01 04 03 02 01 02 03 ff 01 00 01 00 00 10 |................| -00000080 00 09 00 07 06 70 72 6f 74 6f 33 |.....proto3| +00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1e c0 2f |.............../| +00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........| +00000040 c0 0a 00 05 00 2f 00 35 c0 12 00 0a 01 00 00 47 |...../.5.......G| +00000050 33 74 00 00 00 05 00 05 01 00 00 00 00 00 0a 00 |3t..............| +00000060 08 00 06 00 17 00 18 00 19 00 0b 00 02 01 00 00 |................| +00000070 0d 00 0e 00 0c 04 01 04 03 05 01 05 03 02 01 02 |................| +00000080 03 ff 01 00 01 00 00 10 00 09 00 07 06 70 72 6f |.............pro| +00000090 74 6f 33 00 12 00 00 |to3....| >>> Flow 2 (server to client) -00000000 16 03 03 00 59 02 00 00 55 03 03 69 84 d1 d3 44 |....Y...U..i...D| -00000010 e9 66 08 48 bc 70 d8 ae 40 0b 17 69 e7 27 f6 7a |.f.H.p..@..i.'.z| -00000020 d5 ee 86 74 54 9e a8 bb 79 76 89 20 57 53 1b 02 |...tT...yv. WS..| -00000030 5b 70 81 a6 f1 53 bc 9d b7 42 5e ac 92 93 b5 20 |[p...S...B^.... | -00000040 8a bb 36 cc 8f cb 7e a0 61 a2 e8 ef c0 2f 00 00 |..6...~.a..../..| +00000000 16 03 03 00 59 02 00 00 55 03 03 94 d7 79 73 82 |....Y...U....ys.| +00000010 87 7c 85 6e 8a 1b 7d bf 69 c9 98 0c 44 bd f6 78 |.|.n..}.i...D..x| +00000020 d2 80 dc d8 7d 80 bb 91 4b d4 ed 20 fe 9f 2f 7b |....}...K.. ../{| +00000030 f2 1a 44 36 cd ce af f1 b5 01 8a ac 18 e4 2b 23 |..D6..........+#| +00000040 a8 ab 1a 32 23 8b 0b e2 81 a8 0a 40 c0 2f 00 00 |...2#......@./..| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 03 02 be 0b 00 02 ba 00 02 b7 00 02 b4 30 82 02 |.............0..| 00000070 b0 30 82 02 19 a0 03 02 01 02 02 09 00 85 b0 bb |.0..............| @@ -59,37 +60,37 @@ 000002f0 5f 33 c4 b6 d8 c9 75 90 96 8c 0f 52 98 b5 cd 98 |_3....u....R....| 00000300 1f 89 20 5f f2 a0 1c a3 1b 96 94 dd a9 fd 57 e9 |.. _..........W.| 00000310 70 e8 26 6d 71 99 9b 26 6e 38 50 29 6c 90 a7 bd |p.&mq..&n8P)l...| -00000320 d9 16 03 03 00 cd 0c 00 00 c9 03 00 17 41 04 04 |.............A..| -00000330 be 27 08 6f 12 83 1b 04 76 fa 5f 16 d6 e3 64 76 |.'.o....v._...dv| -00000340 ad 0a 77 37 71 64 44 4c 3f 1a be dc 85 ce 46 c8 |..w7qdDL?.....F.| -00000350 29 a1 e2 24 78 66 1f 35 90 05 46 c0 91 d1 fd dd |)..$xf.5..F.....| -00000360 b5 5b 87 d7 6d 9d 77 a7 f7 b3 df 68 27 fd 6d 04 |.[..m.w....h'.m.| -00000370 01 00 80 7b 9b fd 0d 62 57 07 ef 97 f5 ff a9 00 |...{...bW.......| -00000380 a0 89 35 5a 8a e6 e7 ae 7b 55 c5 dc 21 64 87 6e |..5Z....{U..!d.n| -00000390 0f ab 85 6d 82 e8 83 fd 7d 3b 49 a7 ae 92 5f 6d |...m....};I..._m| -000003a0 a3 42 ce ff ef a6 00 6a 33 32 1f 7b eb b7 c2 5c |.B.....j32.{...\| -000003b0 2d 38 cf 10 4b 59 69 4d 15 e0 68 49 39 ba cb 2a |-8..KYiM..hI9..*| -000003c0 d9 b9 f3 fe 33 01 4f 7e ac 69 02 35 a5 e0 33 8d |....3.O~.i.5..3.| -000003d0 b3 74 34 14 45 9c 89 ad 41 2d d0 27 22 90 58 c6 |.t4.E...A-.'".X.| -000003e0 e0 2c b4 6e 19 04 e4 46 26 ec 13 35 48 a6 3f 64 |.,.n...F&..5H.?d| -000003f0 dc 85 2b 16 03 03 00 04 0e 00 00 00 |..+.........| +00000320 d9 16 03 03 00 cd 0c 00 00 c9 03 00 17 41 04 7d |.............A.}| +00000330 75 a5 53 0b a5 4d a6 81 e0 df c4 11 c9 b5 31 ba |u.S..M........1.| +00000340 9f 7b 51 04 57 c6 e0 b9 b0 bc 4f bc 71 74 8a 2e |.{Q.W.....O.qt..| +00000350 d1 f6 39 36 94 4e c7 d3 a7 1b 2c b5 55 04 71 01 |..96.N....,.U.q.| +00000360 9e 2b 42 1e 8b a4 40 b2 13 4f 03 1f 51 9e 5c 04 |.+B...@..O..Q.\.| +00000370 01 00 80 68 05 c7 4a ca df 00 85 2b 53 f7 4f c3 |...h..J....+S.O.| +00000380 b4 0f e8 f7 b8 30 b7 36 56 65 7b 03 6a 72 f1 aa |.....0.6Ve{.jr..| +00000390 54 30 90 9e c7 dc fc 03 96 15 70 67 13 12 a4 f4 |T0........pg....| +000003a0 42 f0 f9 a1 48 c0 44 44 77 0e ea fd cb b5 6e 19 |B...H.DDw.....n.| +000003b0 89 94 a7 12 67 87 47 19 c3 00 2d c4 9b d4 dc 66 |....g.G...-....f| +000003c0 fa ca d7 97 79 9b 28 7f 74 d4 37 c0 06 63 d4 9e |....y.(.t.7..c..| +000003d0 a1 53 16 5a 8e d7 a5 cc 90 4d 63 f9 0c 18 85 7f |.S.Z.....Mc.....| +000003e0 0e 35 3a 49 73 88 82 51 41 e5 2d 58 aa 38 3e bd |.5:Is..QA.-X.8>.| +000003f0 3d d8 da 16 03 03 00 04 0e 00 00 00 |=...........| >>> Flow 3 (client to server) 00000000 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..| 00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.| 00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.| 00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I| 00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 03 00 01 |..h.A.Vk.Z......| -00000050 01 16 03 03 00 28 00 00 00 00 00 00 00 00 88 0d |.....(..........| -00000060 04 8b 8e 93 55 58 d6 75 ca 16 26 42 a3 60 20 67 |....UX.u..&B.` g| -00000070 84 cf d7 b3 10 fe 63 6c 2f 40 64 0c d6 78 |......cl/@d..x| +00000050 01 16 03 03 00 28 00 00 00 00 00 00 00 00 a8 da |.....(..........| +00000060 74 a6 d0 a5 26 86 f3 5f 89 a4 af ac 9c 1a 01 1f |t...&.._........| +00000070 89 8a 1c fc cf 68 3e a5 a3 20 1a b3 78 af |.....h>.. ..x.| >>> Flow 4 (server to client) -00000000 14 03 03 00 01 01 16 03 03 00 28 bd 6c 2f 70 b9 |..........(.l/p.| -00000010 2f 9c 29 70 af 34 49 4c 5b 25 c3 14 b6 6d 28 81 |/.)p.4IL[%...m(.| -00000020 ff 54 d9 71 8d 2c c7 38 dd 44 27 6b 54 1e 53 7b |.T.q.,.8.D'kT.S{| -00000030 22 cb 65 |".e| +00000000 14 03 03 00 01 01 16 03 03 00 28 1a f2 a9 e8 71 |..........(....q| +00000010 b2 a6 ca 36 4a ea 55 f6 20 03 fd f7 90 c3 af 30 |...6J.U. ......0| +00000020 d3 29 c3 d7 1b d6 4d 3e 61 55 94 0d 4e 3e 83 1a |.)....M>aU..N>..| +00000030 97 dd 19 |...| >>> Flow 5 (client to server) -00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 7f 0d d7 |................| -00000010 d9 4b 87 7b 36 fb 24 92 69 22 43 50 1e 46 fb c4 |.K.{6.$.i"CP.F..| -00000020 86 64 6f 15 03 03 00 1a 00 00 00 00 00 00 00 02 |.do.............| -00000030 37 d5 2d 0a be c5 a8 ae d4 bd 2b 09 34 18 a0 87 |7.-.......+.4...| -00000040 08 a6 |..| +00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 94 5b 5e |..............[^| +00000010 51 a1 52 ee 19 78 78 ef 12 0d 9c 66 bf e2 48 cb |Q.R..xx....f..H.| +00000020 f6 00 1e 15 03 03 00 1a 00 00 00 00 00 00 00 02 |................| +00000030 cd 5d 31 58 d9 5a 12 65 5b c6 7e 4e e2 04 e7 1d |.]1X.Z.e[.~N....| +00000040 b1 4c |.L| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA b/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA index 20732703647..1470ba7a250 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA +++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA @@ -1,18 +1,19 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......| +00000000 16 03 01 00 81 01 00 00 7d 03 03 00 00 00 00 00 |........}.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| -00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1a c0 2f |.............../| -00000030 c0 2b c0 11 c0 07 c0 13 c0 09 c0 14 c0 0a 00 05 |.+..............| -00000040 00 2f 00 35 c0 12 00 0a 01 00 00 2e 00 05 00 05 |./.5............| -00000050 01 00 00 00 00 00 0a 00 08 00 06 00 17 00 18 00 |................| -00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................| -00000070 03 02 01 02 03 ff 01 00 01 00 |..........| +00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1e c0 2f |.............../| +00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........| +00000040 c0 0a 00 05 00 2f 00 35 c0 12 00 0a 01 00 00 36 |...../.5.......6| +00000050 00 05 00 05 01 00 00 00 00 00 0a 00 08 00 06 00 |................| +00000060 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| +00000070 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| +00000080 01 00 00 12 00 00 |......| >>> Flow 2 (server to client) -00000000 16 03 03 00 59 02 00 00 55 03 03 53 04 f1 03 6f |....Y...U..S...o| -00000010 c6 4b 55 27 fe e8 fe 4d 7c 0e d4 20 98 b8 7c 81 |.KU'...M|.. ..|.| -00000020 3d 31 f8 35 66 2f 0a 0b f1 2c e3 20 86 4d 12 32 |=1.5f/...,. .M.2| -00000030 73 e3 ba be 25 50 a4 a2 a1 7b f1 9a 76 7a 75 fb |s...%P...{..vzu.| -00000040 e2 64 a2 12 ec f3 e7 9d 9a 24 6e 94 c0 09 00 00 |.d.......$n.....| +00000000 16 03 03 00 59 02 00 00 55 03 03 a5 28 60 99 bf |....Y...U...(`..| +00000010 c7 54 04 87 60 ad c5 32 f6 bf ed 11 47 de 4d ff |.T..`..2....G.M.| +00000020 99 e1 8f 88 f6 af 10 6e 29 74 0a 20 1d 39 cb e0 |.......n)t. .9..| +00000030 a5 11 fe 8e 23 11 83 c7 a6 53 fc 97 03 9d ff 7c |....#....S.....|| +00000040 cf 51 ba 41 64 61 38 22 5c c6 4a 04 c0 09 00 00 |.Q.Ada8"\.J.....| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 03 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..| 00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....| @@ -47,24 +48,23 @@ 00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....| 00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.| 00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....| -00000270 2a 16 03 03 00 d7 0c 00 00 d3 03 00 17 41 04 a3 |*............A..| -00000280 03 8c de d2 b0 68 c8 25 0e 85 ea d7 ae 13 0d 79 |.....h.%.......y| -00000290 ec 59 0d b5 4d 51 96 d9 7f 64 36 fb 4c d5 6a 26 |.Y..MQ...d6.L.j&| -000002a0 ae 0e 48 61 df 5c 2b d4 ff 09 41 15 c4 14 8e 1b |..Ha.\+...A.....| -000002b0 84 a8 c8 cd ef 10 97 95 66 67 85 dd fd dc 2a 04 |........fg....*.| -000002c0 03 00 8a 30 81 87 02 41 11 75 5d bc bd 08 28 d4 |...0...A.u]...(.| -000002d0 5b 1b 45 7f 9c d3 8d 0b 91 fa f6 82 ba 59 bd 3e |[.E..........Y.>| -000002e0 96 01 c6 1d 38 db fe 08 e7 56 89 fc 10 b0 37 6a |....8....V....7j| -000002f0 3d d6 c9 50 16 53 f7 c2 a2 60 67 82 1f 74 b8 d5 |=..P.S...`g..t..| -00000300 bc 02 ec 96 db 82 18 8c 87 02 42 01 0d df f7 b7 |..........B.....| -00000310 05 3c 8c 56 f0 1d 33 18 cf c5 4c 80 7e 0b d9 f9 |.<.V..3...L.~...| -00000320 f0 51 69 fe 5d b8 0b 64 c0 c7 0d f4 75 65 ae 07 |.Qi.]..d....ue..| -00000330 9d cf f4 4b ad 52 f6 b8 10 26 18 bd d6 e2 0d a8 |...K.R...&......| -00000340 80 10 50 34 15 cd 72 0b 7d a9 94 de 4c 16 03 03 |..P4..r.}...L...| -00000350 00 30 0d 00 00 28 03 01 02 40 00 20 06 01 06 02 |.0...(...@. ....| +00000270 2a 16 03 03 00 d7 0c 00 00 d3 03 00 17 41 04 c4 |*............A..| +00000280 0a 40 05 84 eb 90 3c 13 d0 90 af 69 fa 5c 20 75 |.@....<....i.\ u| +00000290 e1 9b f2 30 f7 df cc 75 2c 35 7e 38 16 99 7d 57 |...0...u,5~8..}W| +000002a0 6d d7 f0 93 2d 1d c8 03 89 6e 52 3b 20 e5 8a 5f |m...-....nR; .._| +000002b0 6d ca 6e 6a ca 51 f8 a4 dc 1d ec 3e 73 c9 72 04 |m.nj.Q.....>s.r.| +000002c0 03 00 8a 30 81 87 02 41 37 bf 0d 1d c1 9a 37 39 |...0...A7.....79| +000002d0 4d 4a f8 17 50 5d 4c 78 d4 25 99 9d 81 48 98 a8 |MJ..P]Lx.%...H..| +000002e0 ff 2d 3f 98 4b 9f d8 96 2b fa 37 cc e8 66 25 0e |.-?.K...+.7..f%.| +000002f0 d3 5e 53 c5 3b ad 17 3f 21 ce d2 45 d8 93 95 6c |.^S.;..?!..E...l| +00000300 25 f9 5a 10 9f 37 c8 14 a6 02 42 00 e6 bd 9a 89 |%.Z..7....B.....| +00000310 8e 73 40 f4 90 e6 d8 e2 98 51 10 23 fb 98 e5 47 |.s@......Q.#...G| +00000320 0c 2a 7a 2f 02 66 a8 20 e4 cb 4f ba 14 1d 9e 3a |.*z/.f. ..O....:| +00000330 2f 09 47 44 02 e0 9f 30 21 71 f0 99 09 de 23 d2 |/.GD...0!q....#.| +00000340 f5 f0 b2 93 70 a3 8f 79 b9 4f 88 0b 35 16 03 03 |....p..y.O..5...| +00000350 00 2e 0d 00 00 26 03 01 02 40 00 1e 06 01 06 02 |.....&...@......| 00000360 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 |................| -00000370 03 02 03 03 02 01 02 02 02 03 01 01 00 00 0e 00 |................| -00000380 00 00 |..| +00000370 03 02 03 03 02 01 02 02 02 03 00 00 0e 00 00 00 |................| >>> Flow 3 (client to server) 00000000 16 03 03 02 0a 0b 00 02 06 00 02 03 00 02 00 30 |...............0| 00000010 82 01 fc 30 82 01 5e 02 09 00 9a 30 84 6c 26 35 |...0..^....0.l&5| @@ -104,31 +104,31 @@ 00000230 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e f1 |$ >.V...(^.+-O..| 00000240 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 a6 |..lK[.V.2B.X..I.| 00000250 b5 68 1a 41 03 56 6b dc 5a 89 16 03 03 00 92 0f |.h.A.Vk.Z.......| -00000260 00 00 8e 04 03 00 8a 30 81 87 02 42 00 c6 85 8e |.......0...B....| -00000270 06 b7 04 04 e9 cd 9e 3e cb 66 23 95 b4 42 9c 64 |.......>.f#..B.d| -00000280 81 39 05 3f b5 21 f8 28 af 60 6b 4d 3d ba a1 4b |.9.?.!.(.`kM=..K| -00000290 5e 77 ef e7 59 28 fe 1d c1 27 a2 ff a8 de 33 48 |^w..Y(...'....3H| -000002a0 b3 c1 85 6a 42 9b f9 7e 7e 31 c2 e5 bd 66 02 41 |...jB..~~1...f.A| -000002b0 4b 49 c6 cd 02 e3 83 f7 03 50 18 6d b4 c9 51 02 |KI.......P.m..Q.| -000002c0 c0 ab 87 bc e0 3e 4b 89 53 3a e2 65 89 97 02 c1 |.....>K.S:.e....| -000002d0 88 0d 64 db 8e 4f 73 4e ea 29 0b ed a0 f5 ce 3d |..d..OsN.).....=| -000002e0 5f cc 20 ef 0a 22 02 82 f2 14 2a b7 42 68 bd c7 |_. .."....*.Bh..| -000002f0 4d 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 |M..........@....| -00000300 00 00 00 00 00 00 00 00 00 00 00 00 f0 cc 4f c7 |..............O.| -00000310 b6 0f c9 38 4d 4b 97 2c 4f be 53 08 4c d6 5b 4e |...8MK.,O.S.L.[N| -00000320 24 70 30 81 82 3a 7f 62 95 03 4d fc 54 78 ec 13 |$p0..:.b..M.Tx..| -00000330 b2 a1 00 85 2b 04 e4 1d 7b 6e 87 60 |....+...{n.`| +00000260 00 00 8e 05 03 00 8a 30 81 87 02 42 00 cc a4 ad |.......0...B....| +00000270 0b ff 09 40 8f 2c a6 37 72 1d f7 d2 19 74 85 ad |...@.,.7r....t..| +00000280 ac 33 b0 b8 5b 56 39 cf b0 ef 46 68 94 39 4c d0 |.3..[V9...Fh.9L.| +00000290 f4 97 32 10 99 36 c5 95 c8 14 23 37 78 46 5c a9 |..2..6....#7xF\.| +000002a0 20 95 65 47 ff 54 02 f1 aa 1d d7 bc 39 2d 02 41 | .eG.T......9-.A| +000002b0 2e f9 d6 8c e8 c5 a9 6f 10 4f d6 5f 4e 88 e9 71 |.......o.O._N..q| +000002c0 23 5b 6f b8 ab 19 d3 dd ec f3 32 e3 3b fa 41 a2 |#[o.......2.;.A.| +000002d0 e8 ae dc 27 8d 4e 79 f4 47 ef c9 8f bf 0b 41 3b |...'.Ny.G.....A;| +000002e0 94 16 cb 8f 1e b5 f3 4e 6e 42 46 35 1a 0c ca 79 |.......NnBF5...y| +000002f0 4b 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 |K..........@....| +00000300 00 00 00 00 00 00 00 00 00 00 00 00 64 1c d9 9f |............d...| +00000310 34 ec c2 74 76 7a 9f cf 95 19 be 8d 6a 2f 25 96 |4..tvz......j/%.| +00000320 df de 18 ca 0e c9 d4 2f e4 b0 34 10 5b 72 7a 18 |......./..4.[rz.| +00000330 5c 64 d7 fc 2e 1b 28 10 ae a6 31 e9 |\d....(...1.| >>> Flow 4 (server to client) -00000000 14 03 03 00 01 01 16 03 03 00 40 d5 2a 76 79 1c |..........@.*vy.| -00000010 e7 d5 b1 5c 65 6b d1 45 73 53 4c 05 3a 6c 5d 81 |...\ek.EsSL.:l].| -00000020 dd 2f f0 74 62 e4 8e f8 ed 21 99 c7 4f d6 28 40 |./.tb....!..O.(@| -00000030 63 d9 6d e5 b0 04 73 27 7a 1d 08 19 31 10 da ef |c.m...s'z...1...| -00000040 79 26 33 fb 45 23 be a4 7c 03 66 |y&3.E#..|.f| +00000000 14 03 03 00 01 01 16 03 03 00 40 27 6f 24 a3 0c |..........@'o$..| +00000010 6d d7 68 4a fb 43 b0 97 02 6c 22 7e 2f a1 f1 7a |m.hJ.C...l"~/..z| +00000020 37 bf 38 82 dc a0 83 24 01 4b c0 4f 15 e1 7c 4c |7.8....$.K.O..|L| +00000030 d4 cd b8 e2 71 af f5 20 7d f9 4a 48 4b f0 a1 f3 |....q.. }.JHK...| +00000040 7b 02 29 18 c0 87 a5 dd c4 73 8e |{.)......s.| >>> Flow 5 (client to server) 00000000 17 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........| -00000010 00 00 00 00 00 e2 53 bd c0 ef 9e e6 44 94 ea 5d |......S.....D..]| -00000020 f5 c5 a9 4b ed eb 1c 49 9f 79 44 f9 cd d7 de 02 |...K...I.yD.....| -00000030 51 10 ae 87 7d 15 03 03 00 30 00 00 00 00 00 00 |Q...}....0......| -00000040 00 00 00 00 00 00 00 00 00 00 d3 95 13 7f 5f 58 |.............._X| -00000050 ab d6 17 ea 01 2c 2a ea 5d 7c 44 61 4a 27 97 52 |.....,*.]|DaJ'.R| -00000060 cc 9b 86 f6 37 42 2b 94 01 49 |....7B+..I| +00000010 00 00 00 00 00 bf 7a e1 23 0d d0 13 6e 96 81 6d |......z.#...n..m| +00000020 32 56 0f 75 7e 01 88 5f 6d e6 d6 ca ec 3c 17 e9 |2V.u~.._m....<..| +00000030 44 a9 c0 1c a4 15 03 03 00 30 00 00 00 00 00 00 |D........0......| +00000040 00 00 00 00 00 00 00 00 00 00 76 be 7a 77 29 01 |..........v.zw).| +00000050 8e 13 02 66 81 43 a0 55 03 35 22 09 de ea 52 bb |...f.C.U.5"...R.| +00000060 51 cc c1 09 0e 9b 4d bd 94 85 |Q.....M...| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA b/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA index c3b753a7b44..95c5782ab0d 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA +++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA @@ -1,18 +1,19 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......| +00000000 16 03 01 00 81 01 00 00 7d 03 03 00 00 00 00 00 |........}.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| -00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1a c0 2f |.............../| -00000030 c0 2b c0 11 c0 07 c0 13 c0 09 c0 14 c0 0a 00 05 |.+..............| -00000040 00 2f 00 35 c0 12 00 0a 01 00 00 2e 00 05 00 05 |./.5............| -00000050 01 00 00 00 00 00 0a 00 08 00 06 00 17 00 18 00 |................| -00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................| -00000070 03 02 01 02 03 ff 01 00 01 00 |..........| +00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1e c0 2f |.............../| +00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........| +00000040 c0 0a 00 05 00 2f 00 35 c0 12 00 0a 01 00 00 36 |...../.5.......6| +00000050 00 05 00 05 01 00 00 00 00 00 0a 00 08 00 06 00 |................| +00000060 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| +00000070 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| +00000080 01 00 00 12 00 00 |......| >>> Flow 2 (server to client) -00000000 16 03 03 00 51 02 00 00 4d 03 03 53 04 f1 03 b0 |....Q...M..S....| -00000010 43 00 97 24 a7 a8 ea b2 24 fe 96 24 a1 49 64 fd |C..$....$..$.Id.| -00000020 1c a3 30 35 2d 85 a7 40 42 86 6b 20 af 27 7f ac |..05-..@B.k .'..| -00000030 8b 16 89 6c 78 b7 f5 29 02 58 a6 8b 61 43 c2 b0 |...lx..).X..aC..| -00000040 e0 a8 96 c8 fa 2b 26 ad 9a 5f 2d d6 00 05 00 00 |.....+&.._-.....| +00000000 16 03 03 00 51 02 00 00 4d 03 03 79 e8 35 e3 d2 |....Q...M..y.5..| +00000010 c0 5e 39 d1 46 da 9c 94 56 20 e2 06 d6 9b f6 dd |.^9.F...V ......| +00000020 4f 7a c1 e8 34 a1 9f 8b c2 e1 fb 20 66 9c 5a 9a |Oz..4...... f.Z.| +00000030 3d 22 ab 8e d8 81 03 94 68 a0 6c 72 d8 23 0b 4b |="......h.lr.#.K| +00000040 fe 9d c7 49 a7 7c bd fa b5 7a 5e 5b 00 05 00 00 |...I.|...z^[....| 00000050 05 ff 01 00 01 00 16 03 03 02 be 0b 00 02 ba 00 |................| 00000060 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......| 00000070 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..| @@ -57,10 +58,10 @@ 000002e0 50 56 5c d5 82 5a 2d 5a 5f 33 c4 b6 d8 c9 75 90 |PV\..Z-Z_3....u.| 000002f0 96 8c 0f 52 98 b5 cd 98 1f 89 20 5f f2 a0 1c a3 |...R...... _....| 00000300 1b 96 94 dd a9 fd 57 e9 70 e8 26 6d 71 99 9b 26 |......W.p.&mq..&| -00000310 6e 38 50 29 6c 90 a7 bd d9 16 03 03 00 30 0d 00 |n8P)l........0..| -00000320 00 28 03 01 02 40 00 20 06 01 06 02 06 03 05 01 |.(...@. ........| +00000310 6e 38 50 29 6c 90 a7 bd d9 16 03 03 00 2e 0d 00 |n8P)l...........| +00000320 00 26 03 01 02 40 00 1e 06 01 06 02 06 03 05 01 |.&...@..........| 00000330 05 02 05 03 04 01 04 02 04 03 03 01 03 02 03 03 |................| -00000340 02 01 02 02 02 03 01 01 00 00 0e 00 00 00 |..............| +00000340 02 01 02 02 02 03 00 00 0e 00 00 00 |............| >>> Flow 3 (client to server) 00000000 16 03 03 02 0a 0b 00 02 06 00 02 03 00 02 00 30 |...............0| 00000010 82 01 fc 30 82 01 5e 02 09 00 9a 30 84 6c 26 35 |...0..^....0.l&5| @@ -104,24 +105,24 @@ 00000270 bd 77 82 6f 23 b6 e0 bd a2 92 b7 3a ac e8 56 f1 |.w.o#......:..V.| 00000280 af 54 5e 46 87 e9 3b 33 e7 b8 28 b7 d6 c8 90 35 |.T^F..;3..(....5| 00000290 d4 1c 43 d1 30 6f 55 4e 0a 70 16 03 03 00 92 0f |..C.0oUN.p......| -000002a0 00 00 8e 04 03 00 8a 30 81 87 02 42 00 c6 85 8e |.......0...B....| -000002b0 06 b7 04 04 e9 cd 9e 3e cb 66 23 95 b4 42 9c 64 |.......>.f#..B.d| -000002c0 81 39 05 3f b5 21 f8 28 af 60 6b 4d 3d ba a1 4b |.9.?.!.(.`kM=..K| -000002d0 5e 77 ef e7 59 28 fe 1d c1 27 a2 ff a8 de 33 48 |^w..Y(...'....3H| -000002e0 b3 c1 85 6a 42 9b f9 7e 7e 31 c2 e5 bd 66 02 41 |...jB..~~1...f.A| -000002f0 4b 49 c6 cd 02 e3 83 f7 03 50 18 6d b4 c9 51 02 |KI.......P.m..Q.| -00000300 c0 ab 87 bc e0 3e 4b 89 53 3a e2 65 89 97 02 c1 |.....>K.S:.e....| -00000310 88 5a 97 82 3e 55 6b 7c d8 db b8 cc 1b 30 84 0a |.Z..>Uk|.....0..| -00000320 7a 97 71 e4 10 bb a4 39 8c 2a cf f5 88 c7 d1 95 |z.q....9.*......| -00000330 73 14 03 03 00 01 01 16 03 03 00 24 9f 1e f0 72 |s..........$...r| -00000340 92 ea dc f7 56 96 37 e4 69 db db 66 1d f6 94 c4 |....V.7.i..f....| -00000350 18 31 4f d0 5d c5 f4 53 21 aa 98 b1 dc 08 94 94 |.1O.]..S!.......| +000002a0 00 00 8e 05 03 00 8a 30 81 87 02 41 19 c7 50 06 |.......0...A..P.| +000002b0 42 82 f9 e5 ec 0b f7 65 7e b1 19 53 5f 23 ab 19 |B......e~..S_#..| +000002c0 54 08 ec d2 a7 22 dd 83 7c 97 76 59 a5 6b f4 1d |T...."..|.vY.k..| +000002d0 92 86 34 2d ce 71 bb 01 d2 8a 67 0e a8 fb 51 e4 |..4-.q....g...Q.| +000002e0 69 9c 27 23 74 b9 fd 6f b6 5e 48 a0 cc 02 42 01 |i.'#t..o.^H...B.| +000002f0 50 97 b7 95 14 f4 a6 f2 95 63 17 38 59 a1 51 95 |P........c.8Y.Q.| +00000300 1e bc 99 fb fd 82 8b ab cb 4d 8e 17 a9 f8 e9 c2 |.........M......| +00000310 9b 93 15 02 50 e6 c2 05 54 e7 8a ec 6f 93 1f 79 |....P...T...o..y| +00000320 8d 67 e7 2d d6 65 ab 97 fd be 20 97 bd 6b c4 fc |.g.-.e.... ..k..| +00000330 02 14 03 03 00 01 01 16 03 03 00 24 24 df 52 6e |...........$$.Rn| +00000340 c1 35 48 fe 60 77 28 69 36 fe 96 a1 72 db a2 f5 |.5H.`w(i6...r...| +00000350 d0 b7 c3 d9 67 e5 ee f2 d9 18 bf f0 35 80 06 c2 |....g.......5...| >>> Flow 4 (server to client) -00000000 14 03 03 00 01 01 16 03 03 00 24 ee 68 c1 87 9f |..........$.h...| -00000010 d7 90 94 f1 3b 6d 26 0b 3d 89 7a 45 3b 52 5d 3c |....;m&.=.zE;R]<| -00000020 dd 7c c1 4e 57 3e a9 ee 91 be cf 2b a3 98 9d |.|.NW>.....+...| +00000000 14 03 03 00 01 01 16 03 03 00 24 40 5b dc 01 59 |..........$@[..Y| +00000010 33 6e 61 5a 6d fc c8 a5 f5 00 9b 55 77 c5 e6 f2 |3naZm......Uw...| +00000020 c6 5c b6 2f 94 3c 72 5b b5 0c 3e 78 88 e6 44 |.\./.x..D| >>> Flow 5 (client to server) -00000000 17 03 03 00 1a 88 33 3e 2b 22 6b 92 d0 bb 8a 1e |......3>+"k.....| -00000010 9b f4 9e aa 91 8b 2b 95 ea 53 c8 03 0a 93 58 15 |......+..S....X.| -00000020 03 03 00 16 c4 67 79 ba ec cf 90 b1 f9 ac ec 64 |.....gy........d| -00000030 72 01 08 8f 3a 98 aa 66 25 00 |r...:..f%.| +00000000 17 03 03 00 1a cd 2f 11 b1 3a e4 1c 31 95 9b c4 |....../..:..1...| +00000010 37 20 9f 03 d3 45 a4 15 e1 09 1e 0c f6 5d d3 15 |7 ...E.......]..| +00000020 03 03 00 16 d7 f6 a1 d0 ad 41 69 73 c0 40 22 f2 |.........Ais.@".| +00000030 5f e8 c3 50 f9 35 fc 59 e0 3a |_..P.5.Y.:| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-AES256-GCM-SHA384 b/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-AES256-GCM-SHA384 new file mode 100644 index 00000000000..52e3befe615 --- /dev/null +++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-AES256-GCM-SHA384 @@ -0,0 +1,139 @@ +>>> Flow 1 (client to server) +00000000 16 03 01 00 81 01 00 00 7d 03 03 00 00 00 00 00 |........}.......| +00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1e c0 2f |.............../| +00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........| +00000040 c0 0a 00 05 00 2f 00 35 c0 12 00 0a 01 00 00 36 |...../.5.......6| +00000050 00 05 00 05 01 00 00 00 00 00 0a 00 08 00 06 00 |................| +00000060 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| +00000070 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| +00000080 01 00 00 12 00 00 |......| +>>> Flow 2 (server to client) +00000000 16 03 03 00 59 02 00 00 55 03 03 74 fe 19 af 4b |....Y...U..t...K| +00000010 f3 d8 92 62 5a df 90 2c cc 09 fd 79 45 26 cd 52 |...bZ..,...yE&.R| +00000020 9a e6 da 16 99 fe 1d 91 79 a7 a0 20 b3 13 e9 03 |........y.. ....| +00000030 52 23 5f f0 55 59 f1 9e 00 a7 77 97 90 ed 2b fb |R#_.UY....w...+.| +00000040 9c ab fe b1 db ea 16 95 95 68 b0 e9 c0 30 00 00 |.........h...0..| +00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| +00000060 03 02 be 0b 00 02 ba 00 02 b7 00 02 b4 30 82 02 |.............0..| +00000070 b0 30 82 02 19 a0 03 02 01 02 02 09 00 85 b0 bb |.0..............| +00000080 a4 8a 7f b8 ca 30 0d 06 09 2a 86 48 86 f7 0d 01 |.....0...*.H....| +00000090 01 05 05 00 30 45 31 0b 30 09 06 03 55 04 06 13 |....0E1.0...U...| +000000a0 02 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f |.AU1.0...U....So| +000000b0 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 |me-State1!0...U.| +000000c0 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 |...Internet Widg| +000000d0 69 74 73 20 50 74 79 20 4c 74 64 30 1e 17 0d 31 |its Pty Ltd0...1| +000000e0 30 30 34 32 34 30 39 30 39 33 38 5a 17 0d 31 31 |00424090938Z..11| +000000f0 30 34 32 34 30 39 30 39 33 38 5a 30 45 31 0b 30 |0424090938Z0E1.0| +00000100 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 |...U....AU1.0...| +00000110 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 |U....Some-State1| +00000120 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e |!0...U....Intern| +00000130 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c |et Widgits Pty L| +00000140 74 64 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 |td0..0...*.H....| +00000150 01 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 bb |........0.......| +00000160 79 d6 f5 17 b5 e5 bf 46 10 d0 dc 69 be e6 2b 07 |y......F...i..+.| +00000170 43 5a d0 03 2d 8a 7a 43 85 b7 14 52 e7 a5 65 4c |CZ..-.zC...R..eL| +00000180 2c 78 b8 23 8c b5 b4 82 e5 de 1f 95 3b 7e 62 a5 |,x.#........;~b.| +00000190 2c a5 33 d6 fe 12 5c 7a 56 fc f5 06 bf fa 58 7b |,.3...\zV.....X{| +000001a0 26 3f b5 cd 04 d3 d0 c9 21 96 4a c7 f4 54 9f 5a |&?......!.J..T.Z| +000001b0 bf ef 42 71 00 fe 18 99 07 7f 7e 88 7d 7d f1 04 |..Bq......~.}}..| +000001c0 39 c4 a2 2e db 51 c9 7c e3 c0 4c 3b 32 66 01 cf |9....Q.|..L;2f..| +000001d0 af b1 1d b8 71 9a 1d db db 89 6b ae da 2d 79 02 |....q.....k..-y.| +000001e0 03 01 00 01 a3 81 a7 30 81 a4 30 1d 06 03 55 1d |.......0..0...U.| +000001f0 0e 04 16 04 14 b1 ad e2 85 5a cf cb 28 db 69 ce |.........Z..(.i.| +00000200 23 69 de d3 26 8e 18 88 39 30 75 06 03 55 1d 23 |#i..&...90u..U.#| +00000210 04 6e 30 6c 80 14 b1 ad e2 85 5a cf cb 28 db 69 |.n0l......Z..(.i| +00000220 ce 23 69 de d3 26 8e 18 88 39 a1 49 a4 47 30 45 |.#i..&...9.I.G0E| +00000230 31 0b 30 09 06 03 55 04 06 13 02 41 55 31 13 30 |1.0...U....AU1.0| +00000240 11 06 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 |...U....Some-Sta| +00000250 74 65 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 |te1!0...U....Int| +00000260 65 72 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 |ernet Widgits Pt| +00000270 79 20 4c 74 64 82 09 00 85 b0 bb a4 8a 7f b8 ca |y Ltd...........| +00000280 30 0c 06 03 55 1d 13 04 05 30 03 01 01 ff 30 0d |0...U....0....0.| +00000290 06 09 2a 86 48 86 f7 0d 01 01 05 05 00 03 81 81 |..*.H...........| +000002a0 00 08 6c 45 24 c7 6b b1 59 ab 0c 52 cc f2 b0 14 |..lE$.k.Y..R....| +000002b0 d7 87 9d 7a 64 75 b5 5a 95 66 e4 c5 2b 8e ae 12 |...zdu.Z.f..+...| +000002c0 66 1f eb 4f 38 b3 6e 60 d3 92 fd f7 41 08 b5 25 |f..O8.n`....A..%| +000002d0 13 b1 18 7a 24 fb 30 1d ba ed 98 b9 17 ec e7 d7 |...z$.0.........| +000002e0 31 59 db 95 d3 1d 78 ea 50 56 5c d5 82 5a 2d 5a |1Y....x.PV\..Z-Z| +000002f0 5f 33 c4 b6 d8 c9 75 90 96 8c 0f 52 98 b5 cd 98 |_3....u....R....| +00000300 1f 89 20 5f f2 a0 1c a3 1b 96 94 dd a9 fd 57 e9 |.. _..........W.| +00000310 70 e8 26 6d 71 99 9b 26 6e 38 50 29 6c 90 a7 bd |p.&mq..&n8P)l...| +00000320 d9 16 03 03 00 cd 0c 00 00 c9 03 00 17 41 04 22 |.............A."| +00000330 84 e9 5e 6e 35 92 a3 83 73 0a d6 0d 1a c1 4d ab |..^n5...s.....M.| +00000340 1f ab c2 dc 3f 53 a5 7d 38 c0 92 a4 82 e1 3c c5 |....?S.}8.....<.| +00000350 24 60 20 a5 3b c5 65 ba 9c f1 b9 a5 b9 c2 70 73 |$` .;.e.......ps| +00000360 19 74 a6 d1 0f 75 b4 75 e0 e8 60 20 e9 23 fe 04 |.t...u.u..` .#..| +00000370 01 00 80 92 e0 56 3f 48 0d 10 23 48 b5 95 b6 91 |.....V?H..#H....| +00000380 3e 8a 2e c7 02 e2 85 0e 59 c8 03 24 d9 1a 1a 25 |>.......Y..$...%| +00000390 8e 12 bb 0b 83 ac 51 36 81 3f bc 0e be b9 3b 1d |......Q6.?....;.| +000003a0 67 56 21 4d 24 36 84 05 61 e7 70 60 d5 8e ae 97 |gV!M$6..a.p`....| +000003b0 b8 3a d3 b1 94 72 52 cd b0 0d dd 46 b1 15 3b 58 |.:...rR....F..;X| +000003c0 c1 a4 63 2c 4c 31 f9 c7 4f 27 c1 0f f0 24 36 72 |..c,L1..O'...$6r| +000003d0 e0 f8 51 12 86 c2 13 ed 6b 84 a8 15 c3 d0 39 55 |..Q.....k.....9U| +000003e0 a4 60 50 88 c9 1e 60 60 aa 8d a5 31 3e 35 c3 f8 |.`P...``...1>5..| +000003f0 2c 90 1c 16 03 03 00 2e 0d 00 00 26 03 01 02 40 |,..........&...@| +00000400 00 1e 06 01 06 02 06 03 05 01 05 02 05 03 04 01 |................| +00000410 04 02 04 03 03 01 03 02 03 03 02 01 02 02 02 03 |................| +00000420 00 00 0e 00 00 00 |......| +>>> Flow 3 (client to server) +00000000 16 03 03 01 fb 0b 00 01 f7 00 01 f4 00 01 f1 30 |...............0| +00000010 82 01 ed 30 82 01 58 a0 03 02 01 02 02 01 00 30 |...0..X........0| +00000020 0b 06 09 2a 86 48 86 f7 0d 01 01 05 30 26 31 10 |...*.H......0&1.| +00000030 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 6f |0...U....Acme Co| +00000040 31 12 30 10 06 03 55 04 03 13 09 31 32 37 2e 30 |1.0...U....127.0| +00000050 2e 30 2e 31 30 1e 17 0d 31 31 31 32 30 38 30 37 |.0.10...11120807| +00000060 35 35 31 32 5a 17 0d 31 32 31 32 30 37 30 38 30 |5512Z..121207080| +00000070 30 31 32 5a 30 26 31 10 30 0e 06 03 55 04 0a 13 |012Z0&1.0...U...| +00000080 07 41 63 6d 65 20 43 6f 31 12 30 10 06 03 55 04 |.Acme Co1.0...U.| +00000090 03 13 09 31 32 37 2e 30 2e 30 2e 31 30 81 9c 30 |...127.0.0.10..0| +000000a0 0b 06 09 2a 86 48 86 f7 0d 01 01 01 03 81 8c 00 |...*.H..........| +000000b0 30 81 88 02 81 80 4e d0 7b 31 e3 82 64 d9 59 c0 |0.....N.{1..d.Y.| +000000c0 c2 87 a4 5e 1e 8b 73 33 c7 63 53 df 66 92 06 84 |...^..s3.cS.f...| +000000d0 f6 64 d5 8f e4 36 a7 1d 2b e8 b3 20 36 45 23 b5 |.d...6..+.. 6E#.| +000000e0 e3 95 ae ed e0 f5 20 9c 8d 95 df 7f 5a 12 ef 87 |...... .....Z...| +000000f0 e4 5b 68 e4 e9 0e 74 ec 04 8a 7f de 93 27 c4 01 |.[h...t......'..| +00000100 19 7a bd f2 dc 3d 14 ab d0 54 ca 21 0c d0 4d 6e |.z...=...T.!..Mn| +00000110 87 2e 5c c5 d2 bb 4d 4b 4f ce b6 2c f7 7e 88 ec |..\...MKO..,.~..| +00000120 7c d7 02 91 74 a6 1e 0c 1a da e3 4a 5a 2e de 13 ||...t......JZ...| +00000130 9c 4c 40 88 59 93 02 03 01 00 01 a3 32 30 30 30 |.L@.Y.......2000| +00000140 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 00 a0 30 |...U...........0| +00000150 0d 06 03 55 1d 0e 04 06 04 04 01 02 03 04 30 0f |...U..........0.| +00000160 06 03 55 1d 23 04 08 30 06 80 04 01 02 03 04 30 |..U.#..0.......0| +00000170 0b 06 09 2a 86 48 86 f7 0d 01 01 05 03 81 81 00 |...*.H..........| +00000180 36 1f b3 7a 0c 75 c9 6e 37 46 61 2b d5 bd c0 a7 |6..z.u.n7Fa+....| +00000190 4b cc 46 9a 81 58 7c 85 79 29 c8 c8 c6 67 dd 32 |K.F..X|.y)...g.2| +000001a0 56 45 2b 75 b6 e9 24 a9 50 9a be 1f 5a fa 1a 15 |VE+u..$.P...Z...| +000001b0 d9 cc 55 95 72 16 83 b9 c2 b6 8f fd 88 8c 38 84 |..U.r.........8.| +000001c0 1d ab 5d 92 31 13 4f fd 83 3b c6 9d f1 11 62 b6 |..].1.O..;....b.| +000001d0 8b ec ab 67 be c8 64 b0 11 50 46 58 17 6b 99 1c |...g..d..PFX.k..| +000001e0 d3 1d fc 06 f1 0e e5 96 a8 0c f9 78 20 b7 44 18 |...........x .D.| +000001f0 51 8d 10 7e 4f 94 67 df a3 4e 70 73 8e 90 91 85 |Q..~O.g..Nps....| +00000200 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..| +00000210 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.| +00000220 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.| +00000230 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I| +00000240 a6 b5 68 1a 41 03 56 6b dc 5a 89 16 03 03 00 88 |..h.A.Vk.Z......| +00000250 0f 00 00 84 05 01 00 80 33 bb 8e 67 64 03 e7 7e |........3..gd..~| +00000260 be a5 b1 bc cf 7a 07 24 01 17 c3 3d 4b 72 dd c3 |.....z.$...=Kr..| +00000270 64 a7 36 e8 49 ab b6 87 ce d6 af 9e 07 22 76 e8 |d.6.I........"v.| +00000280 0d 44 a3 36 c9 eb a4 49 85 cf 72 67 e8 2a a7 5b |.D.6...I..rg.*.[| +00000290 d3 f2 46 af 53 48 c6 13 f7 0b 5b 9c c7 4d 3e 05 |..F.SH....[..M>.| +000002a0 3c 0f 69 a7 40 3a e8 70 04 01 1c 29 b2 42 0f 5f |<.i.@:.p...).B._| +000002b0 1c d5 b7 5c c2 17 07 7f bd a2 b3 9a 95 81 51 24 |...\..........Q$| +000002c0 54 5c 42 d6 a4 76 c0 d7 54 d2 11 54 bf fd dc a0 |T\B..v..T..T....| +000002d0 ee 95 26 64 59 a0 fc 51 14 03 03 00 01 01 16 03 |..&dY..Q........| +000002e0 03 00 28 00 00 00 00 00 00 00 00 af f4 8a be d9 |..(.............| +000002f0 ff f1 44 e4 41 ab 9b b3 d8 b0 3d 3f 6b c5 1d b6 |..D.A.....=?k...| +00000300 1d 9e 35 f5 20 f4 2a af e8 35 77 |..5. .*..5w| +>>> Flow 4 (server to client) +00000000 14 03 03 00 01 01 16 03 03 00 28 ff 0d 47 63 2b |..........(..Gc+| +00000010 bd 00 3a ad 82 e3 a7 b3 b0 84 4a 26 f4 30 78 20 |..:.......J&.0x | +00000020 80 f2 2b 15 98 61 1c cb 8b 17 67 8a 11 96 aa 93 |..+..a....g.....| +00000030 68 f7 fb |h..| +>>> Flow 5 (client to server) +00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 a6 8d 7b |...............{| +00000010 99 5e a2 e1 95 bb 5f e4 01 f4 0e 20 52 b4 64 4e |.^...._.... R.dN| +00000020 86 b1 3f 15 03 03 00 1a 00 00 00 00 00 00 00 02 |..?.............| +00000030 61 98 eb d0 7c ac bd 00 ac 7a e1 32 20 3e 81 b6 |a...|....z.2 >..| +00000040 9d d5 |..| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA b/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA index 0037af61a03..23bf29d776e 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA +++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA @@ -1,18 +1,19 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......| +00000000 16 03 01 00 81 01 00 00 7d 03 03 00 00 00 00 00 |........}.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| -00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1a c0 2f |.............../| -00000030 c0 2b c0 11 c0 07 c0 13 c0 09 c0 14 c0 0a 00 05 |.+..............| -00000040 00 2f 00 35 c0 12 00 0a 01 00 00 2e 00 05 00 05 |./.5............| -00000050 01 00 00 00 00 00 0a 00 08 00 06 00 17 00 18 00 |................| -00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................| -00000070 03 02 01 02 03 ff 01 00 01 00 |..........| +00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1e c0 2f |.............../| +00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........| +00000040 c0 0a 00 05 00 2f 00 35 c0 12 00 0a 01 00 00 36 |...../.5.......6| +00000050 00 05 00 05 01 00 00 00 00 00 0a 00 08 00 06 00 |................| +00000060 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| +00000070 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| +00000080 01 00 00 12 00 00 |......| >>> Flow 2 (server to client) -00000000 16 03 03 00 59 02 00 00 55 03 03 53 04 f1 02 fd |....Y...U..S....| -00000010 41 bd ef ee f3 da fc 1a 31 8c 77 f2 e9 66 54 a0 |A.......1.w..fT.| -00000020 f4 15 b1 1c 84 0d 6d 74 87 ac 7d 20 78 17 8b 08 |......mt..} x...| -00000030 10 20 c9 44 e4 8a 43 af 4a c7 b8 3d 99 f2 f7 af |. .D..C.J..=....| -00000040 bb a3 21 2f 40 cc ed b6 da a8 a1 d5 c0 09 00 00 |..!/@...........| +00000000 16 03 03 00 59 02 00 00 55 03 03 b3 7f 4e e7 11 |....Y...U....N..| +00000010 6d bc 56 ec 9c a8 61 08 d6 5a 2a 42 7b f1 94 0a |m.V...a..Z*B{...| +00000020 29 35 8b 7e 23 a0 6c 59 23 cf 39 20 84 09 b6 5b |)5.~#.lY#.9 ...[| +00000030 2f 46 80 3b 26 92 fd 81 e9 24 8c e2 b8 64 a2 03 |/F.;&....$...d..| +00000040 3a 68 c3 7b 44 f8 28 41 e2 d3 6c 7c c0 09 00 00 |:h.{D.(A..l|....| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 03 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..| 00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....| @@ -47,24 +48,23 @@ 00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....| 00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.| 00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....| -00000270 2a 16 03 03 00 d8 0c 00 00 d4 03 00 17 41 04 a9 |*............A..| -00000280 19 8b d9 9b 5c 7c 6a 7d 85 d2 70 4e 89 7e 0b 5b |....\|j}..pN.~.[| -00000290 dd 5e a1 63 8d 15 bc 0b 0c 47 3d 4d e8 a7 56 88 |.^.c.....G=M..V.| -000002a0 2e f6 7f e2 4d fc ed cc 03 ed a1 2d ac ae 81 a5 |....M......-....| -000002b0 e2 6d 7f 9f a3 93 e9 10 c1 0e 48 1b f3 f4 38 04 |.m........H...8.| -000002c0 03 00 8b 30 81 88 02 42 00 87 fe 7e 63 82 14 57 |...0...B...~c..W| -000002d0 dc 7d e2 0f cc 97 2d ba 3c a7 56 4a 17 a8 09 6a |.}....-.<.VJ...j| -000002e0 28 2e f2 66 1a 3f 2d 48 2b 6f 79 a1 60 cd 5e 10 |(..f.?-H+oy.`.^.| -000002f0 0b 0a 28 f2 5f e4 3f 4f f9 c9 91 34 d9 dc bc fc |..(._.?O...4....| -00000300 98 ea 77 0b 99 f8 a2 11 c4 bd 02 42 01 a0 b0 dc |..w........B....| -00000310 db 5b c2 09 99 bd ee a0 b9 aa 31 b9 10 84 22 be |.[........1...".| -00000320 5a 63 12 5a 43 00 8e c1 33 cc 91 bb c2 70 7a 63 |Zc.ZC...3....pzc| -00000330 19 82 c0 74 48 a1 c7 3d 1f f1 6f 4a 6f 6a 8c 3f |...tH..=..oJoj.?| -00000340 28 31 a8 0c 65 19 26 62 4b 7a 7c 4b ea 1a 16 03 |(1..e.&bKz|K....| -00000350 03 00 30 0d 00 00 28 03 01 02 40 00 20 06 01 06 |..0...(...@. ...| -00000360 02 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 |................| -00000370 01 03 02 03 03 02 01 02 02 02 03 01 01 00 00 0e |................| -00000380 00 00 00 |...| +00000270 2a 16 03 03 00 d7 0c 00 00 d3 03 00 17 41 04 0f |*............A..| +00000280 4d b0 41 d4 dc 6b 8a 85 52 eb eb 18 4a 8f a7 e6 |M.A..k..R...J...| +00000290 24 52 e5 86 be 57 d7 0a e7 23 84 a8 a9 6c 96 08 |$R...W...#...l..| +000002a0 4b f7 47 32 79 d9 df 81 f6 05 40 63 3b 14 67 3b |K.G2y.....@c;.g;| +000002b0 ea 01 a0 0d 43 1a 36 29 b3 51 7a e4 af 1b 67 04 |....C.6).Qz...g.| +000002c0 03 00 8a 30 81 87 02 42 01 8e 57 8a b8 b7 5b 2f |...0...B..W...[/| +000002d0 9c 31 74 d8 7d 68 d7 6e 83 73 5f fb d0 cd de 66 |.1t.}h.n.s_....f| +000002e0 60 fa 0a 0a 15 0b 30 3b 08 b6 f1 3e 4f 20 13 62 |`.....0;...>O .b| +000002f0 b5 ff 86 81 dc 42 a1 4c af c8 ff b3 24 81 d8 e1 |.....B.L....$...| +00000300 d1 09 0c 32 11 92 5e dd 3f 87 02 41 76 a7 29 48 |...2..^.?..Av.)H| +00000310 52 68 1c 72 4d d5 39 bf fa 61 ec b2 27 ce 10 4e |Rh.rM.9..a..'..N| +00000320 86 12 3d 1e 04 9c 11 b7 b4 0c cf 98 9d 01 c3 93 |..=.............| +00000330 cf 83 9e 92 9a ca fd 8f b1 9f 1b 20 c4 fb a4 46 |........... ...F| +00000340 60 fc fd d5 33 b0 8f b5 b5 c8 a4 70 c5 16 03 03 |`...3......p....| +00000350 00 2e 0d 00 00 26 03 01 02 40 00 1e 06 01 06 02 |.....&...@......| +00000360 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 |................| +00000370 03 02 03 03 02 01 02 02 02 03 00 00 0e 00 00 00 |................| >>> Flow 3 (client to server) 00000000 16 03 03 01 fb 0b 00 01 f7 00 01 f4 00 01 f1 30 |...............0| 00000010 82 01 ed 30 82 01 58 a0 03 02 01 02 02 01 00 30 |...0..X........0| @@ -103,31 +103,31 @@ 00000220 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.| 00000230 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I| 00000240 a6 b5 68 1a 41 03 56 6b dc 5a 89 16 03 03 00 88 |..h.A.Vk.Z......| -00000250 0f 00 00 84 04 01 00 80 38 f2 16 e5 b5 86 16 62 |........8......b| -00000260 86 e1 7d 01 f1 a8 e1 f7 e7 85 b1 a0 17 ee 84 25 |..}............%| -00000270 cb 3c 46 61 1a 78 7b 1e ee 32 bc d9 6c fa 6b 76 |....| +00000280 85 3f ab b4 5c 2a 37 76 8b 28 56 08 4f 08 b9 51 |.?..\*7v.(V.O..Q| +00000290 71 14 07 27 47 45 11 a0 03 cf 72 7d 67 ef 31 8d |q..'GE....r}g.1.| +000002a0 e7 db 36 76 b1 b3 f4 bf aa 6c c4 56 94 35 71 e1 |..6v.....l.V.5q.| +000002b0 dd 88 6d 15 90 c8 70 ad d8 95 55 42 9b c1 45 19 |..m...p...UB..E.| +000002c0 36 ce 87 c6 fd 94 8a d4 98 6e ec 18 d5 da 59 54 |6........n....YT| +000002d0 80 a7 8c 90 ae 55 20 1c 14 03 03 00 01 01 16 03 |.....U .........| 000002e0 03 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00 |..@.............| -000002f0 00 00 00 5e e7 6e 1c a2 02 24 34 f0 a6 b6 27 ea |...^.n...$4...'.| -00000300 69 d5 0e 2e a8 ad 5c ad 6c 06 78 68 39 92 27 f1 |i.....\.l.xh9.'.| -00000310 e8 35 49 67 4d fb 5d 8a 31 2e 4e 3f 19 ed ea 30 |.5IgM.].1.N?...0| -00000320 20 60 e1 | `.| +000002f0 00 00 00 58 fe bc 5c ba b2 a9 96 77 2f 95 c9 10 |...X..\....w/...| +00000300 fd 6d fc 6a 88 8c df 82 c3 a4 3d cc 28 f4 bf 7d |.m.j......=.(..}| +00000310 4a f8 3d 97 36 e5 a0 76 92 94 da dd cc f5 e4 0e |J.=.6..v........| +00000320 7a c4 2c |z.,| >>> Flow 4 (server to client) -00000000 14 03 03 00 01 01 16 03 03 00 40 ee a8 82 bc 3f |..........@....?| -00000010 bf ab a6 e4 30 e0 3d f1 2f 19 a2 ac 7a 81 57 f1 |....0.=./...z.W.| -00000020 ee 67 3f 55 2b 30 fa 72 b5 10 03 ec 8d 0a 8f bb |.g?U+0.r........| -00000030 24 f5 45 f5 4e 53 4b 93 a5 0d 42 6c 46 69 98 fb |$.E.NSK...BlFi..| -00000040 63 c5 9f 95 65 d1 b6 f0 a4 15 bd |c...e......| +00000000 14 03 03 00 01 01 16 03 03 00 40 81 ab 5a 66 a8 |..........@..Zf.| +00000010 0f a5 d3 07 00 66 45 1f 31 a9 ef f7 a0 d9 23 46 |.....fE.1.....#F| +00000020 f0 3e 50 18 99 e3 5a bd eb b7 1d 81 d5 95 d5 ee |.>P...Z.........| +00000030 21 31 41 4b 19 92 b5 95 36 da 21 c0 4a 2a a0 1c |!1AK....6.!.J*..| +00000040 a3 9f 8e a0 6f 9d 37 5e 12 11 03 |....o.7^...| >>> Flow 5 (client to server) 00000000 17 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........| -00000010 00 00 00 00 00 cb 4e bc d1 a9 58 ef c8 39 a9 36 |......N...X..9.6| -00000020 f4 35 05 96 8e a4 50 bc f4 15 06 f9 fd 41 6d 1e |.5....P......Am.| -00000030 5e 7c 82 63 94 15 03 03 00 30 00 00 00 00 00 00 |^|.c.....0......| -00000040 00 00 00 00 00 00 00 00 00 00 bd 77 87 a5 5a d4 |...........w..Z.| -00000050 b8 59 e6 6b 0f dd ea f9 ed 18 b2 9f a9 61 b4 3a |.Y.k.........a.:| -00000060 47 15 15 3b 83 ef e1 6d db a8 |G..;...m..| +00000010 00 00 00 00 00 a9 51 94 19 72 ab 9f 3e 97 5e 99 |......Q..r..>.^.| +00000020 2c ec 13 48 3e 10 54 5f 8a 85 88 4d 1a a8 f5 ed |,..H>.T_...M....| +00000030 c3 4f a9 59 a3 15 03 03 00 30 00 00 00 00 00 00 |.O.Y.....0......| +00000040 00 00 00 00 00 00 00 00 00 00 25 00 6d 2f a0 f6 |..........%.m/..| +00000050 ce 8a 30 ba 53 da 97 c6 11 f3 d2 f3 9e 66 d6 dd |..0.S........f..| +00000060 19 f3 ee 07 03 d3 e6 f1 30 32 |........02| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA b/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA index df3eaa4406e..ff79aa236c5 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA +++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA @@ -1,18 +1,19 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......| +00000000 16 03 01 00 81 01 00 00 7d 03 03 00 00 00 00 00 |........}.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| -00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1a c0 2f |.............../| -00000030 c0 2b c0 11 c0 07 c0 13 c0 09 c0 14 c0 0a 00 05 |.+..............| -00000040 00 2f 00 35 c0 12 00 0a 01 00 00 2e 00 05 00 05 |./.5............| -00000050 01 00 00 00 00 00 0a 00 08 00 06 00 17 00 18 00 |................| -00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................| -00000070 03 02 01 02 03 ff 01 00 01 00 |..........| +00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1e c0 2f |.............../| +00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........| +00000040 c0 0a 00 05 00 2f 00 35 c0 12 00 0a 01 00 00 36 |...../.5.......6| +00000050 00 05 00 05 01 00 00 00 00 00 0a 00 08 00 06 00 |................| +00000060 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| +00000070 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| +00000080 01 00 00 12 00 00 |......| >>> Flow 2 (server to client) -00000000 16 03 03 00 51 02 00 00 4d 03 03 53 04 f1 02 1d |....Q...M..S....| -00000010 0e dc 86 e5 a9 07 71 46 15 34 af 47 15 3f 03 9c |......qF.4.G.?..| -00000020 fc d6 fd 44 7c f4 f1 c7 8d 6f f8 20 28 ea 3c dc |...D|....o. (.<.| -00000030 b2 4c b7 ba 20 88 c4 db a5 73 ea 93 ab 3a 85 a6 |.L.. ....s...:..| -00000040 8f 59 49 d9 a9 31 14 d5 a6 2b 4f d1 00 05 00 00 |.YI..1...+O.....| +00000000 16 03 03 00 51 02 00 00 4d 03 03 b3 b2 22 69 e4 |....Q...M...."i.| +00000010 1a a1 56 94 26 0c 43 b7 89 0c 34 ce dc 5a c8 ca |..V.&.C...4..Z..| +00000020 e2 42 92 5c 75 9a b3 22 22 64 38 20 6d 2c 26 0b |.B.\u..""d8 m,&.| +00000030 34 b6 b8 20 36 e2 58 e5 ee 1f e2 9f a0 75 f6 d9 |4.. 6.X......u..| +00000040 0c e4 39 ce 3c 8e 2e f8 e8 d1 a2 16 00 05 00 00 |..9.<...........| 00000050 05 ff 01 00 01 00 16 03 03 02 be 0b 00 02 ba 00 |................| 00000060 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......| 00000070 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..| @@ -57,10 +58,10 @@ 000002e0 50 56 5c d5 82 5a 2d 5a 5f 33 c4 b6 d8 c9 75 90 |PV\..Z-Z_3....u.| 000002f0 96 8c 0f 52 98 b5 cd 98 1f 89 20 5f f2 a0 1c a3 |...R...... _....| 00000300 1b 96 94 dd a9 fd 57 e9 70 e8 26 6d 71 99 9b 26 |......W.p.&mq..&| -00000310 6e 38 50 29 6c 90 a7 bd d9 16 03 03 00 30 0d 00 |n8P)l........0..| -00000320 00 28 03 01 02 40 00 20 06 01 06 02 06 03 05 01 |.(...@. ........| +00000310 6e 38 50 29 6c 90 a7 bd d9 16 03 03 00 2e 0d 00 |n8P)l...........| +00000320 00 26 03 01 02 40 00 1e 06 01 06 02 06 03 05 01 |.&...@..........| 00000330 05 02 05 03 04 01 04 02 04 03 03 01 03 02 03 03 |................| -00000340 02 01 02 02 02 03 01 01 00 00 0e 00 00 00 |..............| +00000340 02 01 02 02 02 03 00 00 0e 00 00 00 |............| >>> Flow 3 (client to server) 00000000 16 03 03 01 fb 0b 00 01 f7 00 01 f4 00 01 f1 30 |...............0| 00000010 82 01 ed 30 82 01 58 a0 03 02 01 02 02 01 00 30 |...0..X........0| @@ -103,24 +104,24 @@ 00000260 e6 bd 77 82 6f 23 b6 e0 bd a2 92 b7 3a ac e8 56 |..w.o#......:..V| 00000270 f1 af 54 5e 46 87 e9 3b 33 e7 b8 28 b7 d6 c8 90 |..T^F..;3..(....| 00000280 35 d4 1c 43 d1 30 6f 55 4e 0a 70 16 03 03 00 88 |5..C.0oUN.p.....| -00000290 0f 00 00 84 04 01 00 80 2a 1f ae 48 9f 86 16 dc |........*..H....| -000002a0 c2 55 1f 5f 95 81 ed 56 00 5d 35 46 e5 b6 57 d5 |.U._...V.]5F..W.| -000002b0 a6 3e 32 38 8b e2 c6 1c b9 b1 38 b2 da 66 45 ed |.>28......8..fE.| -000002c0 58 6a 7f 43 41 93 a5 09 da b9 04 ce 3f 13 8a 19 |Xj.CA.......?...| -000002d0 13 e9 2c 1f c5 e7 35 b4 2d ea 7c 81 90 33 c0 66 |..,...5.-.|..3.f| -000002e0 dc 41 8b 23 08 8f 69 d4 d6 a2 5f c1 bd 26 e6 2e |.A.#..i..._..&..| -000002f0 7f c8 7c a8 2d d4 08 95 ce 6e 58 54 04 a2 a6 63 |..|.-....nXT...c| -00000300 54 72 67 f2 7f 61 0a 6b 58 46 d4 88 95 38 37 f2 |Trg..a.kXF...87.| -00000310 93 95 48 56 14 a7 b9 7c 14 03 03 00 01 01 16 03 |..HV...|........| -00000320 03 00 24 64 bb 41 3a cb a2 2f 95 53 5c 2f f7 83 |..$d.A:../.S\/..| -00000330 a2 35 18 f6 d0 8d 6f e2 54 ed 2f 07 10 f4 36 e2 |.5....o.T./...6.| -00000340 3d e5 30 1d e3 63 01 |=.0..c.| +00000290 0f 00 00 84 05 01 00 80 01 24 8d bb 05 61 2d 29 |.........$...a-)| +000002a0 12 11 90 f5 57 21 be b7 29 76 55 63 94 8e 7b 4d |....W!..)vUc..{M| +000002b0 3b 3d 89 5b 1f b9 e1 8c 36 68 6f 31 21 50 af e4 |;=.[....6ho1!P..| +000002c0 9f ca a5 68 55 b9 eb 36 75 3a 0c be 11 30 28 c8 |...hU..6u:...0(.| +000002d0 8b 82 93 9a 71 37 4d 4e 4f d2 0c 2f 13 36 ad c3 |....q7MNO../.6..| +000002e0 df 8a 1b 59 b2 f9 8b a7 74 63 75 4a f4 9d e0 6b |...Y....tcuJ...k| +000002f0 42 02 5a a9 6e a4 a8 24 d3 23 f7 09 ee b0 dc c4 |B.Z.n..$.#......| +00000300 6f 87 58 72 e7 e3 87 b3 6b 15 ba 7f dd 9b 93 91 |o.Xr....k.......| +00000310 5b 21 a0 31 31 bd 15 b5 14 03 03 00 01 01 16 03 |[!.11...........| +00000320 03 00 24 fc 0e 7c e8 3e 8b b5 dc c9 3d 38 61 a1 |..$..|.>....=8a.| +00000330 24 d6 77 1f 06 1f 30 32 ba dd 05 68 45 f1 4f 0d |$.w...02...hE.O.| +00000340 2e 24 09 ad c1 e5 b7 |.$.....| >>> Flow 4 (server to client) -00000000 14 03 03 00 01 01 16 03 03 00 24 0a 22 b6 bc da |..........$."...| -00000010 34 38 53 8e 80 e2 25 7b 31 2f 70 8e 3a db e8 a3 |48S...%{1/p.:...| -00000020 70 0e 88 22 b4 a8 be d4 a3 e3 cc 13 94 ef 47 |p.."..........G| +00000000 14 03 03 00 01 01 16 03 03 00 24 d7 b6 b3 0a e6 |..........$.....| +00000010 86 9a 25 e4 38 de d0 57 ff 93 0b f4 de 76 3d 00 |..%.8..W.....v=.| +00000020 64 35 cf 70 f6 ea 74 2d b0 71 2d 92 e2 df eb |d5.p..t-.q-....| >>> Flow 5 (client to server) -00000000 17 03 03 00 1a b4 9c b1 57 ea 01 03 fe 01 e7 1e |........W.......| -00000010 c4 a7 0f 25 14 99 00 4f 88 51 c1 98 6e 99 01 15 |...%...O.Q..n...| -00000020 03 03 00 16 2e c4 11 8b 1a fc 37 81 18 33 e4 9f |..........7..3..| -00000030 48 a3 29 e3 ad 9b 9b ec 9f 99 |H.).......| +00000000 17 03 03 00 1a db bd 43 12 7c b5 83 b5 18 9d 6a |.......C.|.....j| +00000010 70 3f 5a eb cb d0 ba d4 03 3e a0 7b 25 f0 41 15 |p?Z......>.{%.A.| +00000020 03 03 00 16 f8 f2 a3 27 a5 c7 25 d9 6c 08 b1 96 |.......'..%.l...| +00000030 38 22 38 df 16 fb e2 9f 61 a3 |8"8.....a.| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES b/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES index 76445903bac..e700e16352a 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES +++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES @@ -1,18 +1,19 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......| +00000000 16 03 01 00 81 01 00 00 7d 03 03 00 00 00 00 00 |........}.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| -00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1a c0 2f |.............../| -00000030 c0 2b c0 11 c0 07 c0 13 c0 09 c0 14 c0 0a 00 05 |.+..............| -00000040 00 2f 00 35 c0 12 00 0a 01 00 00 2e 00 05 00 05 |./.5............| -00000050 01 00 00 00 00 00 0a 00 08 00 06 00 17 00 18 00 |................| -00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................| -00000070 03 02 01 02 03 ff 01 00 01 00 |..........| +00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1e c0 2f |.............../| +00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........| +00000040 c0 0a 00 05 00 2f 00 35 c0 12 00 0a 01 00 00 36 |...../.5.......6| +00000050 00 05 00 05 01 00 00 00 00 00 0a 00 08 00 06 00 |................| +00000060 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| +00000070 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| +00000080 01 00 00 12 00 00 |......| >>> Flow 2 (server to client) -00000000 16 03 03 00 59 02 00 00 55 03 03 53 04 f1 02 a0 |....Y...U..S....| -00000010 5f bd a4 8d 98 93 b8 da 08 86 9f b2 be 9a a4 91 |_...............| -00000020 2b 3c 1f 18 f0 75 7c a9 a8 a0 f7 20 4a 89 9a d2 |+<...u|.... J...| -00000030 34 3b d9 b1 c2 fd 61 bd 97 19 22 ce b9 d1 5b a7 |4;....a..."...[.| -00000040 83 80 9c 19 d0 f5 a0 aa 4c ac 06 20 c0 09 00 00 |........L.. ....| +00000000 16 03 03 00 59 02 00 00 55 03 03 21 9b eb 15 24 |....Y...U..!...$| +00000010 46 b6 c1 85 f5 be c5 0d e2 6b 60 bc ee 73 b1 fb |F........k`..s..| +00000020 34 6f f0 b8 f0 9e 1c 26 a4 4b 0f 20 cb 2b 84 a2 |4o.....&.K. .+..| +00000030 cb a5 48 70 fe 84 25 b0 16 20 14 a1 83 21 fc f9 |..Hp..%.. ...!..| +00000040 82 fc 9e 1a d1 3b 56 69 ab c5 0e 2c c0 09 00 00 |.....;Vi...,....| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 03 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..| 00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....| @@ -47,21 +48,21 @@ 00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....| 00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.| 00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....| -00000270 2a 16 03 03 00 d7 0c 00 00 d3 03 00 17 41 04 3c |*............A.<| -00000280 8f 35 1e 47 5d 7b ad 13 0c e9 5c c0 97 c7 83 06 |.5.G]{....\.....| -00000290 49 0f 6c cf e5 4d 3b ed f7 1b c6 96 8d ba 54 35 |I.l..M;.......T5| -000002a0 7f df 35 e3 6e 28 e9 71 f2 24 b5 ab 17 2b 4b 2b |..5.n(.q.$...+K+| -000002b0 0c 8f 9f 48 89 73 8f 09 69 84 af 7f ec 43 7a 04 |...H.s..i....Cz.| -000002c0 03 00 8a 30 81 87 02 41 79 84 43 0c 78 fa 7e e2 |...0...Ay.C.x.~.| -000002d0 c5 51 c1 60 88 c4 4a 59 7d 02 fa dc 19 68 33 ed |.Q.`..JY}....h3.| -000002e0 19 ef a1 df ef 6b 21 a6 98 aa ba a9 13 70 91 0f |.....k!......p..| -000002f0 cc 6c 5c 1e 99 53 1b 42 51 6c 06 a7 3c c4 04 22 |.l\..S.BQl..<.."| -00000300 5d 0d c1 30 ab e3 ec b4 54 02 42 01 15 15 1a 6e |]..0....T.B....n| -00000310 6f f1 c6 b1 10 84 2c c8 04 de 2b 52 d5 b4 f7 c9 |o.....,...+R....| -00000320 4f 6d 0e 0e 26 45 1d 7a 28 59 2b 8b f6 92 3a 23 |Om..&E.z(Y+...:#| -00000330 7a 39 9c d5 4e cc 5d c5 45 92 9c d0 5f 33 12 e3 |z9..N.].E..._3..| -00000340 2b 29 39 52 bb 16 aa e1 72 9e b5 fe 99 16 03 03 |+)9R....r.......| -00000350 00 04 0e 00 00 00 |......| +00000270 2a 16 03 03 00 d8 0c 00 00 d4 03 00 17 41 04 b6 |*............A..| +00000280 3f 37 33 68 cb 79 c0 86 f4 9d 12 ac c4 9d 8c 9b |?73h.y..........| +00000290 59 1c d4 a9 01 9f 2d cb 80 24 02 ec e0 ff d1 8c |Y.....-..$......| +000002a0 bd 82 67 3f 47 58 1a 2e 6b 61 f6 8e 4e 27 7f 49 |..g?GX..ka..N'.I| +000002b0 b5 45 f1 0b 9a 33 ff 53 ac 65 e2 82 7a 18 5c 04 |.E...3.S.e..z.\.| +000002c0 03 00 8b 30 81 88 02 42 00 e1 2d ff 5d e7 77 f1 |...0...B..-.].w.| +000002d0 12 d9 e4 c2 4d cd 9c b5 ee e4 fd 21 b2 d8 53 a9 |....M......!..S.| +000002e0 42 e7 c5 9b 51 c3 59 37 a5 08 d4 e6 29 12 c5 56 |B...Q.Y7....)..V| +000002f0 b8 fe f0 bb 77 87 a3 ee 09 b0 8c cd 1c 39 9e b5 |....w........9..| +00000300 d9 15 63 53 cb d7 f1 55 5b 48 02 42 01 19 10 8a |..cS...U[H.B....| +00000310 7a ee 95 b1 77 44 d4 a3 bf d1 f3 f1 b0 d8 c7 7e |z...wD.........~| +00000320 42 c0 83 04 f5 f7 9c c0 ce 6a 98 47 9d 21 29 84 |B........j.G.!).| +00000330 c8 be 6b 67 4e fc c6 26 ec 63 df 00 33 e6 d2 f7 |..kgN..&.c..3...| +00000340 34 93 85 9b 1b 0f e0 89 42 b6 0b 94 1b 80 16 03 |4.......B.......| +00000350 03 00 04 0e 00 00 00 |.......| >>> Flow 3 (client to server) 00000000 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..| 00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.| @@ -69,21 +70,21 @@ 00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I| 00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 03 00 01 |..h.A.Vk.Z......| 00000050 01 16 03 03 00 40 00 00 00 00 00 00 00 00 00 00 |.....@..........| -00000060 00 00 00 00 00 00 20 a3 f8 5a e2 ea f3 09 19 3e |...... ..Z.....>| -00000070 4a 54 69 70 06 5b 17 35 0f ed e7 30 3b 6f eb a1 |JTip.[.5...0;o..| -00000080 cb 9c 35 81 10 2e 34 f7 12 a5 e4 63 20 b2 65 31 |..5...4....c .e1| -00000090 19 da 30 43 39 59 |..0C9Y| +00000060 00 00 00 00 00 00 50 73 9c 9f a8 d7 78 ac 06 14 |......Ps....x...| +00000070 8f ae fc fb ef 7d 99 db b7 c9 91 dd f2 fe da 1b |.....}..........| +00000080 aa 9e 7d e4 5c 2f 5f dd 74 aa fe 03 51 e7 cd 98 |..}.\/_.t...Q...| +00000090 e9 21 19 c9 6f 59 |.!..oY| >>> Flow 4 (server to client) -00000000 14 03 03 00 01 01 16 03 03 00 40 8d 4d 31 07 df |..........@.M1..| -00000010 ab 41 f5 19 9c 1a 57 fc 33 ab 5f e6 bd 45 b9 fa |.A....W.3._..E..| -00000020 7f db c0 df 72 f2 3b ef aa d4 5e 34 e6 3d 44 7c |....r.;...^4.=D|| -00000030 12 05 c7 57 da 54 b1 e3 66 f0 0a ab cd 15 a5 bf |...W.T..f.......| -00000040 c5 c2 07 a9 d9 a7 2e 5e 29 da da |.......^)..| +00000000 14 03 03 00 01 01 16 03 03 00 40 47 18 b5 1b 75 |..........@G...u| +00000010 b8 a3 63 ab 77 d3 47 cb 14 26 b4 88 fe 15 db 22 |..c.w.G..&....."| +00000020 76 3b 25 d3 68 8e f2 a7 d5 03 2b 82 7b b1 0f 10 |v;%.h.....+.{...| +00000030 49 6a 3d 95 d0 4b 55 0e 14 eb bb a7 34 bb 57 b3 |Ij=..KU.....4.W.| +00000040 5d fb 7e 15 80 5a fa f3 3a df 90 |].~..Z..:..| >>> Flow 5 (client to server) 00000000 17 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........| -00000010 00 00 00 00 00 dc 03 7b 29 2c 49 64 58 2d dc f7 |.......{),IdX-..| -00000020 26 a1 3b ec 2d e8 30 c4 6c a3 ff e2 bc b5 a4 a6 |&.;.-.0.l.......| -00000030 93 ce 14 bd da 15 03 03 00 30 00 00 00 00 00 00 |.........0......| -00000040 00 00 00 00 00 00 00 00 00 00 a6 77 10 30 15 eb |...........w.0..| -00000050 ed cf 73 5b 74 5d 09 52 4a 5b e2 f0 e4 67 f8 7a |..s[t].RJ[...g.z| -00000060 5e 5e fc ba 7f 80 0a d2 f4 fb |^^........| +00000010 00 00 00 00 00 70 74 e2 60 fc 3a 7a b7 5e 16 07 |.....pt.`.:z.^..| +00000020 22 92 07 fe 92 53 c4 43 1b 8f 94 07 84 48 2b 50 |"....S.C.....H+P| +00000030 ab 1d 6d 49 ed 15 03 03 00 30 00 00 00 00 00 00 |..mI.....0......| +00000040 00 00 00 00 00 00 00 00 00 00 ce a8 ba 91 0b e4 |................| +00000050 8c 38 23 9b 8b 2c 0a 0c 63 79 61 f4 b6 25 f7 41 |.8#..,..cya..%.A| +00000060 04 9f b0 8f e0 e5 24 44 2f e9 |......$D/.| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM b/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM index fb5af17f0c4..607ecdcb240 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM +++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM @@ -1,18 +1,19 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......| +00000000 16 03 01 00 81 01 00 00 7d 03 03 00 00 00 00 00 |........}.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| -00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1a c0 2f |.............../| -00000030 c0 2b c0 11 c0 07 c0 13 c0 09 c0 14 c0 0a 00 05 |.+..............| -00000040 00 2f 00 35 c0 12 00 0a 01 00 00 2e 00 05 00 05 |./.5............| -00000050 01 00 00 00 00 00 0a 00 08 00 06 00 17 00 18 00 |................| -00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................| -00000070 03 02 01 02 03 ff 01 00 01 00 |..........| +00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1e c0 2f |.............../| +00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........| +00000040 c0 0a 00 05 00 2f 00 35 c0 12 00 0a 01 00 00 36 |...../.5.......6| +00000050 00 05 00 05 01 00 00 00 00 00 0a 00 08 00 06 00 |................| +00000060 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| +00000070 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| +00000080 01 00 00 12 00 00 |......| >>> Flow 2 (server to client) -00000000 16 03 03 00 59 02 00 00 55 03 03 53 04 f1 02 48 |....Y...U..S...H| -00000010 03 36 01 05 56 6f f0 54 d2 c3 d3 41 c2 e2 69 7b |.6..Vo.T...A..i{| -00000020 50 f8 03 ef 3f 5d 7c e6 9c cb fe 20 82 a0 81 fd |P...?]|.... ....| -00000030 72 4b b8 e6 29 76 3b 0f 1d 0a b7 82 9d 0b cf a0 |rK..)v;.........| -00000040 65 b1 56 53 c9 d5 58 7b f0 b6 2d cf c0 2b 00 00 |e.VS..X{..-..+..| +00000000 16 03 03 00 59 02 00 00 55 03 03 91 8a 4f 94 29 |....Y...U....O.)| +00000010 32 fa 66 7a 7f b8 a7 04 5c 34 b9 7e 12 83 35 1f |2.fz....\4.~..5.| +00000020 93 b0 af e0 9f 71 07 5e 2f d7 ca 20 52 dc 0d e7 |.....q.^/.. R...| +00000030 f8 16 db 90 9a 78 2f 03 0b f0 ae a7 2f c6 b4 4c |.....x/...../..L| +00000040 62 e7 de 32 d5 68 61 f3 07 e4 60 d2 c0 2b 00 00 |b..2.ha...`..+..| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 03 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..| 00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....| @@ -47,38 +48,38 @@ 00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....| 00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.| 00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....| -00000270 2a 16 03 03 00 d7 0c 00 00 d3 03 00 17 41 04 86 |*............A..| -00000280 36 b4 78 76 87 70 ed ae 0d 34 70 3d 16 e5 a4 db |6.xv.p...4p=....| -00000290 ae 28 58 4c 01 5a 56 73 a7 0d 34 59 a7 04 75 69 |.(XL.ZVs..4Y..ui| -000002a0 f2 55 24 40 b0 33 c6 93 ff ae e0 14 f5 4b ce a8 |.U$@.3.......K..| -000002b0 e2 e6 9a 67 1d 66 fb 8f fd 56 59 e7 73 f2 2c 04 |...g.f...VY.s.,.| -000002c0 03 00 8a 30 81 87 02 41 73 ab a8 3c 64 17 69 9f |...0...As..>> Flow 3 (client to server) 00000000 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..| 00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.| 00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.| 00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I| 00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 03 00 01 |..h.A.Vk.Z......| -00000050 01 16 03 03 00 28 00 00 00 00 00 00 00 00 87 7a |.....(.........z| -00000060 82 d7 46 25 1d a6 bb c2 a8 a8 4e a5 d1 f8 02 db |..F%......N.....| -00000070 33 33 ca 78 b6 d3 bd 77 8a 33 23 a7 95 fb |33.x...w.3#...| +00000050 01 16 03 03 00 28 00 00 00 00 00 00 00 00 83 cf |.....(..........| +00000060 ef 50 c2 e7 da b9 74 7f 1c e0 b8 fb dc 39 c9 98 |.P....t......9..| +00000070 0c a3 7d 8c c6 fa 6f f2 ee 44 a0 a0 03 18 |..}...o..D....| >>> Flow 4 (server to client) -00000000 14 03 03 00 01 01 16 03 03 00 28 ce a1 9d 01 c0 |..........(.....| -00000010 31 e5 d5 57 16 e1 a6 b3 8b 25 58 0f fa 2a de 3e |1..W.....%X..*.>| -00000020 0c d9 06 11 a6 b0 d7 b0 33 ad 31 73 5b 26 b4 d2 |........3.1s[&..| -00000030 12 56 c8 |.V.| +00000000 14 03 03 00 01 01 16 03 03 00 28 73 c4 48 24 3d |..........(s.H$=| +00000010 8f 5f f3 8c fc fd 63 be 64 39 d5 56 67 bd d7 c4 |._....c.d9.Vg...| +00000020 0d 57 88 1a 45 a6 f3 ad 11 b2 5a 41 58 33 f3 d3 |.W..E.....ZAX3..| +00000030 58 fa 21 |X.!| >>> Flow 5 (client to server) -00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 d5 04 4c |...............L| -00000010 7b 35 b4 d7 90 ae fe 00 d2 f2 4b 76 f1 36 5e 24 |{5........Kv.6^$| -00000020 4a aa 94 15 03 03 00 1a 00 00 00 00 00 00 00 02 |J...............| -00000030 d3 1c 41 37 ab f6 17 79 f0 01 a4 19 a5 75 7a 8e |..A7...y.....uz.| -00000040 a3 b2 |..| +00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 65 5e 55 |.............e^U| +00000010 32 be 00 77 6e 1d 8e 8f 95 33 24 3d 7a c2 b0 3f |2..wn....3$=z..?| +00000020 ca aa 97 15 03 03 00 1a 00 00 00 00 00 00 00 02 |................| +00000030 b2 71 6e 42 6a 0d cf c9 ac 14 a4 b5 9c c9 71 60 |.qnBj.........q`| +00000040 d7 c2 |..| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES256-GCM-SHA384 b/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES256-GCM-SHA384 new file mode 100644 index 00000000000..df2f7376de8 --- /dev/null +++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES256-GCM-SHA384 @@ -0,0 +1,85 @@ +>>> Flow 1 (client to server) +00000000 16 03 01 00 81 01 00 00 7d 03 03 00 00 00 00 00 |........}.......| +00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1e c0 2f |.............../| +00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........| +00000040 c0 0a 00 05 00 2f 00 35 c0 12 00 0a 01 00 00 36 |...../.5.......6| +00000050 00 05 00 05 01 00 00 00 00 00 0a 00 08 00 06 00 |................| +00000060 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| +00000070 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| +00000080 01 00 00 12 00 00 |......| +>>> Flow 2 (server to client) +00000000 16 03 03 00 59 02 00 00 55 03 03 11 50 81 a7 ef |....Y...U...P...| +00000010 3f bd a5 a9 41 11 e6 86 b2 a3 d8 bf 29 c3 d4 f4 |?...A.......)...| +00000020 b6 20 2d cb 94 1b 0e dd 99 d1 0b 20 78 92 23 31 |. -........ x.#1| +00000030 e3 fc 99 67 1f fd f3 2a fc 9c 4c 74 6e 32 e4 f8 |...g...*..Ltn2..| +00000040 ed 6d 2e 6d ad a9 a9 bf 63 27 7e 44 c0 2c 00 00 |.m.m....c'~D.,..| +00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| +00000060 03 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..| +00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....| +00000080 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 0b 30 |0...*.H.=..0E1.0| +00000090 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 |...U....AU1.0...| +000000a0 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 |U....Some-State1| +000000b0 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e |!0...U....Intern| +000000c0 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c |et Widgits Pty L| +000000d0 74 64 30 1e 17 0d 31 32 31 31 32 32 31 35 30 36 |td0...1211221506| +000000e0 33 32 5a 17 0d 32 32 31 31 32 30 31 35 30 36 33 |32Z..22112015063| +000000f0 32 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 41 |2Z0E1.0...U....A| +00000100 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d 65 |U1.0...U....Some| +00000110 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a 13 |-State1!0...U...| +00000120 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 74 |.Internet Widgit| +00000130 73 20 50 74 79 20 4c 74 64 30 81 9b 30 10 06 07 |s Pty Ltd0..0...| +00000140 2a 86 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 |*.H.=....+...#..| +00000150 86 00 04 00 c4 a1 ed be 98 f9 0b 48 73 36 7e c3 |...........Hs6~.| +00000160 16 56 11 22 f2 3d 53 c3 3b 4d 21 3d cd 6b 75 e6 |.V.".=S.;M!=.ku.| +00000170 f6 b0 dc 9a df 26 c1 bc b2 87 f0 72 32 7c b3 64 |.....&.....r2|.d| +00000180 2f 1c 90 bc ea 68 23 10 7e fe e3 25 c0 48 3a 69 |/....h#.~..%.H:i| +00000190 e0 28 6d d3 37 00 ef 04 62 dd 0d a0 9c 70 62 83 |.(m.7...b....pb.| +000001a0 d8 81 d3 64 31 aa 9e 97 31 bd 96 b0 68 c0 9b 23 |...d1...1...h..#| +000001b0 de 76 64 3f 1a 5c 7f e9 12 0e 58 58 b6 5f 70 dd |.vd?.\....XX._p.| +000001c0 9b d8 ea d5 d7 f5 d5 cc b9 b6 9f 30 66 5b 66 9a |...........0f[f.| +000001d0 20 e2 27 e5 bf fe 3b 30 09 06 07 2a 86 48 ce 3d | .'...;0...*.H.=| +000001e0 04 01 03 81 8c 00 30 81 88 02 42 01 88 a2 4f eb |......0...B...O.| +000001f0 e2 45 c5 48 7d 1b ac f5 ed 98 9d ae 47 70 c0 5e |.E.H}.......Gp.^| +00000200 1b b6 2f bd f1 b6 4d b7 61 40 d3 11 a2 ce ee 0b |../...M.a@......| +00000210 7e 92 7e ff 76 9d c3 3b 7e a5 3f ce fa 10 e2 59 |~.~.v..;~.?....Y| +00000220 ec 47 2d 7c ac da 4e 97 0e 15 a0 6f d0 02 42 01 |.G-|..N....o..B.| +00000230 4d fc be 67 13 9c 2d 05 0e bd 3f a3 8c 25 c1 33 |M..g..-...?..%.3| +00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....| +00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.| +00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....| +00000270 2a 16 03 03 00 d7 0c 00 00 d3 03 00 17 41 04 fc |*............A..| +00000280 e6 25 27 3c 76 10 a8 9e d3 a4 a8 68 31 06 85 fc |.%'>> Flow 3 (client to server) +00000000 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..| +00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.| +00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.| +00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I| +00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 03 00 01 |..h.A.Vk.Z......| +00000050 01 16 03 03 00 28 00 00 00 00 00 00 00 00 a3 3f |.....(.........?| +00000060 be 65 91 cd fe 37 43 e0 ea 6f 15 9d c2 aa 6a 02 |.e...7C..o....j.| +00000070 20 b8 bc b5 c8 9a 1c d4 c4 e5 9b 2e 39 e7 | ...........9.| +>>> Flow 4 (server to client) +00000000 14 03 03 00 01 01 16 03 03 00 28 7c b7 1f 13 9e |..........(|....| +00000010 21 d2 eb db 32 fc 36 d0 53 e1 11 04 ce d0 61 33 |!...2.6.S.....a3| +00000020 1e 30 3d 91 c3 6a 0d 98 55 f5 e0 5c ca 77 fa 72 |.0=..j..U..\.w.r| +00000030 63 6a be |cj.| +>>> Flow 5 (client to server) +00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 d9 db db |................| +00000010 4b 3a ae 5c a4 dc 96 33 ed b5 a0 70 64 1f 96 2f |K:.\...3...pd../| +00000020 b6 cd 1e 15 03 03 00 1a 00 00 00 00 00 00 00 02 |................| +00000030 18 a0 d1 98 a6 71 c9 56 36 bd 1a 46 4b 5b 45 29 |.....q.V6..FK[E)| +00000040 1f dd |..| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES b/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES index 5336bbbad8f..994ebb1e37f 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES +++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES @@ -1,18 +1,19 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......| +00000000 16 03 01 00 81 01 00 00 7d 03 03 00 00 00 00 00 |........}.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| -00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1a c0 2f |.............../| -00000030 c0 2b c0 11 c0 07 c0 13 c0 09 c0 14 c0 0a 00 05 |.+..............| -00000040 00 2f 00 35 c0 12 00 0a 01 00 00 2e 00 05 00 05 |./.5............| -00000050 01 00 00 00 00 00 0a 00 08 00 06 00 17 00 18 00 |................| -00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................| -00000070 03 02 01 02 03 ff 01 00 01 00 |..........| +00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1e c0 2f |.............../| +00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........| +00000040 c0 0a 00 05 00 2f 00 35 c0 12 00 0a 01 00 00 36 |...../.5.......6| +00000050 00 05 00 05 01 00 00 00 00 00 0a 00 08 00 06 00 |................| +00000060 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| +00000070 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| +00000080 01 00 00 12 00 00 |......| >>> Flow 2 (server to client) -00000000 16 03 03 00 59 02 00 00 55 03 03 53 04 f1 02 41 |....Y...U..S...A| -00000010 95 cc 56 30 65 46 24 75 d5 9e 3c a7 5b 6c 99 fe |..V0eF$u..<.[l..| -00000020 86 35 23 42 3a 8f 4d 4c b9 98 7d 20 a7 46 43 72 |.5#B:.ML..} .FCr| -00000030 66 bb b6 ad ff ad cf 63 37 fe 6b b4 78 94 08 49 |f......c7.k.x..I| -00000040 54 06 ed f4 85 73 38 4a c6 fe b6 98 c0 13 00 00 |T....s8J........| +00000000 16 03 03 00 59 02 00 00 55 03 03 e6 ae 89 0d 22 |....Y...U......"| +00000010 e5 e0 cd 57 a3 ca 71 4f 17 2f 64 77 f8 30 89 ef |...W..qO./dw.0..| +00000020 e8 19 70 ac dd 2c c5 9f 84 7d 1d 20 1c 59 3c fe |..p..,...}. .Y<.| +00000030 a9 ec 10 dd 38 3b 43 fe 6b 09 e5 e4 83 d9 7a 78 |....8;C.k.....zx| +00000040 86 08 33 da 9b e1 09 d8 c9 07 34 19 c0 13 00 00 |..3.......4.....| 00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................| 00000060 03 02 be 0b 00 02 ba 00 02 b7 00 02 b4 30 82 02 |.............0..| 00000070 b0 30 82 02 19 a0 03 02 01 02 02 09 00 85 b0 bb |.0..............| @@ -58,20 +59,20 @@ 000002f0 5f 33 c4 b6 d8 c9 75 90 96 8c 0f 52 98 b5 cd 98 |_3....u....R....| 00000300 1f 89 20 5f f2 a0 1c a3 1b 96 94 dd a9 fd 57 e9 |.. _..........W.| 00000310 70 e8 26 6d 71 99 9b 26 6e 38 50 29 6c 90 a7 bd |p.&mq..&n8P)l...| -00000320 d9 16 03 03 00 cd 0c 00 00 c9 03 00 17 41 04 48 |.............A.H| -00000330 68 d8 8a 10 b4 bf eb 8d d1 98 b0 a6 f4 47 5d 91 |h............G].| -00000340 61 da 50 d9 85 7b 5d 90 02 2c 38 c9 af 81 d3 55 |a.P..{]..,8....U| -00000350 07 62 b1 62 58 7f 39 94 d7 91 96 a8 1f 47 60 a5 |.b.bX.9......G`.| -00000360 c0 04 f2 fb cb 15 75 a6 16 3f 94 53 7c ff dd 04 |......u..?.S|...| -00000370 01 00 80 b9 82 fa 0b f8 8c 94 2c 6e 05 81 7d 80 |..........,n..}.| -00000380 5d 9a 77 78 af c8 33 5d 89 7e 2e 3c e5 72 66 a8 |].wx..3].~.<.rf.| -00000390 f1 5c 02 04 02 70 76 7b 45 ff 0d 29 a0 cb 0d db |.\...pv{E..)....| -000003a0 7a 4c c4 13 19 cd 47 b2 f1 c9 43 4f 95 d2 f1 c6 |zL....G...CO....| -000003b0 bc ae 31 4a 9d de 80 b2 a4 b7 b6 dd 8c 03 3e 2a |..1J..........>*| -000003c0 46 5e d1 e7 5b c5 9e 06 58 f3 55 b2 77 09 f3 98 |F^..[...X.U.w...| -000003d0 d5 7f 5a 74 64 7e 48 22 8f 7d a8 68 b6 1d 90 df |..Ztd~H".}.h....| -000003e0 2c 91 d7 c5 07 3d d1 6f e9 c1 91 03 3c 23 5a 56 |,....=.o....<#ZV| -000003f0 3b b2 c2 16 03 03 00 04 0e 00 00 00 |;...........| +00000320 d9 16 03 03 00 cd 0c 00 00 c9 03 00 17 41 04 77 |.............A.w| +00000330 87 a7 ad f6 f8 34 82 05 ef bb 14 6d c7 8b 7b 2a |.....4.....m..{*| +00000340 4d ca 41 65 58 3c 83 fa 4d ce 0c 74 46 85 fe 38 |M.AeX<..M..tF..8| +00000350 95 80 ee 7c c2 bf f2 be a3 c6 bf f3 aa 07 23 40 |...|..........#@| +00000360 7e cc 74 4a 4e 2e 69 af 6b e0 42 8a fc 41 be 04 |~.tJN.i.k.B..A..| +00000370 01 00 80 99 ed a8 3a ef 93 1b 4c 17 80 9e cc eb |......:...L.....| +00000380 da 39 fb c8 9a 73 e1 96 20 3e 41 fa 8b 1a b1 68 |.9...s.. >A....h| +00000390 cd 47 bc 4b 7b 0c 14 da 87 d3 36 09 5e 37 33 88 |.G.K{.....6.^73.| +000003a0 7f 88 07 87 46 ec e5 72 a8 59 92 07 fa 4d 02 dc |....F..r.Y...M..| +000003b0 bf 3a f5 e4 77 0b a6 85 ce 43 ee 1b 90 30 7f ec |.:..w....C...0..| +000003c0 88 79 f8 88 59 af 6b 7f 2d 88 de 92 cd c8 36 cf |.y..Y.k.-.....6.| +000003d0 ba b9 08 6a c4 3d d7 9a 48 50 e1 67 d0 62 a5 b3 |...j.=..HP.g.b..| +000003e0 b0 5f 2e 16 ee 4d 7d a2 cf d9 93 19 89 b7 64 0f |._...M}.......d.| +000003f0 0f 8e 3d 16 03 03 00 04 0e 00 00 00 |..=.........| >>> Flow 3 (client to server) 00000000 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..| 00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.| @@ -79,21 +80,21 @@ 00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I| 00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 03 00 01 |..h.A.Vk.Z......| 00000050 01 16 03 03 00 40 00 00 00 00 00 00 00 00 00 00 |.....@..........| -00000060 00 00 00 00 00 00 59 e6 92 05 27 ec 09 2c b0 a5 |......Y...'..,..| -00000070 2a fb 7e f1 03 53 16 63 68 a1 86 13 bb da 98 27 |*.~..S.ch......'| -00000080 6d 42 08 35 6a ec 58 61 2a 4d 44 ec ae c5 b9 d2 |mB.5j.Xa*MD.....| -00000090 76 57 1f 75 9f 8d |vW.u..| +00000060 00 00 00 00 00 00 f2 20 58 ec f1 88 a6 26 79 9d |....... X....&y.| +00000070 2e 9b 02 b5 5e da e2 c1 c5 8d c8 93 6f 6d 07 4e |....^.......om.N| +00000080 fa dd ee cb b1 ae c7 3b 09 b2 cc 64 7a cd 98 91 |.......;...dz...| +00000090 cb f8 3c 34 3b ed |..<4;.| >>> Flow 4 (server to client) -00000000 14 03 03 00 01 01 16 03 03 00 40 6e 03 d0 e6 98 |..........@n....| -00000010 1f f5 39 7b 06 9f 95 f0 7a 88 35 7c 55 db c3 2f |..9{....z.5|U../| -00000020 00 ef 5b d3 62 87 a2 94 da 2f f6 4a 89 c9 a8 3d |..[.b..../.J...=| -00000030 3a 92 db 77 35 92 01 4b f5 c5 6b 95 09 9f cd 79 |:..w5..K..k....y| -00000040 3c af 37 5b 27 bf 93 3e 04 55 71 |<.7['..>.Uq| +00000000 14 03 03 00 01 01 16 03 03 00 40 4c a1 8d bd 49 |..........@L...I| +00000010 33 d3 72 fb 2f 23 7e 11 29 fc d2 ff 9b 67 30 c8 |3.r./#~.)....g0.| +00000020 be c1 bc 51 6e 92 a5 f4 9d e3 b3 f9 d2 d4 c4 a5 |...Qn...........| +00000030 83 23 90 b3 17 00 35 18 c5 ef 8b 18 a3 cf ed 9d |.#....5.........| +00000040 a9 52 c9 11 0a c9 55 c2 76 df 78 |.R....U.v.x| >>> Flow 5 (client to server) 00000000 17 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........| -00000010 00 00 00 00 00 bc c9 d0 8e 80 14 de 32 18 49 e8 |............2.I.| -00000020 20 dc 5e 6c e4 6d 14 00 df 51 71 fb 86 95 16 4c | .^l.m...Qq....L| -00000030 04 8e 71 e1 48 15 03 03 00 30 00 00 00 00 00 00 |..q.H....0......| -00000040 00 00 00 00 00 00 00 00 00 00 b7 6d 30 72 61 53 |...........m0raS| -00000050 d8 0a d4 1d ae e5 d4 22 46 c9 d5 4e 4a 86 f5 ac |......."F..NJ...| -00000060 72 98 c6 db 38 29 97 2c 84 0b |r...8).,..| +00000010 00 00 00 00 00 60 40 d0 bf 8f ef 05 2b 89 d7 bb |.....`@.....+...| +00000020 27 d0 1f b2 cf c3 ff 8e be 69 16 a9 b3 03 e8 3c |'........i.....<| +00000030 30 1d 58 39 4a 15 03 03 00 30 00 00 00 00 00 00 |0.X9J....0......| +00000040 00 00 00 00 00 00 00 00 00 00 de 61 51 a1 3c fc |...........aQ.<.| +00000050 1c 7b e6 f2 7d e0 aa 80 2d 9c e9 22 09 5c dd 8a |.{..}...-..".\..| +00000060 55 cc c4 77 34 97 05 88 98 d3 |U..w4.....| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-RSA-RC4 b/libgo/go/crypto/tls/testdata/Client-TLSv12-RSA-RC4 index 0377f052ae6..73e34c0ce35 100644 --- a/libgo/go/crypto/tls/testdata/Client-TLSv12-RSA-RC4 +++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-RSA-RC4 @@ -1,18 +1,19 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 75 01 00 00 71 03 03 00 00 00 00 00 |....u...q.......| +00000000 16 03 01 00 81 01 00 00 7d 03 03 00 00 00 00 00 |........}.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| -00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1a c0 2f |.............../| -00000030 c0 2b c0 11 c0 07 c0 13 c0 09 c0 14 c0 0a 00 05 |.+..............| -00000040 00 2f 00 35 c0 12 00 0a 01 00 00 2e 00 05 00 05 |./.5............| -00000050 01 00 00 00 00 00 0a 00 08 00 06 00 17 00 18 00 |................| -00000060 19 00 0b 00 02 01 00 00 0d 00 0a 00 08 04 01 04 |................| -00000070 03 02 01 02 03 ff 01 00 01 00 |..........| +00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1e c0 2f |.............../| +00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........| +00000040 c0 0a 00 05 00 2f 00 35 c0 12 00 0a 01 00 00 36 |...../.5.......6| +00000050 00 05 00 05 01 00 00 00 00 00 0a 00 08 00 06 00 |................| +00000060 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| +00000070 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| +00000080 01 00 00 12 00 00 |......| >>> Flow 2 (server to client) -00000000 16 03 03 00 51 02 00 00 4d 03 03 53 04 f1 02 9d |....Q...M..S....| -00000010 2e 4e d9 17 4a 35 fa 9d 94 f6 45 0a f6 6b 5d 1c |.N..J5....E..k].| -00000020 1e 15 19 8d 6d 94 cc 90 d9 39 94 20 8b 4b de 76 |....m....9. .K.v| -00000030 d5 64 5d b7 19 df e7 eb 7e a0 22 c4 09 38 a0 12 |.d].....~."..8..| -00000040 d5 59 10 c8 31 06 dc fc e4 9d d1 80 00 05 00 00 |.Y..1...........| +00000000 16 03 03 00 51 02 00 00 4d 03 03 e8 ae 4c 97 41 |....Q...M....L.A| +00000010 78 0f 08 84 d4 4a 80 6d a2 e1 d0 67 40 8f 01 8b |x....J.m...g@...| +00000020 20 54 cb 28 16 52 04 fd 3c c2 84 20 30 96 f0 51 | T.(.R..<.. 0..Q| +00000030 72 86 6a d8 47 b9 47 e3 a4 ad 97 77 a9 77 1a f9 |r.j.G.G....w.w..| +00000040 ba 63 33 32 4f 43 09 1c e1 bd 1b 3b 00 05 00 00 |.c32OC.....;....| 00000050 05 ff 01 00 01 00 16 03 03 02 be 0b 00 02 ba 00 |................| 00000060 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......| 00000070 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..| @@ -69,15 +70,15 @@ 00000060 e6 bd 77 82 6f 23 b6 e0 bd a2 92 b7 3a ac e8 56 |..w.o#......:..V| 00000070 f1 af 54 5e 46 87 e9 3b 33 e7 b8 28 b7 d6 c8 90 |..T^F..;3..(....| 00000080 35 d4 1c 43 d1 30 6f 55 4e 0a 70 14 03 03 00 01 |5..C.0oUN.p.....| -00000090 01 16 03 03 00 24 37 14 b2 97 7b b5 f0 9a 38 05 |.....$7...{...8.| -000000a0 22 35 69 9c 95 2f 86 4b 37 98 22 db 4e 9a 46 9c |"5i../.K7.".N.F.| -000000b0 b9 81 74 72 58 18 53 0c 5c 3c |..trX.S.\<| +00000090 01 16 03 03 00 24 54 8c 7f 71 03 7c 98 e5 97 65 |.....$T..q.|...e| +000000a0 51 13 b2 9d 4a b8 c9 c1 e6 11 1b 50 c8 1b c0 46 |Q...J......P...F| +000000b0 a7 cb 13 97 92 a0 51 d4 a9 e5 |......Q...| >>> Flow 4 (server to client) -00000000 14 03 03 00 01 01 16 03 03 00 24 3c b3 e7 77 5a |..........$<..wZ| -00000010 7c 36 5a 74 74 26 8d 5b 5a 09 96 60 e8 24 45 2f ||6Ztt&.[Z..`.$E/| -00000020 c2 39 14 5e db 58 12 49 ad a8 b6 ea ef 58 16 |.9.^.X.I.....X.| +00000000 14 03 03 00 01 01 16 03 03 00 24 37 ca ae 55 79 |..........$7..Uy| +00000010 e7 0a 70 55 1e d1 76 61 57 46 d2 c0 d0 ed 3d 70 |..pU..vaWF....=p| +00000020 1f 02 f2 06 5b 3e 50 ec 13 4b 67 e2 7c bd 45 |....[>P..Kg.|.E| >>> Flow 5 (client to server) -00000000 17 03 03 00 1a 6d 29 d7 ba 2f 85 02 b6 f0 82 64 |.....m)../.....d| -00000010 6c 55 ae ab f6 fd 14 ff b8 38 f0 f8 a6 ea cc 15 |lU.......8......| -00000020 03 03 00 16 10 c5 d9 41 7b e2 89 67 dc 29 8e f8 |.......A{..g.)..| -00000030 b5 ab 32 91 44 2c 27 84 49 f7 |..2.D,'.I.| +00000000 17 03 03 00 1a c4 13 68 ec e0 38 a1 07 35 da d7 |.......h..8..5..| +00000010 c4 6b f9 5c ed a7 8a cb 96 7a 22 7c ca a5 30 15 |.k.\.....z"|..0.| +00000020 03 03 00 16 f7 a7 8d 41 b0 c1 4b 61 60 b0 b2 ed |.......A..Ka`...| +00000030 4a ab c3 54 d5 20 eb 67 b7 8f |J..T. .g..| diff --git a/libgo/go/crypto/tls/testdata/Client-TLSv12-SCT b/libgo/go/crypto/tls/testdata/Client-TLSv12-SCT new file mode 100644 index 00000000000..826c9f0a579 --- /dev/null +++ b/libgo/go/crypto/tls/testdata/Client-TLSv12-SCT @@ -0,0 +1,118 @@ +>>> Flow 1 (client to server) +00000000 16 03 01 00 81 01 00 00 7d 03 03 00 00 00 00 00 |........}.......| +00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 1e c0 2f |.............../| +00000030 c0 2b c0 30 c0 2c c0 11 c0 07 c0 13 c0 09 c0 14 |.+.0.,..........| +00000040 c0 0a 00 05 00 2f 00 35 c0 12 00 0a 01 00 00 36 |...../.5.......6| +00000050 00 05 00 05 01 00 00 00 00 00 0a 00 08 00 06 00 |................| +00000060 17 00 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 |................| +00000070 0c 04 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 |................| +00000080 01 00 00 12 00 00 |......| +>>> Flow 2 (server to client) +00000000 16 03 03 01 c6 02 00 01 c2 03 03 1b f6 69 c1 c2 |.............i..| +00000010 36 77 72 32 69 95 c9 e7 db 9b 5d bd 59 ba 08 02 |6wr2i.....].Y...| +00000020 1e 76 11 c4 8e 49 08 22 8e 8a 5a 20 44 ec d9 13 |.v...I."..Z D...| +00000030 23 ad 05 45 48 29 00 c6 11 3d 5a 5c a1 ee 34 2b |#..EH)...=Z\..4+| +00000040 58 ef 34 5b 7e 42 08 84 23 66 56 ee c0 2f 00 01 |X.4[~B..#fV../..| +00000050 7a ff 01 00 01 00 00 0b 00 04 03 00 01 02 00 12 |z...............| +00000060 01 69 01 67 00 75 00 a4 b9 09 90 b4 18 58 14 87 |.i.g.u.......X..| +00000070 bb 13 a2 cc 67 70 0a 3c 35 98 04 f9 1b df b8 e3 |....gp.<5.......| +00000080 77 cd 0e c8 0d dc 10 00 00 01 47 97 99 ee 16 00 |w.........G.....| +00000090 00 04 03 00 46 30 44 02 20 1c 4b 82 5d 95 6e 67 |....F0D. .K.].ng| +000000a0 5b db 04 95 4b f6 ce f4 32 3e 86 7a 7a 32 ab 18 |[...K...2>.zz2..| +000000b0 60 74 de 08 da 05 91 4c 2f 02 20 73 54 1b 6e 7f |`t.....L/. sT.n.| +000000c0 a1 b0 7d 11 bc e6 f3 85 2f 97 66 1a f7 8a e4 10 |..}...../.f.....| +000000d0 25 8f 12 f4 6f 39 0f d2 9e 18 f0 00 76 00 68 f6 |%...o9......v.h.| +000000e0 98 f8 1f 64 82 be 3a 8c ee b9 28 1d 4c fc 71 51 |...d..:...(.L.qQ| +000000f0 5d 67 93 d4 44 d1 0a 67 ac bb 4f 4f fb c4 00 00 |]g..D..g..OO....| +00000100 01 47 97 e1 b5 70 00 00 04 03 00 47 30 45 02 20 |.G...p.....G0E. | +00000110 32 21 14 38 06 d8 72 2e 00 30 64 1a e2 e8 6d 4e |2!.8..r..0d...mN| +00000120 5a e1 d9 42 1e 82 4b 96 25 89 d5 26 13 d3 9c fa |Z..B..K.%..&....| +00000130 02 21 00 8f 12 28 64 51 4f 44 d5 8c 18 62 23 b2 |.!...(dQOD...b#.| +00000140 43 93 33 05 f3 43 55 a1 d9 ee cd c5 71 35 91 dd |C.3..CU.....q5..| +00000150 49 d1 0b 00 76 00 ee 4b bd b7 75 ce 60 ba e1 42 |I...v..K..u.`..B| +00000160 69 1f ab e1 9e 66 a3 0f 7e 5f b0 72 d8 83 00 c4 |i....f..~_.r....| +00000170 7b 89 7a a8 fd cb 00 00 01 48 5c 64 8a 87 00 00 |{.z......H\d....| +00000180 04 03 00 47 30 45 02 20 29 89 d6 b0 53 d3 d2 e9 |...G0E. )...S...| +00000190 91 bc f1 b5 40 be 1e 2e e7 5c b4 74 27 ed 8f 9b |....@....\.t'...| +000001a0 02 e9 fa c2 4c ba a2 be 02 21 00 af 43 64 52 71 |....L....!..CdRq| +000001b0 15 29 58 40 91 c7 08 16 96 03 a8 73 a5 65 a0 6c |.)X@.......s.e.l| +000001c0 b8 48 56 5a b6 29 83 64 6d 2a 9d 16 03 03 02 be |.HVZ.).dm*......| +000001d0 0b 00 02 ba 00 02 b7 00 02 b4 30 82 02 b0 30 82 |..........0...0.| +000001e0 02 19 a0 03 02 01 02 02 09 00 85 b0 bb a4 8a 7f |................| +000001f0 b8 ca 30 0d 06 09 2a 86 48 86 f7 0d 01 01 05 05 |..0...*.H.......| +00000200 00 30 45 31 0b 30 09 06 03 55 04 06 13 02 41 55 |.0E1.0...U....AU| +00000210 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d 65 2d |1.0...U....Some-| +00000220 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a 13 18 |State1!0...U....| +00000230 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 74 73 |Internet Widgits| +00000240 20 50 74 79 20 4c 74 64 30 1e 17 0d 31 30 30 34 | Pty Ltd0...1004| +00000250 32 34 30 39 30 39 33 38 5a 17 0d 31 31 30 34 32 |24090938Z..11042| +00000260 34 30 39 30 39 33 38 5a 30 45 31 0b 30 09 06 03 |4090938Z0E1.0...| +00000270 55 04 06 13 02 41 55 31 13 30 11 06 03 55 04 08 |U....AU1.0...U..| +00000280 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f |..Some-State1!0.| +00000290 06 03 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 |..U....Internet | +000002a0 57 69 64 67 69 74 73 20 50 74 79 20 4c 74 64 30 |Widgits Pty Ltd0| +000002b0 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 |..0...*.H.......| +000002c0 00 03 81 8d 00 30 81 89 02 81 81 00 bb 79 d6 f5 |.....0.......y..| +000002d0 17 b5 e5 bf 46 10 d0 dc 69 be e6 2b 07 43 5a d0 |....F...i..+.CZ.| +000002e0 03 2d 8a 7a 43 85 b7 14 52 e7 a5 65 4c 2c 78 b8 |.-.zC...R..eL,x.| +000002f0 23 8c b5 b4 82 e5 de 1f 95 3b 7e 62 a5 2c a5 33 |#........;~b.,.3| +00000300 d6 fe 12 5c 7a 56 fc f5 06 bf fa 58 7b 26 3f b5 |...\zV.....X{&?.| +00000310 cd 04 d3 d0 c9 21 96 4a c7 f4 54 9f 5a bf ef 42 |.....!.J..T.Z..B| +00000320 71 00 fe 18 99 07 7f 7e 88 7d 7d f1 04 39 c4 a2 |q......~.}}..9..| +00000330 2e db 51 c9 7c e3 c0 4c 3b 32 66 01 cf af b1 1d |..Q.|..L;2f.....| +00000340 b8 71 9a 1d db db 89 6b ae da 2d 79 02 03 01 00 |.q.....k..-y....| +00000350 01 a3 81 a7 30 81 a4 30 1d 06 03 55 1d 0e 04 16 |....0..0...U....| +00000360 04 14 b1 ad e2 85 5a cf cb 28 db 69 ce 23 69 de |......Z..(.i.#i.| +00000370 d3 26 8e 18 88 39 30 75 06 03 55 1d 23 04 6e 30 |.&...90u..U.#.n0| +00000380 6c 80 14 b1 ad e2 85 5a cf cb 28 db 69 ce 23 69 |l......Z..(.i.#i| +00000390 de d3 26 8e 18 88 39 a1 49 a4 47 30 45 31 0b 30 |..&...9.I.G0E1.0| +000003a0 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 |...U....AU1.0...| +000003b0 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 |U....Some-State1| +000003c0 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e |!0...U....Intern| +000003d0 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c |et Widgits Pty L| +000003e0 74 64 82 09 00 85 b0 bb a4 8a 7f b8 ca 30 0c 06 |td...........0..| +000003f0 03 55 1d 13 04 05 30 03 01 01 ff 30 0d 06 09 2a |.U....0....0...*| +00000400 86 48 86 f7 0d 01 01 05 05 00 03 81 81 00 08 6c |.H.............l| +00000410 45 24 c7 6b b1 59 ab 0c 52 cc f2 b0 14 d7 87 9d |E$.k.Y..R.......| +00000420 7a 64 75 b5 5a 95 66 e4 c5 2b 8e ae 12 66 1f eb |zdu.Z.f..+...f..| +00000430 4f 38 b3 6e 60 d3 92 fd f7 41 08 b5 25 13 b1 18 |O8.n`....A..%...| +00000440 7a 24 fb 30 1d ba ed 98 b9 17 ec e7 d7 31 59 db |z$.0.........1Y.| +00000450 95 d3 1d 78 ea 50 56 5c d5 82 5a 2d 5a 5f 33 c4 |...x.PV\..Z-Z_3.| +00000460 b6 d8 c9 75 90 96 8c 0f 52 98 b5 cd 98 1f 89 20 |...u....R...... | +00000470 5f f2 a0 1c a3 1b 96 94 dd a9 fd 57 e9 70 e8 26 |_..........W.p.&| +00000480 6d 71 99 9b 26 6e 38 50 29 6c 90 a7 bd d9 16 03 |mq..&n8P)l......| +00000490 03 00 cd 0c 00 00 c9 03 00 17 41 04 d7 61 5b 05 |..........A..a[.| +000004a0 de 22 d3 3d 00 72 a5 be 0a c1 76 94 a1 34 41 6e |.".=.r....v..4An| +000004b0 55 f2 74 91 d2 6f 5c 47 87 c8 4b eb ab ab 10 b9 |U.t..o\G..K.....| +000004c0 f9 0a bc 63 03 5f 90 5b e3 6f e1 44 97 cc bf d2 |...c._.[.o.D....| +000004d0 e8 0d f5 9c 2e 9d 07 2c b2 00 90 0b 04 01 00 80 |.......,........| +000004e0 67 3d c7 73 42 b9 b2 fd 4b dd 02 57 87 95 20 75 |g=.sB...K..W.. u| +000004f0 da c1 e7 d3 33 09 01 5d e9 32 d7 20 7f 92 a9 dd |....3..].2. ....| +00000500 bb 17 c5 ee f2 07 b2 04 1d 5e 1f c2 41 66 3f 14 |.........^..Af?.| +00000510 90 cd 84 ac 49 46 04 3e ce 89 7d 79 42 2a 8c 56 |....IF.>..}yB*.V| +00000520 93 d3 9c 3b 57 38 9e 91 af 62 ad 86 40 29 3d 46 |...;W8...b..@)=F| +00000530 c7 cc f4 3f a1 7d ee 53 3d 94 1c 85 b9 1d a9 5f |...?.}.S=......_| +00000540 10 8e ee 38 5e 98 5d 39 31 79 83 cd f9 02 a8 a9 |...8^.]91y......| +00000550 b8 82 21 33 40 ed 27 54 a3 6e 64 cb e9 ce dd e1 |..!3@.'T.nd.....| +00000560 16 03 03 00 04 0e 00 00 00 |.........| +>>> Flow 3 (client to server) +00000000 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..| +00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.| +00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.| +00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I| +00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 03 00 01 |..h.A.Vk.Z......| +00000050 01 16 03 03 00 28 00 00 00 00 00 00 00 00 60 0e |.....(........`.| +00000060 49 99 7a 9f 28 6e 46 03 a8 fd 0e b7 ed bb 9c ba |I.z.(nF.........| +00000070 07 9c 4d cc 26 2b c2 70 a0 26 38 a0 f2 a0 |..M.&+.p.&8...| +>>> Flow 4 (server to client) +00000000 14 03 03 00 01 01 16 03 03 00 28 d2 ef 8f f4 7b |..........(....{| +00000010 7a 9b c8 98 a4 36 f2 be 61 46 0e af f4 6f 63 71 |z....6..aF...ocq| +00000020 6e bd 87 ea 1b f2 95 ad 36 7d a3 52 7f b2 b6 45 |n.......6}.R...E| +00000030 3f 0b 62 |?.b| +>>> Flow 5 (client to server) +00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 53 a1 85 |.............S..| +00000010 ce 3c c1 64 39 80 fb db 67 ec 48 20 7f e9 82 f4 |.<.d9...g.H ....| +00000020 2d 69 0a 15 03 03 00 1a 00 00 00 00 00 00 00 02 |-i..............| +00000030 ab 78 11 1b 80 55 23 db 07 c5 7f c3 5e 19 d8 b3 |.x...U#.....^...| +00000040 f8 c6 |..| diff --git a/libgo/go/crypto/tls/testdata/Server-SSLv3-RSA-3DES b/libgo/go/crypto/tls/testdata/Server-SSLv3-RSA-3DES index a6c7a4196c7..20520f542d4 100644 --- a/libgo/go/crypto/tls/testdata/Server-SSLv3-RSA-3DES +++ b/libgo/go/crypto/tls/testdata/Server-SSLv3-RSA-3DES @@ -1,83 +1,78 @@ >>> Flow 1 (client to server) -00000000 16 03 00 00 2f 01 00 00 2b 03 00 52 cc 57 59 d8 |..../...+..R.WY.| -00000010 86 d6 07 ae e0 8d 63 b7 1e cb aa c6 67 32 c8 dd |......c.....g2..| -00000020 68 03 d8 3d 37 18 72 c3 c0 f1 9d 00 00 04 00 0a |h..=7.r.........| +00000000 16 03 00 00 2f 01 00 00 2b 03 00 10 71 68 59 99 |..../...+...qhY.| +00000010 9c a6 e7 36 8b 0d 03 be f5 42 ab 7c d0 3b 76 3e |...6.....B.|.;v>| +00000020 46 7c 6c a3 94 09 b7 1b 0e 42 27 00 00 04 00 0a |F|l......B'.....| 00000030 00 ff 01 00 |....| >>> Flow 2 (server to client) 00000000 16 03 00 00 31 02 00 00 2d 03 00 00 00 00 00 00 |....1...-.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 0a 00 00 |................| -00000030 05 ff 01 00 01 00 16 03 00 02 be 0b 00 02 ba 00 |................| -00000040 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......| -00000050 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..| -00000060 09 2a 86 48 86 f7 0d 01 01 05 05 00 30 45 31 0b |.*.H........0E1.| -00000070 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 |0...U....AU1.0..| -00000080 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 |.U....Some-State| -00000090 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 |1!0...U....Inter| -000000a0 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 |net Widgits Pty | -000000b0 4c 74 64 30 1e 17 0d 31 30 30 34 32 34 30 39 30 |Ltd0...100424090| -000000c0 39 33 38 5a 17 0d 31 31 30 34 32 34 30 39 30 39 |938Z..1104240909| -000000d0 33 38 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 |38Z0E1.0...U....| -000000e0 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som| -000000f0 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..| -00000100 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi| -00000110 74 73 20 50 74 79 20 4c 74 64 30 81 9f 30 0d 06 |ts Pty Ltd0..0..| -00000120 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 |.*.H............| -00000130 30 81 89 02 81 81 00 bb 79 d6 f5 17 b5 e5 bf 46 |0.......y......F| -00000140 10 d0 dc 69 be e6 2b 07 43 5a d0 03 2d 8a 7a 43 |...i..+.CZ..-.zC| -00000150 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 8c b5 b4 82 |...R..eL,x.#....| -00000160 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 fe 12 5c 7a |....;~b.,.3...\z| -00000170 56 fc f5 06 bf fa 58 7b 26 3f b5 cd 04 d3 d0 c9 |V.....X{&?......| -00000180 21 96 4a c7 f4 54 9f 5a bf ef 42 71 00 fe 18 99 |!.J..T.Z..Bq....| -00000190 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e db 51 c9 7c |..~.}}..9....Q.|| -000001a0 e3 c0 4c 3b 32 66 01 cf af b1 1d b8 71 9a 1d db |..L;2f......q...| -000001b0 db 89 6b ae da 2d 79 02 03 01 00 01 a3 81 a7 30 |..k..-y........0| -000001c0 81 a4 30 1d 06 03 55 1d 0e 04 16 04 14 b1 ad e2 |..0...U.........| -000001d0 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 88 |.Z..(.i.#i..&...| -000001e0 39 30 75 06 03 55 1d 23 04 6e 30 6c 80 14 b1 ad |90u..U.#.n0l....| -000001f0 e2 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 |..Z..(.i.#i..&..| -00000200 88 39 a1 49 a4 47 30 45 31 0b 30 09 06 03 55 04 |.9.I.G0E1.0...U.| -00000210 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a |...AU1.0...U....| -00000220 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 |Some-State1!0...| -00000230 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 |U....Internet Wi| -00000240 64 67 69 74 73 20 50 74 79 20 4c 74 64 82 09 00 |dgits Pty Ltd...| -00000250 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 55 1d 13 04 |........0...U...| -00000260 05 30 03 01 01 ff 30 0d 06 09 2a 86 48 86 f7 0d |.0....0...*.H...| -00000270 01 01 05 05 00 03 81 81 00 08 6c 45 24 c7 6b b1 |..........lE$.k.| -00000280 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a 64 75 b5 5a |Y..R.......zdu.Z| -00000290 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f 38 b3 6e 60 |.f..+...f..O8.n`| -000002a0 d3 92 fd f7 41 08 b5 25 13 b1 18 7a 24 fb 30 1d |....A..%...z$.0.| -000002b0 ba ed 98 b9 17 ec e7 d7 31 59 db 95 d3 1d 78 ea |........1Y....x.| -000002c0 50 56 5c d5 82 5a 2d 5a 5f 33 c4 b6 d8 c9 75 90 |PV\..Z-Z_3....u.| -000002d0 96 8c 0f 52 98 b5 cd 98 1f 89 20 5f f2 a0 1c a3 |...R...... _....| -000002e0 1b 96 94 dd a9 fd 57 e9 70 e8 26 6d 71 99 9b 26 |......W.p.&mq..&| -000002f0 6e 38 50 29 6c 90 a7 bd d9 16 03 00 00 04 0e 00 |n8P)l...........| -00000300 00 00 |..| +00000030 05 ff 01 00 01 00 16 03 00 02 71 0b 00 02 6d 00 |..........q...m.| +00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......| +00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..| +00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.| +00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google | +00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..| +00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150| +000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501| +000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..| +000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES| +000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G| +000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....| +000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........| +00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..| +00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.| +00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......| +00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....| +00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........| +00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K| +00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}| +00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....| +00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..| +00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%| +000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........| +000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...| +000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....| +000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.| +000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=| +000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.| +00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp| +00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H| +00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..| +00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....| +00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..| +00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w| +00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k| +00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..| +00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@| +00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...| +000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 00 00 |..A4......9.....| +000002b0 04 0e 00 00 00 |.....| >>> Flow 3 (client to server) -00000000 16 03 00 00 84 10 00 00 80 75 e0 c9 76 d6 e9 34 |.........u..v..4| -00000010 1d e3 31 9e db 3b 03 41 93 e8 db 73 7c e9 3f 6a |..1..;.A...s|.?j| -00000020 d8 2a 7b 25 83 4f 45 de 3f 78 3f b6 53 a7 b4 6c |.*{%.OE.?x?.S..l| -00000030 e3 87 c4 c3 70 55 71 79 55 dc 74 98 84 21 19 13 |....pUqyU.t..!..| -00000040 be d5 8e 0a ff 2f 9f 7a 6b d4 6c ef 78 d1 cb 65 |...../.zk.l.x..e| -00000050 32 4c 0c c5 29 b9 60 94 c6 79 56 a2 aa 2d d9 ad |2L..).`..yV..-..| -00000060 51 2c 54 1b 28 23 33 54 cd 48 cb 80 13 45 3d 4a |Q,T.(#3T.H...E=J| -00000070 8e 2f f2 da bd 68 3e 1b eb 73 f9 2d 35 6b b1 40 |./...h>..s.-5k.@| -00000080 2e 6d 9d 1c e9 c1 02 80 37 14 03 00 00 01 01 16 |.m......7.......| -00000090 03 00 00 40 f7 c3 dd a4 64 3d 81 24 de a2 81 7d |...@....d=.$...}| -000000a0 e4 df 78 46 e7 ba 93 6c 36 43 05 96 fc 75 ef ec |..xF...l6C...u..| -000000b0 a5 46 6d 47 a5 be 74 ad 15 93 d9 87 4f 1d e2 b3 |.FmG..t.....O...| -000000c0 03 ff 2e 89 6e 50 f4 d6 a6 e2 b3 54 cb 74 07 f7 |....nP.....T.t..| -000000d0 ca 1b 8c 0a |....| +00000000 16 03 00 00 84 10 00 00 80 1b 62 18 c8 60 0b f7 |..........b..`..| +00000010 4a b8 ec 98 56 eb aa 4b d9 05 c0 f1 be b9 a5 28 |J...V..K.......(| +00000020 62 e8 3e 25 08 9f 28 dd 08 1f 04 80 5f 10 81 cf |b.>%..(....._...| +00000030 aa 2f 55 cd f1 0f ec 5b 90 0a 1f 49 bc a3 96 38 |./U....[...I...8| +00000040 c7 32 b6 0a da b3 a5 7a 76 28 82 19 30 f4 6b ae |.2.....zv(..0.k.| +00000050 fb 81 cc b4 ad 92 f8 c6 20 da 27 89 45 f4 43 c2 |........ .'.E.C.| +00000060 16 7e de 29 03 dc 90 dd 3a 23 58 4c 35 be 11 a5 |.~.)....:#XL5...| +00000070 52 18 79 13 e6 b3 2d e6 8e f5 76 60 0c c1 92 bb |R.y...-...v`....| +00000080 07 67 c5 24 12 1b aa d6 53 14 03 00 00 01 01 16 |.g.$....S.......| +00000090 03 00 00 40 5f 64 da b6 24 19 07 44 32 85 f3 c0 |...@_d..$..D2...| +000000a0 9b c6 2c ad b1 d1 0f 4b 52 20 2f ea 6f 15 80 44 |..,....KR /.o..D| +000000b0 78 34 44 02 67 e0 2e b4 b8 df 7b 3f 21 dd 66 9b |x4D.g.....{?!.f.| +000000c0 e7 5f 71 ff 5f 30 fb 5b 5a 19 f0 24 f8 21 bc 7c |._q._0.[Z..$.!.|| +000000d0 00 e1 1f e8 |....| >>> Flow 4 (server to client) -00000000 14 03 00 00 01 01 16 03 00 00 40 6d 3d d8 d5 cf |..........@m=...| -00000010 05 7d 98 8c 28 28 e2 43 ab ad 4a fa ae bf ec c3 |.}..((.C..J.....| -00000020 9c 0a 13 4d 28 a4 45 c4 b9 f2 bc c5 12 a2 68 91 |...M(.E.......h.| -00000030 77 fa 72 f8 9e 4e b7 1f b4 02 02 e3 5d 57 b0 8b |w.r..N......]W..| -00000040 d8 90 0c 9d e6 df 5b 90 92 a1 0d 17 03 00 00 18 |......[.........| -00000050 91 48 8a e1 d6 bf 79 1c d5 0a 70 d5 94 20 25 78 |.H....y...p.. %x| -00000060 d8 84 c8 6e 54 f0 99 01 17 03 00 00 28 74 19 90 |...nT.......(t..| -00000070 41 44 53 27 bb fb 1f fd 71 34 20 61 a0 eb a4 7c |ADS'....q4 a...|| -00000080 fe 36 f8 4b d7 b0 27 d3 b9 36 e1 67 af 2d 0e 23 |.6.K..'..6.g.-.#| -00000090 2b 76 a7 2f c3 15 03 00 00 18 db fc e9 fd 87 5f |+v./..........._| -000000a0 92 a8 3d 4b 35 f5 c6 48 2c b4 42 50 c3 81 28 f0 |..=K5..H,.BP..(.| -000000b0 2b 41 |+A| +00000000 14 03 00 00 01 01 16 03 00 00 40 48 01 fc 08 a0 |..........@H....| +00000010 fa 0e 63 58 25 18 06 3c 54 5c 60 ce 35 f6 ec b8 |..cX%...| +000000b0 b3 fa |..| diff --git a/libgo/go/crypto/tls/testdata/Server-SSLv3-RSA-AES b/libgo/go/crypto/tls/testdata/Server-SSLv3-RSA-AES index 4885b267da7..e0fe95658da 100644 --- a/libgo/go/crypto/tls/testdata/Server-SSLv3-RSA-AES +++ b/libgo/go/crypto/tls/testdata/Server-SSLv3-RSA-AES @@ -1,84 +1,79 @@ >>> Flow 1 (client to server) -00000000 16 03 00 00 2f 01 00 00 2b 03 00 52 cc 57 59 30 |..../...+..R.WY0| -00000010 e1 ee 8c 60 5b 40 dd 95 bd b4 84 87 2f 01 15 e7 |...`[@....../...| -00000020 50 88 4c 82 6b 6d 93 8a 57 d0 27 00 00 04 00 2f |P.L.km..W.'..../| +00000000 16 03 00 00 2f 01 00 00 2b 03 00 37 cd 49 a6 9f |..../...+..7.I..| +00000010 e9 19 6a 39 cd 75 ce 6c f1 1b 96 d3 d4 f0 33 0c |..j9.u.l......3.| +00000020 8f 53 b2 06 c4 0e 39 86 e3 98 7e 00 00 04 00 2f |.S....9...~..../| 00000030 00 ff 01 00 |....| >>> Flow 2 (server to client) 00000000 16 03 00 00 31 02 00 00 2d 03 00 00 00 00 00 00 |....1...-.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2f 00 00 |............./..| -00000030 05 ff 01 00 01 00 16 03 00 02 be 0b 00 02 ba 00 |................| -00000040 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......| -00000050 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..| -00000060 09 2a 86 48 86 f7 0d 01 01 05 05 00 30 45 31 0b |.*.H........0E1.| -00000070 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 |0...U....AU1.0..| -00000080 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 |.U....Some-State| -00000090 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 |1!0...U....Inter| -000000a0 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 |net Widgits Pty | -000000b0 4c 74 64 30 1e 17 0d 31 30 30 34 32 34 30 39 30 |Ltd0...100424090| -000000c0 39 33 38 5a 17 0d 31 31 30 34 32 34 30 39 30 39 |938Z..1104240909| -000000d0 33 38 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 |38Z0E1.0...U....| -000000e0 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som| -000000f0 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..| -00000100 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi| -00000110 74 73 20 50 74 79 20 4c 74 64 30 81 9f 30 0d 06 |ts Pty Ltd0..0..| -00000120 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 |.*.H............| -00000130 30 81 89 02 81 81 00 bb 79 d6 f5 17 b5 e5 bf 46 |0.......y......F| -00000140 10 d0 dc 69 be e6 2b 07 43 5a d0 03 2d 8a 7a 43 |...i..+.CZ..-.zC| -00000150 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 8c b5 b4 82 |...R..eL,x.#....| -00000160 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 fe 12 5c 7a |....;~b.,.3...\z| -00000170 56 fc f5 06 bf fa 58 7b 26 3f b5 cd 04 d3 d0 c9 |V.....X{&?......| -00000180 21 96 4a c7 f4 54 9f 5a bf ef 42 71 00 fe 18 99 |!.J..T.Z..Bq....| -00000190 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e db 51 c9 7c |..~.}}..9....Q.|| -000001a0 e3 c0 4c 3b 32 66 01 cf af b1 1d b8 71 9a 1d db |..L;2f......q...| -000001b0 db 89 6b ae da 2d 79 02 03 01 00 01 a3 81 a7 30 |..k..-y........0| -000001c0 81 a4 30 1d 06 03 55 1d 0e 04 16 04 14 b1 ad e2 |..0...U.........| -000001d0 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 88 |.Z..(.i.#i..&...| -000001e0 39 30 75 06 03 55 1d 23 04 6e 30 6c 80 14 b1 ad |90u..U.#.n0l....| -000001f0 e2 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 |..Z..(.i.#i..&..| -00000200 88 39 a1 49 a4 47 30 45 31 0b 30 09 06 03 55 04 |.9.I.G0E1.0...U.| -00000210 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a |...AU1.0...U....| -00000220 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 |Some-State1!0...| -00000230 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 |U....Internet Wi| -00000240 64 67 69 74 73 20 50 74 79 20 4c 74 64 82 09 00 |dgits Pty Ltd...| -00000250 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 55 1d 13 04 |........0...U...| -00000260 05 30 03 01 01 ff 30 0d 06 09 2a 86 48 86 f7 0d |.0....0...*.H...| -00000270 01 01 05 05 00 03 81 81 00 08 6c 45 24 c7 6b b1 |..........lE$.k.| -00000280 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a 64 75 b5 5a |Y..R.......zdu.Z| -00000290 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f 38 b3 6e 60 |.f..+...f..O8.n`| -000002a0 d3 92 fd f7 41 08 b5 25 13 b1 18 7a 24 fb 30 1d |....A..%...z$.0.| -000002b0 ba ed 98 b9 17 ec e7 d7 31 59 db 95 d3 1d 78 ea |........1Y....x.| -000002c0 50 56 5c d5 82 5a 2d 5a 5f 33 c4 b6 d8 c9 75 90 |PV\..Z-Z_3....u.| -000002d0 96 8c 0f 52 98 b5 cd 98 1f 89 20 5f f2 a0 1c a3 |...R...... _....| -000002e0 1b 96 94 dd a9 fd 57 e9 70 e8 26 6d 71 99 9b 26 |......W.p.&mq..&| -000002f0 6e 38 50 29 6c 90 a7 bd d9 16 03 00 00 04 0e 00 |n8P)l...........| -00000300 00 00 |..| +00000030 05 ff 01 00 01 00 16 03 00 02 71 0b 00 02 6d 00 |..........q...m.| +00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......| +00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..| +00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.| +00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google | +00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..| +00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150| +000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501| +000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..| +000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES| +000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G| +000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....| +000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........| +00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..| +00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.| +00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......| +00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....| +00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........| +00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K| +00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}| +00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....| +00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..| +00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%| +000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........| +000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...| +000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....| +000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.| +000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=| +000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.| +00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp| +00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H| +00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..| +00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....| +00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..| +00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w| +00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k| +00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..| +00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@| +00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...| +000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 00 00 |..A4......9.....| +000002b0 04 0e 00 00 00 |.....| >>> Flow 3 (client to server) -00000000 16 03 00 00 84 10 00 00 80 74 50 05 6f f5 83 c9 |.........tP.o...| -00000010 f5 0c 5a 65 c7 4e c6 f3 87 96 d7 5d 3e 88 27 32 |..Ze.N.....]>.'2| -00000020 89 12 ba ec db ef c0 85 70 84 ed b6 83 03 8f 44 |........p......D| -00000030 f5 6f fa fa d0 1f 95 30 d1 ae a7 71 cf ee e9 b1 |.o.....0...q....| -00000040 80 7b 34 a9 ea 1b 5e e5 71 40 3f e8 7d 30 d1 8b |.{4...^.q@?.}0..| -00000050 11 f1 68 1f c8 25 f0 77 c5 af b3 92 6e d9 81 cc |..h..%.w....n...| -00000060 f8 fd 82 95 cc 1f 4a b1 05 15 7a b3 a1 22 33 09 |......J...z.."3.| -00000070 e7 a5 c2 89 7f 03 e0 91 b6 61 a3 a0 4e 17 0d 7a |.........a..N..z| -00000080 13 01 c4 b6 50 c7 d9 81 15 14 03 00 00 01 01 16 |....P...........| -00000090 03 00 00 40 56 da 56 ab e6 26 98 58 53 1f 36 b5 |...@V.V..&.XS.6.| -000000a0 03 14 bd 42 29 ee 9c 7c e4 48 26 82 68 ae fd fe |...B)..|.H&.h...| -000000b0 5e a4 43 22 75 95 7b c8 77 88 fd d6 d4 9b c9 b5 |^.C"u.{.w.......| -000000c0 ee 3e a6 e8 c5 04 90 63 3f ac be 56 67 da 30 d4 |.>.....c?..Vg.0.| -000000d0 64 fb a8 a0 |d...| +00000000 16 03 00 00 84 10 00 00 80 4d 3f 93 aa 84 d8 ad |.........M?.....| +00000010 93 2c 63 02 66 2f 96 88 b8 5c 09 1e 63 e2 e5 96 |.,c.f/...\..c...| +00000020 26 d8 07 14 86 26 62 f4 0c 04 68 1c bf bb b1 53 |&....&b...h....S| +00000030 97 96 43 59 4a 57 65 12 88 45 34 2b 86 2b 05 aa |..CYJWe..E4+.+..| +00000040 9b 2b b9 aa 13 30 5c 91 c0 9f 03 8a 96 61 dd 87 |.+...0\......a..| +00000050 ae e3 ad 6a 7b 8a 18 23 67 c9 df ad f2 47 eb 8b |...j{..#g....G..| +00000060 7d 24 95 47 f1 4e b5 c6 15 b4 12 2a 42 df b3 99 |}$.G.N.....*B...| +00000070 d1 b8 60 ce 6a cf 98 c1 13 a1 68 e6 92 ee 92 a2 |..`.j.....h.....| +00000080 1d 2f 63 66 f3 b9 1b fc 33 14 03 00 00 01 01 16 |./cf....3.......| +00000090 03 00 00 40 75 48 68 7d 8f f5 5a c0 cb 90 a5 9e |...@uHh}..Z.....| +000000a0 94 bb eb 61 b5 36 aa ce 09 7a 11 ba 22 56 2a d7 |...a.6...z.."V*.| +000000b0 91 a3 99 73 5b c5 b2 b7 b9 92 56 c6 cb fe 13 73 |...s[.....V....s| +000000c0 28 30 03 26 62 63 7e 8a d2 58 c8 e7 52 03 26 67 |(0.&bc~..X..R.&g| +000000d0 48 21 4f 21 |H!O!| >>> Flow 4 (server to client) -00000000 14 03 00 00 01 01 16 03 00 00 40 96 af fb 79 96 |..........@...y.| -00000010 92 97 2d d0 67 46 1e 08 b5 35 65 ef dc bc 8e 57 |..-.gF...5e....W| -00000020 53 b7 36 58 74 d7 88 b1 55 fc eb fa 2e f3 17 b7 |S.6Xt...U.......| -00000030 62 58 a0 9d 99 e1 85 d4 33 e0 b4 1f 1d 94 f2 88 |bX......3.......| -00000040 d5 9a 34 5b 74 cd d2 ff 87 bd 52 17 03 00 00 20 |..4[t.....R.... | -00000050 c6 61 c2 28 ac d2 0c 08 7f f1 c2 62 af 37 7e 78 |.a.(.......b.7~x| -00000060 e8 e2 a1 54 f2 3a 80 97 f8 47 64 f2 cd 94 dd 0b |...T.:...Gd.....| -00000070 17 03 00 00 30 b8 40 8f a3 18 ff 03 84 d4 1c 28 |....0.@........(| -00000080 82 ce d8 9a 81 3a dd 23 7c 65 d8 ca f7 f1 46 1b |.....:.#|e....F.| -00000090 70 f0 d7 d9 54 a7 71 e6 4d d4 25 61 5a e4 30 d3 |p...T.q.M.%aZ.0.| -000000a0 4a 42 ae 26 a5 15 03 00 00 20 c4 e8 ed 40 57 00 |JB.&..... ...@W.| -000000b0 dc a5 0e 82 90 47 92 08 dd 7e 50 6b 30 66 5e 90 |.....G...~Pk0f^.| -000000c0 73 7c 81 93 8d 24 b1 06 e7 39 |s|...$...9| +00000000 14 03 00 00 01 01 16 03 00 00 40 84 8f 6e 80 35 |..........@..n.5| +00000010 57 73 64 ef 29 bb 25 ff 5d 9d c7 55 38 b7 18 b3 |Wsd.).%.]..U8...| +00000020 13 d1 ac 20 e0 1e f8 48 47 7a 40 2d bc a7 f2 af |... ...HGz@-....| +00000030 ed a6 26 48 f4 51 b4 b6 56 60 9b c3 d9 43 00 95 |..&H.Q..V`...C..| +00000040 86 be 6c 4e 49 6b f9 10 99 51 22 17 03 00 00 20 |..lNIk...Q".... | +00000050 d4 7e dc 50 7b c2 26 ee 79 09 84 9f d7 e0 52 b1 |.~.P{.&.y.....R.| +00000060 e8 9c 92 30 b7 34 06 c6 e5 86 57 a1 fb 8d 06 d6 |...0.4....W.....| +00000070 17 03 00 00 30 93 0a 3d 64 26 3d a2 74 bc 8f d1 |....0..=d&=.t...| +00000080 16 38 d0 6b 62 eb 82 b0 9a 50 68 aa 7e f7 45 32 |.8.kb....Ph.~.E2| +00000090 43 cb 84 2d 95 39 6c bc c8 a0 2d aa ea fe f5 84 |C..-.9l...-.....| +000000a0 c8 e4 8b 93 a1 15 03 00 00 20 03 7b 3e 43 1d 0a |......... .{>C..| +000000b0 9b 9b e3 17 0f de be 75 e5 6e 2f 5b e8 8d a8 68 |.......u.n/[...h| +000000c0 4e f0 82 49 00 dd b6 95 b4 22 |N..I....."| diff --git a/libgo/go/crypto/tls/testdata/Server-SSLv3-RSA-RC4 b/libgo/go/crypto/tls/testdata/Server-SSLv3-RSA-RC4 index 1314b659bf0..39124c67ef1 100644 --- a/libgo/go/crypto/tls/testdata/Server-SSLv3-RSA-RC4 +++ b/libgo/go/crypto/tls/testdata/Server-SSLv3-RSA-RC4 @@ -1,79 +1,74 @@ >>> Flow 1 (client to server) -00000000 16 03 00 00 2f 01 00 00 2b 03 00 52 cc 57 59 79 |..../...+..R.WYy| -00000010 b9 3b ef df 53 fb 09 f6 01 e5 18 0a fc 3d 65 bb |.;..S........=e.| -00000020 cf 9c 4c 77 b1 e8 6b 4f 5f c7 94 00 00 04 00 05 |..Lw..kO_.......| +00000000 16 03 00 00 2f 01 00 00 2b 03 00 a7 1d 3d ed 0f |..../...+....=..| +00000010 2c 7b 1f f1 c8 1c a9 17 ce 69 e2 73 a2 07 d2 91 |,{.......i.s....| +00000020 e9 27 fa 70 11 6f 18 6d 2a 25 f1 00 00 04 00 05 |.'.p.o.m*%......| 00000030 00 ff 01 00 |....| >>> Flow 2 (server to client) 00000000 16 03 00 00 31 02 00 00 2d 03 00 00 00 00 00 00 |....1...-.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................| -00000030 05 ff 01 00 01 00 16 03 00 02 be 0b 00 02 ba 00 |................| -00000040 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......| -00000050 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..| -00000060 09 2a 86 48 86 f7 0d 01 01 05 05 00 30 45 31 0b |.*.H........0E1.| -00000070 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 |0...U....AU1.0..| -00000080 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 |.U....Some-State| -00000090 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 |1!0...U....Inter| -000000a0 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 |net Widgits Pty | -000000b0 4c 74 64 30 1e 17 0d 31 30 30 34 32 34 30 39 30 |Ltd0...100424090| -000000c0 39 33 38 5a 17 0d 31 31 30 34 32 34 30 39 30 39 |938Z..1104240909| -000000d0 33 38 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 |38Z0E1.0...U....| -000000e0 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som| -000000f0 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..| -00000100 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi| -00000110 74 73 20 50 74 79 20 4c 74 64 30 81 9f 30 0d 06 |ts Pty Ltd0..0..| -00000120 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 |.*.H............| -00000130 30 81 89 02 81 81 00 bb 79 d6 f5 17 b5 e5 bf 46 |0.......y......F| -00000140 10 d0 dc 69 be e6 2b 07 43 5a d0 03 2d 8a 7a 43 |...i..+.CZ..-.zC| -00000150 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 8c b5 b4 82 |...R..eL,x.#....| -00000160 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 fe 12 5c 7a |....;~b.,.3...\z| -00000170 56 fc f5 06 bf fa 58 7b 26 3f b5 cd 04 d3 d0 c9 |V.....X{&?......| -00000180 21 96 4a c7 f4 54 9f 5a bf ef 42 71 00 fe 18 99 |!.J..T.Z..Bq....| -00000190 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e db 51 c9 7c |..~.}}..9....Q.|| -000001a0 e3 c0 4c 3b 32 66 01 cf af b1 1d b8 71 9a 1d db |..L;2f......q...| -000001b0 db 89 6b ae da 2d 79 02 03 01 00 01 a3 81 a7 30 |..k..-y........0| -000001c0 81 a4 30 1d 06 03 55 1d 0e 04 16 04 14 b1 ad e2 |..0...U.........| -000001d0 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 88 |.Z..(.i.#i..&...| -000001e0 39 30 75 06 03 55 1d 23 04 6e 30 6c 80 14 b1 ad |90u..U.#.n0l....| -000001f0 e2 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 |..Z..(.i.#i..&..| -00000200 88 39 a1 49 a4 47 30 45 31 0b 30 09 06 03 55 04 |.9.I.G0E1.0...U.| -00000210 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a |...AU1.0...U....| -00000220 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 |Some-State1!0...| -00000230 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 |U....Internet Wi| -00000240 64 67 69 74 73 20 50 74 79 20 4c 74 64 82 09 00 |dgits Pty Ltd...| -00000250 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 55 1d 13 04 |........0...U...| -00000260 05 30 03 01 01 ff 30 0d 06 09 2a 86 48 86 f7 0d |.0....0...*.H...| -00000270 01 01 05 05 00 03 81 81 00 08 6c 45 24 c7 6b b1 |..........lE$.k.| -00000280 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a 64 75 b5 5a |Y..R.......zdu.Z| -00000290 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f 38 b3 6e 60 |.f..+...f..O8.n`| -000002a0 d3 92 fd f7 41 08 b5 25 13 b1 18 7a 24 fb 30 1d |....A..%...z$.0.| -000002b0 ba ed 98 b9 17 ec e7 d7 31 59 db 95 d3 1d 78 ea |........1Y....x.| -000002c0 50 56 5c d5 82 5a 2d 5a 5f 33 c4 b6 d8 c9 75 90 |PV\..Z-Z_3....u.| -000002d0 96 8c 0f 52 98 b5 cd 98 1f 89 20 5f f2 a0 1c a3 |...R...... _....| -000002e0 1b 96 94 dd a9 fd 57 e9 70 e8 26 6d 71 99 9b 26 |......W.p.&mq..&| -000002f0 6e 38 50 29 6c 90 a7 bd d9 16 03 00 00 04 0e 00 |n8P)l...........| -00000300 00 00 |..| +00000030 05 ff 01 00 01 00 16 03 00 02 71 0b 00 02 6d 00 |..........q...m.| +00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......| +00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..| +00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.| +00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google | +00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..| +00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150| +000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501| +000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..| +000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES| +000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G| +000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....| +000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........| +00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..| +00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.| +00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......| +00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....| +00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........| +00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K| +00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}| +00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....| +00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..| +00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%| +000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........| +000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...| +000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....| +000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.| +000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=| +000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.| +00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp| +00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H| +00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..| +00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....| +00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..| +00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w| +00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k| +00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..| +00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@| +00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...| +000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 00 00 |..A4......9.....| +000002b0 04 0e 00 00 00 |.....| >>> Flow 3 (client to server) -00000000 16 03 00 00 84 10 00 00 80 4d 66 7a f3 f8 ab 86 |.........Mfz....| -00000010 43 4c 5f 7c 52 ca e7 3f ba 62 b3 82 88 16 7d ca |CL_|R..?.b....}.| -00000020 3a 66 15 c0 36 55 2c ab bf 30 6b cd 9c d8 b9 48 |:f..6U,..0k....H| -00000030 03 c9 d0 98 ab 0b a6 5b 39 c8 fe 82 8e bb f0 16 |.......[9.......| -00000040 6f 96 62 81 f2 dc 52 02 c9 de e4 47 73 21 6e 1e |o.b...R....Gs!n.| -00000050 3a 11 89 7a e2 6b 9e 04 64 72 15 ba 2d 10 a2 69 |:..z.k..dr..-..i| -00000060 07 e6 ba 17 cf 54 d6 4e 5f 99 e8 59 8b 54 ce 8e |.....T.N_..Y.T..| -00000070 6b 58 ba 83 68 46 4a 5f 43 3e 9b e1 32 a2 19 42 |kX..hFJ_C>..2..B| -00000080 46 0f e4 47 1a 3b 16 5f e1 14 03 00 00 01 01 16 |F..G.;._........| -00000090 03 00 00 3c 78 7e ee da 0d 38 0b 1a d6 d4 8e d5 |...>> Flow 4 (server to client) -00000000 14 03 00 00 01 01 16 03 00 00 3c 23 29 64 62 23 |..........<#)db#| -00000010 19 20 f8 2e 15 07 ee c8 f4 ab f0 3e 66 c3 ed 7b |. .........>f..{| -00000020 7c a7 c2 7e c3 25 3c 8f f3 04 dc 37 e8 fc 0a 1d ||..~.%<....7....| -00000030 fa 7a 09 d4 21 11 e3 24 21 4b 37 d1 85 cc 40 bf |.z..!..$!K7...@.| -00000040 bd bd f8 59 6b cd 73 17 03 00 00 21 47 1d ac 54 |...Yk.s....!G..T| -00000050 bd 58 a6 c0 04 e2 0c 6b 66 64 5a 85 09 0e 47 fc |.X.....kfdZ...G.| -00000060 0b 57 ee f1 24 b6 89 57 46 be 6b 0d f2 15 03 00 |.W..$..WF.k.....| -00000070 00 16 b4 f7 34 99 19 43 b6 b3 5a 8b c3 d2 67 2f |....4..C..Z...g/| -00000080 3b 19 1c 31 d4 f9 bd 96 |;..1....| +00000000 14 03 00 00 01 01 16 03 00 00 3c 29 af 2c 96 3a |..........<).,.:| +00000010 be a0 91 a8 e4 66 6b 30 ba e2 80 fc a2 8a 09 b4 |.....fk0........| +00000020 28 14 3b 36 c2 3b 3e 88 e2 10 da 93 af 71 9a 06 |(.;6.;>......q..| +00000030 1c 8d 97 04 05 ec e2 69 cf 28 20 0f ec 4c a7 f3 |.......i.( ..L..| +00000040 18 4e 6b 5b 88 9c a9 17 03 00 00 21 5e 0b b4 2d |.Nk[.......!^..-| +00000050 a6 b5 0b 3a 86 de 8a e7 87 f3 4c f6 74 7e 0d 16 |...:......L.t~..| +00000060 9b fc 0c 42 6b f4 9e 15 8b 6a c5 97 88 15 03 00 |...Bk....j......| +00000070 00 16 f0 a4 e2 16 bf 81 05 ad 1d f5 1c 89 d9 ab |................| +00000080 48 23 ab 96 ea 92 aa cd |H#......| diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES b/libgo/go/crypto/tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES index 9b8cb4d9b62..f81ffc28c0e 100644 --- a/libgo/go/crypto/tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES +++ b/libgo/go/crypto/tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES @@ -1,12 +1,13 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 76 01 00 00 72 03 01 53 04 f0 f9 4b |....v...r..S...K| -00000010 30 a8 68 d0 79 13 14 69 ee 3b 5d 05 cb 71 63 43 |0.h.y..i.;]..qcC| -00000020 4a 55 6b 05 25 53 19 ba e0 2f b1 00 00 04 c0 0a |JUk.%S.../......| -00000030 00 ff 01 00 00 45 00 0b 00 04 03 00 01 02 00 0a |.....E..........| -00000040 00 34 00 32 00 0e 00 0d 00 19 00 0b 00 0c 00 18 |.4.2............| -00000050 00 09 00 0a 00 16 00 17 00 08 00 06 00 07 00 14 |................| -00000060 00 15 00 04 00 05 00 12 00 13 00 01 00 02 00 03 |................| -00000070 00 0f 00 10 00 11 00 0f 00 01 01 |...........| +00000000 16 03 01 00 7d 01 00 00 79 03 01 65 14 3f 40 e4 |....}...y..e.?@.| +00000010 2f 74 65 7e d0 c8 87 03 59 61 9d c3 84 5e c9 62 |/te~....Ya...^.b| +00000020 e6 46 b8 0c 4a 5e 3f 33 43 a5 dd 00 00 04 c0 0a |.F..J^?3C.......| +00000030 00 ff 02 01 00 00 4b 00 0b 00 04 03 00 01 02 00 |......K.........| +00000040 0a 00 3a 00 38 00 0e 00 0d 00 19 00 1c 00 0b 00 |..:.8...........| +00000050 0c 00 1b 00 18 00 09 00 0a 00 1a 00 16 00 17 00 |................| +00000060 08 00 06 00 07 00 14 00 15 00 04 00 05 00 12 00 |................| +00000070 13 00 01 00 02 00 03 00 0f 00 10 00 11 00 0f 00 |................| +00000080 01 01 |..| >>> Flow 2 (server to client) 00000000 16 03 01 00 31 02 00 00 2d 03 01 00 00 00 00 00 |....1...-.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| @@ -49,36 +50,36 @@ 00000260 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd a7 24 20 3e |uq..T[....g..$ >| 00000270 b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e f1 07 9f 6c |.V...(^.+-O....l| 00000280 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 a6 b5 68 1a |K[.V.2B.X..I..h.| -00000290 41 03 56 6b dc 5a 89 00 8b 30 81 88 02 42 00 c6 |A.Vk.Z...0...B..| -000002a0 85 8e 06 b7 04 04 e9 cd 9e 3e cb 66 23 95 b4 42 |.........>.f#..B| -000002b0 9c 64 81 39 05 3f b5 21 f8 28 af 60 6b 4d 3d ba |.d.9.?.!.(.`kM=.| -000002c0 a1 4b 5e 77 ef e7 59 28 fe 1d c1 27 a2 ff a8 de |.K^w..Y(...'....| -000002d0 33 48 b3 c1 85 6a 42 9b f9 7e 7e 31 c2 e5 bd 66 |3H...jB..~~1...f| -000002e0 02 42 00 ad 7d 06 35 ab ec 8d ac d4 ba 1b 49 5e |.B..}.5.......I^| -000002f0 05 5f f0 97 93 82 b8 2b 8d 91 98 63 8e b4 14 62 |._.....+...c...b| -00000300 db 1e c9 2b 30 f8 41 9b a6 e6 bc de 0e 68 30 21 |...+0.A......h0!| -00000310 d8 ef 2f 05 42 da f2 e0 2c 06 33 1d 0d 9a 1a 75 |../.B...,.3....u| -00000320 59 a7 3a bc 16 03 01 00 04 0e 00 00 00 |Y.:..........| +00000290 41 03 56 6b dc 5a 89 00 8b 30 81 88 02 42 01 3e |A.Vk.Z...0...B.>| +000002a0 79 81 6e 89 cd 3e 3f ec e4 b5 75 17 28 ee fb 09 |y.n..>?...u.(...| +000002b0 21 19 6f 3c e6 ca 1e f2 18 b6 47 f8 37 05 1c 85 |!.o<......G.7...| +000002c0 0f a4 b8 6b 40 04 50 77 e3 05 9b 24 b8 93 e8 4d |...k@.Pw...$...M| +000002d0 ef 30 cd 51 90 58 a2 49 71 b3 3f b9 46 ab a9 72 |.0.Q.X.Iq.?.F..r| +000002e0 02 42 01 58 ef 20 c1 0a 33 f8 fd 50 9e 65 f5 ef |.B.X. ..3..P.e..| +000002f0 f4 91 49 2d d2 de 66 2b 97 69 7d b1 d0 ef d6 91 |..I-..f+.i}.....| +00000300 0f fc 57 2b 73 b9 49 01 33 d2 1b 5b 9a 2c 51 35 |..W+s.I.3..[.,Q5| +00000310 0e eb 38 53 fa 20 07 84 52 b3 43 24 09 5a 32 c0 |..8S. ..R.C$.Z2.| +00000320 32 17 34 6c 16 03 01 00 04 0e 00 00 00 |2.4l.........| >>> Flow 3 (client to server) -00000000 16 03 01 00 46 10 00 00 42 41 04 08 28 cf bd 3c |....F...BA..(..<| -00000010 3c cc 98 9e 73 3f 92 a7 cb 22 83 3b c7 61 46 0e |<...s?...".;.aF.| -00000020 4d 7c 30 b5 06 85 2f 01 be b5 40 e2 64 1e 45 c1 |M|0.../...@.d.E.| -00000030 9d 73 95 d5 65 92 0b 9b e7 6f c6 91 ab b6 fa be |.s..e....o......| -00000040 61 83 a7 f2 eb f5 65 31 fe 24 7b 14 03 01 00 01 |a.....e1.${.....| -00000050 01 16 03 01 00 30 15 d1 c4 ca 0b 01 84 13 5a ba |.....0........Z.| -00000060 89 04 87 73 7c bb d8 89 7e 10 27 ba 6f 5d dc d3 |...s|...~.'.o]..| -00000070 b5 ef 32 86 58 cc fb eb 5c 32 9e 95 ef 01 1c ac |..2.X...\2......| -00000080 dc 8e df 7f fe 0a |......| +00000000 16 03 01 00 46 10 00 00 42 41 04 31 74 f8 f6 18 |....F...BA.1t...| +00000010 55 6a 9b 3b 78 0a 0e f0 c9 91 aa 8e 77 39 0a 88 |Uj.;x.......w9..| +00000020 a4 d4 f6 04 9d de 89 18 b6 50 12 72 26 9c 8f e1 |.........P.r&...| +00000030 f0 b2 e6 df ce 3b 46 be e9 2a 9a e3 7f d1 d5 92 |.....;F..*......| +00000040 ff e3 ae 0a 2d a1 3b 07 f6 04 59 14 03 01 00 01 |....-.;...Y.....| +00000050 01 16 03 01 00 30 02 4f df 41 30 97 6f f7 18 ca |.....0.O.A0.o...| +00000060 05 35 17 a1 a2 a5 71 61 b1 d8 dd 9a c6 f3 54 53 |.5....qa......TS| +00000070 84 f6 fb 93 1e 0e 9d e7 fe 35 85 9e 73 d0 2e a1 |.........5..s...| +00000080 a7 63 d9 40 c6 ac |.c.@..| >>> Flow 4 (server to client) -00000000 14 03 01 00 01 01 16 03 01 00 30 e8 48 86 81 3c |..........0.H..<| -00000010 f5 25 5c 94 a9 06 c4 5c 71 62 b1 43 76 ec 2c 44 |.%\....\qb.Cv.,D| -00000020 95 b5 8c 95 d2 ff 82 92 b6 fc 52 75 03 c6 a1 f0 |..........Ru....| -00000030 99 6d b1 ed ec 68 6c d7 9f 18 50 17 03 01 00 20 |.m...hl...P.... | -00000040 32 d9 26 8a 81 b8 9d a5 7b fd d5 4e 7a db 2e 29 |2.&.....{..Nz..)| -00000050 58 9a 4f 6a 27 18 bc dc c2 49 b8 65 cb 8e 16 5a |X.Oj'....I.e...Z| -00000060 17 03 01 00 30 c4 56 0a ad 9a 82 cb 3e 32 f1 7c |....0.V.....>2.|| -00000070 95 6e dd cd e9 4d f0 e5 2d c9 a3 f7 de bb d7 fd |.n...M..-.......| -00000080 84 bb df 34 8c 64 1f 03 58 64 19 4a 5b 7a a8 81 |...4.d..Xd.J[z..| -00000090 52 bb 51 0a 43 15 03 01 00 20 89 18 7a 40 ec 49 |R.Q.C.... ..z@.I| -000000a0 52 d5 d3 20 ac 07 eb e9 4a 78 23 cf e7 21 32 74 |R.. ....Jx#..!2t| -000000b0 ec 40 8d a8 f4 33 1c ae 93 cf |.@...3....| +00000000 14 03 01 00 01 01 16 03 01 00 30 07 7e 4e 9c 19 |..........0.~N..| +00000010 f0 35 cd 02 b7 a6 0a 1a b1 a8 11 a3 f9 b1 35 7b |.5............5{| +00000020 96 7f e6 e1 00 c6 6d 9e e6 8a bb a2 b8 bd a3 9d |......m.........| +00000030 05 22 1b f1 f5 28 4a 00 6e f1 71 17 03 01 00 20 |."...(J.n.q.... | +00000040 ad c7 4c dc f4 81 1a 39 3d 86 5e 8e f5 0d a3 33 |..L....9=.^....3| +00000050 88 32 e7 be 8b 6a 8d 44 29 7b 47 fd e5 33 01 1e |.2...j.D){G..3..| +00000060 17 03 01 00 30 61 47 ee ae 89 25 ac 85 3b 8a 84 |....0aG...%..;..| +00000070 47 61 ea 3e 4c 70 57 07 d6 f1 1c 21 cb 44 7e de |Ga.>LpW....!.D~.| +00000080 b5 01 9e fb fe ad bc be 74 c0 65 a0 6b c1 0c 8c |........t.e.k...| +00000090 2b 00 24 c6 b7 15 03 01 00 20 b7 8b 6b e5 77 ab |+.$...... ..k.w.| +000000a0 f6 50 9e 88 4d 56 a8 25 8d 02 db cb 68 8b 3f 62 |.P..MV.%....h.?b| +000000b0 be aa 02 24 75 b1 e5 4b 18 c9 |...$u..K..| diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv10-RSA-3DES b/libgo/go/crypto/tls/testdata/Server-TLSv10-RSA-3DES index c0e6241c07e..55cb487d12a 100644 --- a/libgo/go/crypto/tls/testdata/Server-TLSv10-RSA-3DES +++ b/libgo/go/crypto/tls/testdata/Server-TLSv10-RSA-3DES @@ -1,79 +1,74 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 36 01 00 00 32 03 01 52 cc 57 59 13 |....6...2..R.WY.| -00000010 8b e6 5b a3 1d cb 94 ef 48 e4 59 7e 20 6d 07 67 |..[.....H.Y~ m.g| -00000020 1e 28 6d 31 a2 e7 96 b3 7d 32 cc 00 00 04 00 0a |.(m1....}2......| +00000000 16 03 01 00 36 01 00 00 32 03 01 35 4a e8 32 84 |....6...2..5J.2.| +00000010 51 68 04 7e d0 0f 43 94 c7 5d 44 d2 95 a3 12 63 |Qh.~..C..]D....c| +00000020 77 c5 ce 78 5a 25 a3 81 df c4 6b 00 00 04 00 0a |w..xZ%....k.....| 00000030 00 ff 01 00 00 05 00 0f 00 01 01 |...........| >>> Flow 2 (server to client) 00000000 16 03 01 00 31 02 00 00 2d 03 01 00 00 00 00 00 |....1...-.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 0a 00 00 |................| -00000030 05 ff 01 00 01 00 16 03 01 02 be 0b 00 02 ba 00 |................| -00000040 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......| -00000050 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..| -00000060 09 2a 86 48 86 f7 0d 01 01 05 05 00 30 45 31 0b |.*.H........0E1.| -00000070 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 |0...U....AU1.0..| -00000080 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 |.U....Some-State| -00000090 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 |1!0...U....Inter| -000000a0 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 |net Widgits Pty | -000000b0 4c 74 64 30 1e 17 0d 31 30 30 34 32 34 30 39 30 |Ltd0...100424090| -000000c0 39 33 38 5a 17 0d 31 31 30 34 32 34 30 39 30 39 |938Z..1104240909| -000000d0 33 38 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 |38Z0E1.0...U....| -000000e0 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som| -000000f0 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..| -00000100 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi| -00000110 74 73 20 50 74 79 20 4c 74 64 30 81 9f 30 0d 06 |ts Pty Ltd0..0..| -00000120 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 |.*.H............| -00000130 30 81 89 02 81 81 00 bb 79 d6 f5 17 b5 e5 bf 46 |0.......y......F| -00000140 10 d0 dc 69 be e6 2b 07 43 5a d0 03 2d 8a 7a 43 |...i..+.CZ..-.zC| -00000150 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 8c b5 b4 82 |...R..eL,x.#....| -00000160 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 fe 12 5c 7a |....;~b.,.3...\z| -00000170 56 fc f5 06 bf fa 58 7b 26 3f b5 cd 04 d3 d0 c9 |V.....X{&?......| -00000180 21 96 4a c7 f4 54 9f 5a bf ef 42 71 00 fe 18 99 |!.J..T.Z..Bq....| -00000190 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e db 51 c9 7c |..~.}}..9....Q.|| -000001a0 e3 c0 4c 3b 32 66 01 cf af b1 1d b8 71 9a 1d db |..L;2f......q...| -000001b0 db 89 6b ae da 2d 79 02 03 01 00 01 a3 81 a7 30 |..k..-y........0| -000001c0 81 a4 30 1d 06 03 55 1d 0e 04 16 04 14 b1 ad e2 |..0...U.........| -000001d0 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 88 |.Z..(.i.#i..&...| -000001e0 39 30 75 06 03 55 1d 23 04 6e 30 6c 80 14 b1 ad |90u..U.#.n0l....| -000001f0 e2 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 |..Z..(.i.#i..&..| -00000200 88 39 a1 49 a4 47 30 45 31 0b 30 09 06 03 55 04 |.9.I.G0E1.0...U.| -00000210 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a |...AU1.0...U....| -00000220 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 |Some-State1!0...| -00000230 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 |U....Internet Wi| -00000240 64 67 69 74 73 20 50 74 79 20 4c 74 64 82 09 00 |dgits Pty Ltd...| -00000250 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 55 1d 13 04 |........0...U...| -00000260 05 30 03 01 01 ff 30 0d 06 09 2a 86 48 86 f7 0d |.0....0...*.H...| -00000270 01 01 05 05 00 03 81 81 00 08 6c 45 24 c7 6b b1 |..........lE$.k.| -00000280 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a 64 75 b5 5a |Y..R.......zdu.Z| -00000290 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f 38 b3 6e 60 |.f..+...f..O8.n`| -000002a0 d3 92 fd f7 41 08 b5 25 13 b1 18 7a 24 fb 30 1d |....A..%...z$.0.| -000002b0 ba ed 98 b9 17 ec e7 d7 31 59 db 95 d3 1d 78 ea |........1Y....x.| -000002c0 50 56 5c d5 82 5a 2d 5a 5f 33 c4 b6 d8 c9 75 90 |PV\..Z-Z_3....u.| -000002d0 96 8c 0f 52 98 b5 cd 98 1f 89 20 5f f2 a0 1c a3 |...R...... _....| -000002e0 1b 96 94 dd a9 fd 57 e9 70 e8 26 6d 71 99 9b 26 |......W.p.&mq..&| -000002f0 6e 38 50 29 6c 90 a7 bd d9 16 03 01 00 04 0e 00 |n8P)l...........| -00000300 00 00 |..| +00000030 05 ff 01 00 01 00 16 03 01 02 71 0b 00 02 6d 00 |..........q...m.| +00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......| +00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..| +00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.| +00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google | +00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..| +00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150| +000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501| +000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..| +000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES| +000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G| +000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....| +000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........| +00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..| +00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.| +00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......| +00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....| +00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........| +00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K| +00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}| +00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....| +00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..| +00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%| +000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........| +000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...| +000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....| +000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.| +000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=| +000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.| +00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp| +00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H| +00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..| +00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....| +00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..| +00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w| +00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k| +00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..| +00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@| +00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...| +000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 01 00 |..A4......9.....| +000002b0 04 0e 00 00 00 |.....| >>> Flow 3 (client to server) -00000000 16 03 01 00 86 10 00 00 82 00 80 2e af d2 61 f6 |..............a.| -00000010 e2 b8 24 da 28 17 55 99 fd 11 bd 7a ab 98 dd f2 |..$.(.U....z....| -00000020 f6 5f e0 11 6b 12 61 6f 86 48 b2 6e db f0 dd d5 |._..k.ao.H.n....| -00000030 07 88 e5 95 f4 2d 6b 0c d0 09 1a 5e 5f 50 1f dc |.....-k....^_P..| -00000040 f2 e7 02 7d 5e a0 70 29 80 ef 87 aa cc 95 3f 2e |...}^.p)......?.| -00000050 24 d1 40 b6 62 53 1d 25 31 87 1e 2f 77 d3 e1 1c |$.@.bS.%1../w...| -00000060 c4 99 89 bc 99 09 e9 ad 1f ce 09 e6 36 1c 3e 97 |............6.>.| -00000070 be 62 69 a0 4e 14 20 9c 82 2a 3e fc 7e 9b c4 7a |.bi.N. ..*>.~..z| -00000080 5a f7 ad 1a 03 17 2a f8 7a 5f 44 14 03 01 00 01 |Z.....*.z_D.....| -00000090 01 16 03 01 00 28 49 6b da 73 07 ad 85 9a 0e fb |.....(Ik.s......| -000000a0 dd e0 69 ef c9 22 2d 86 91 51 26 63 d0 24 7d 16 |..i.."-..Q&c.$}.| -000000b0 3c db 9b 00 c9 7e 64 e2 69 02 85 7d f7 47 |<....~d.i..}.G| +00000000 16 03 01 00 86 10 00 00 82 00 80 1f 4d 12 64 f2 |............M.d.| +00000010 72 22 86 4a 16 05 3f d2 1b e5 ed a7 f1 19 c4 6d |r".J..?........m| +00000020 1d 3a 5c f6 46 8f b9 4d 9e c4 d4 19 95 0a 63 9f |.:\.F..M......c.| +00000030 8a 41 1f fc d5 98 45 ca 69 33 37 64 d5 c8 0e 5a |.A....E.i37d...Z| +00000040 12 9f 06 54 8a 61 8b 13 f0 d8 fb b9 97 fb cd 1d |...T.a..........| +00000050 bd 6c 88 cc 98 57 c3 66 3a 86 04 c9 b9 21 c6 f2 |.l...W.f:....!..| +00000060 f3 43 7d 4e bf 28 d5 a2 d7 39 e0 78 cb eb b4 af |.C}N.(...9.x....| +00000070 21 0e ae 4c 16 9b b3 49 5f 81 02 55 59 97 d9 d2 |!..L...I_..UY...| +00000080 c4 e2 4c be 0a a6 41 62 48 1d 66 14 03 01 00 01 |..L...AbH.f.....| +00000090 01 16 03 01 00 28 9d e0 c3 31 82 c2 48 5d fb 47 |.....(...1..H].G| +000000a0 85 60 d4 17 d2 4f 4d 3c 64 db e4 49 1f a9 66 93 |.`...OM>> Flow 4 (server to client) -00000000 14 03 01 00 01 01 16 03 01 00 28 dc 60 83 43 6c |..........(.`.Cl| -00000010 37 79 ab 6e 92 1f 66 d0 b1 12 ce c1 64 9d 2b 68 |7y.n..f.....d.+h| -00000020 c7 1a e5 1f 8c 80 08 d2 86 3e a1 2c e3 7e f4 64 |.........>.,.~.d| -00000030 e7 96 b2 17 03 01 00 18 8d b5 7c 03 78 cf dc 09 |..........|.x...| -00000040 95 06 4b a6 82 f9 30 d2 6b 26 cb 0a 9a 9d 47 9f |..K...0.k&....G.| -00000050 17 03 01 00 28 30 a9 55 dd b9 4d 6a 76 00 39 96 |....(0.U..Mjv.9.| -00000060 a3 94 6a df e5 af 1e a2 eb bb e4 ac 95 2c f7 93 |..j..........,..| -00000070 ef d1 b5 13 d8 e2 06 1a ad 5c 00 dd 0c 15 03 01 |.........\......| -00000080 00 18 a5 62 e4 8b 51 1d 28 46 bc 8a c8 50 a3 32 |...b..Q.(F...P.2| -00000090 6b 7b f1 b6 19 43 63 1f 7d 38 |k{...Cc.}8| +00000000 14 03 01 00 01 01 16 03 01 00 28 94 66 8f ad 8f |..........(.f...| +00000010 9f 00 72 f6 af 51 47 67 63 df 3f dd 17 09 0a c5 |..r..QGgc.?.....| +00000020 bf f8 4d 66 39 f9 b5 47 01 f8 e8 6d ed b4 17 39 |..Mf9..G...m...9| +00000030 ff 0a ca 17 03 01 00 18 68 93 94 51 12 b9 17 0b |........h..Q....| +00000040 d1 a0 22 fc cc c4 76 1a 1e 02 c6 20 5e 74 83 4c |.."...v.... ^t.L| +00000050 17 03 01 00 28 08 bd 86 07 84 90 78 bd 1d 90 ce |....(......x....| +00000060 09 80 bb d8 de fd 39 82 4b c4 0d 06 f3 65 f5 5b |......9.K....e.[| +00000070 3d c3 fd 69 80 1f 51 ce 1d 98 f1 05 fa 15 03 01 |=..i..Q.........| +00000080 00 18 ed 48 04 21 85 77 d7 b6 29 e3 25 af ea ec |...H.!.w..).%...| +00000090 3e 41 82 a0 ca 7d 44 79 8a 0b |>A...}Dy..| diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv10-RSA-AES b/libgo/go/crypto/tls/testdata/Server-TLSv10-RSA-AES index 1670997b0d0..46713022890 100644 --- a/libgo/go/crypto/tls/testdata/Server-TLSv10-RSA-AES +++ b/libgo/go/crypto/tls/testdata/Server-TLSv10-RSA-AES @@ -1,82 +1,77 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 36 01 00 00 32 03 01 52 cc 57 59 5d |....6...2..R.WY]| -00000010 0d 77 24 3e b3 32 3d ba 0f b0 aa 1d e3 13 06 f6 |.w$>.2=.........| -00000020 0f be 3c 92 ba 93 bd a6 6d 69 53 00 00 04 00 2f |..<.....miS..../| +00000000 16 03 01 00 36 01 00 00 32 03 01 8c 5a 87 31 6a |....6...2...Z.1j| +00000010 8c 7a d5 26 4b 94 17 27 fc a2 c0 5f b5 bc 3f 10 |.z.&K..'..._..?.| +00000020 80 0e e0 1e 36 80 4b 91 61 77 d4 00 00 04 00 2f |....6.K.aw...../| 00000030 00 ff 01 00 00 05 00 0f 00 01 01 |...........| >>> Flow 2 (server to client) 00000000 16 03 01 00 31 02 00 00 2d 03 01 00 00 00 00 00 |....1...-.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2f 00 00 |............./..| -00000030 05 ff 01 00 01 00 16 03 01 02 be 0b 00 02 ba 00 |................| -00000040 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......| -00000050 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..| -00000060 09 2a 86 48 86 f7 0d 01 01 05 05 00 30 45 31 0b |.*.H........0E1.| -00000070 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 |0...U....AU1.0..| -00000080 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 |.U....Some-State| -00000090 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 |1!0...U....Inter| -000000a0 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 |net Widgits Pty | -000000b0 4c 74 64 30 1e 17 0d 31 30 30 34 32 34 30 39 30 |Ltd0...100424090| -000000c0 39 33 38 5a 17 0d 31 31 30 34 32 34 30 39 30 39 |938Z..1104240909| -000000d0 33 38 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 |38Z0E1.0...U....| -000000e0 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som| -000000f0 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..| -00000100 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi| -00000110 74 73 20 50 74 79 20 4c 74 64 30 81 9f 30 0d 06 |ts Pty Ltd0..0..| -00000120 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 |.*.H............| -00000130 30 81 89 02 81 81 00 bb 79 d6 f5 17 b5 e5 bf 46 |0.......y......F| -00000140 10 d0 dc 69 be e6 2b 07 43 5a d0 03 2d 8a 7a 43 |...i..+.CZ..-.zC| -00000150 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 8c b5 b4 82 |...R..eL,x.#....| -00000160 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 fe 12 5c 7a |....;~b.,.3...\z| -00000170 56 fc f5 06 bf fa 58 7b 26 3f b5 cd 04 d3 d0 c9 |V.....X{&?......| -00000180 21 96 4a c7 f4 54 9f 5a bf ef 42 71 00 fe 18 99 |!.J..T.Z..Bq....| -00000190 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e db 51 c9 7c |..~.}}..9....Q.|| -000001a0 e3 c0 4c 3b 32 66 01 cf af b1 1d b8 71 9a 1d db |..L;2f......q...| -000001b0 db 89 6b ae da 2d 79 02 03 01 00 01 a3 81 a7 30 |..k..-y........0| -000001c0 81 a4 30 1d 06 03 55 1d 0e 04 16 04 14 b1 ad e2 |..0...U.........| -000001d0 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 88 |.Z..(.i.#i..&...| -000001e0 39 30 75 06 03 55 1d 23 04 6e 30 6c 80 14 b1 ad |90u..U.#.n0l....| -000001f0 e2 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 |..Z..(.i.#i..&..| -00000200 88 39 a1 49 a4 47 30 45 31 0b 30 09 06 03 55 04 |.9.I.G0E1.0...U.| -00000210 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a |...AU1.0...U....| -00000220 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 |Some-State1!0...| -00000230 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 |U....Internet Wi| -00000240 64 67 69 74 73 20 50 74 79 20 4c 74 64 82 09 00 |dgits Pty Ltd...| -00000250 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 55 1d 13 04 |........0...U...| -00000260 05 30 03 01 01 ff 30 0d 06 09 2a 86 48 86 f7 0d |.0....0...*.H...| -00000270 01 01 05 05 00 03 81 81 00 08 6c 45 24 c7 6b b1 |..........lE$.k.| -00000280 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a 64 75 b5 5a |Y..R.......zdu.Z| -00000290 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f 38 b3 6e 60 |.f..+...f..O8.n`| -000002a0 d3 92 fd f7 41 08 b5 25 13 b1 18 7a 24 fb 30 1d |....A..%...z$.0.| -000002b0 ba ed 98 b9 17 ec e7 d7 31 59 db 95 d3 1d 78 ea |........1Y....x.| -000002c0 50 56 5c d5 82 5a 2d 5a 5f 33 c4 b6 d8 c9 75 90 |PV\..Z-Z_3....u.| -000002d0 96 8c 0f 52 98 b5 cd 98 1f 89 20 5f f2 a0 1c a3 |...R...... _....| -000002e0 1b 96 94 dd a9 fd 57 e9 70 e8 26 6d 71 99 9b 26 |......W.p.&mq..&| -000002f0 6e 38 50 29 6c 90 a7 bd d9 16 03 01 00 04 0e 00 |n8P)l...........| -00000300 00 00 |..| +00000030 05 ff 01 00 01 00 16 03 01 02 71 0b 00 02 6d 00 |..........q...m.| +00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......| +00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..| +00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.| +00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google | +00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..| +00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150| +000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501| +000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..| +000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES| +000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G| +000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....| +000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........| +00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..| +00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.| +00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......| +00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....| +00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........| +00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K| +00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}| +00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....| +00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..| +00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%| +000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........| +000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...| +000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....| +000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.| +000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=| +000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.| +00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp| +00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H| +00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..| +00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....| +00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..| +00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w| +00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k| +00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..| +00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@| +00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...| +000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 01 00 |..A4......9.....| +000002b0 04 0e 00 00 00 |.....| >>> Flow 3 (client to server) -00000000 16 03 01 00 86 10 00 00 82 00 80 20 e6 80 f7 48 |........... ...H| -00000010 7e 7d 08 08 54 e1 b4 e3 98 27 5f 90 9d 3b e3 c2 |~}..T....'_..;..| -00000020 c8 8b dc 9e ff 75 fa fc 60 e1 9e 67 7c c4 08 27 |.....u..`..g|..'| -00000030 cc 6f 15 6c bc 7c 96 de 83 8f 98 6d 4a c7 b7 20 |.o.l.|.....mJ.. | -00000040 8c 19 47 5a ff 76 92 0a df df 66 d2 b6 9d 2d 06 |..GZ.v....f...-.| -00000050 fb ac 07 cf 38 08 f1 fd 0d fe 07 d7 69 3e 8a 79 |....8.......i>.y| -00000060 dc 2d ab bb f7 18 3c 51 14 6e c6 70 95 a2 59 b1 |.-........0| -000000c0 ed c6 bc c2 38 b6 |....8.| +00000000 16 03 01 00 86 10 00 00 82 00 80 31 f5 2e e4 c7 |...........1....| +00000010 f5 76 d6 f7 2d 1b 8d 4d a9 2a 43 84 b2 0b 08 d6 |.v..-..M.*C.....| +00000020 4d d9 9a eb 4b 01 49 6e 11 45 43 0d 31 a7 c3 66 |M...K.In.EC.1..f| +00000030 da 1c 92 68 fb 3d 36 27 94 2f 67 ae 3d 31 a3 8f |...h.=6'./g.=1..| +00000040 01 5a d9 17 92 bc 20 7c cb ae b4 ca 4c ce d4 a9 |.Z.... |....L...| +00000050 2c 1d fe fc 3c a9 14 31 1d 65 08 d8 6e 8d ac 9d |,...<..1.e..n...| +00000060 21 ee 63 4a e2 da 3c 0e b1 34 8f 6e 20 dd d4 d4 |!.cJ..<..4.n ...| +00000070 d8 16 27 5d 02 54 e6 ec 5f 43 84 5b 21 24 ef 5d |..'].T.._C.[!$.]| +00000080 45 c4 2b 2c 98 7d 50 dc 0b fc 76 14 03 01 00 01 |E.+,.}P...v.....| +00000090 01 16 03 01 00 30 ef 50 ea 3c e3 b7 a8 5b 9a d2 |.....0.P.<...[..| +000000a0 11 69 0f d0 5e 79 c8 cb 68 4a ac 16 ef b4 de 1f |.i..^y..hJ......| +000000b0 21 0b 8e 91 cb 70 3f 02 bd 45 c1 34 02 e0 66 8a |!....p?..E.4..f.| +000000c0 00 ea 6c 5a 96 41 |..lZ.A| >>> Flow 4 (server to client) -00000000 14 03 01 00 01 01 16 03 01 00 30 5d 0c a2 18 13 |..........0]....| -00000010 40 a1 84 ce c5 d8 4e fc a4 8a 14 b5 94 18 b1 86 |@.....N.........| -00000020 da 6a 7d 26 08 d6 a0 f8 78 5b 42 7e f8 83 54 56 |.j}&....x[B~..TV| -00000030 36 a4 91 37 67 5a d7 68 37 c4 4f 17 03 01 00 20 |6..7gZ.h7.O.... | -00000040 fd aa 5e cf 4b 12 c5 be a4 a2 65 5d 6e 65 46 5f |..^.K.....e]neF_| -00000050 d2 fe 46 e7 77 2d 9c 1e 0b 39 40 48 c2 2f be 21 |..F.w-...9@H./.!| -00000060 17 03 01 00 30 03 af 9e 6b d6 76 ed 9e 1d 8b 8b |....0...k.v.....| -00000070 2e 2a 5d da c4 73 95 ac 0e 6f 69 cb 63 df 50 27 |.*]..s...oi.c.P'| -00000080 30 de 2e 55 86 85 ad 3e 33 22 49 72 f2 e2 9f 8f |0..U...>3"Ir....| -00000090 ba cf 4e 30 34 15 03 01 00 20 4c 4c 97 61 70 ea |..N04.... LL.ap.| -000000a0 ae fc a2 e9 c6 c2 b6 2e 4d 85 f6 ae 2b 56 46 82 |........M...+VF.| -000000b0 9d d8 a5 82 17 fa 3e 62 67 7e |......>bg~| +00000000 14 03 01 00 01 01 16 03 01 00 30 99 2c 65 32 5f |..........0.,e2_| +00000010 53 37 d8 c2 98 87 f4 68 b6 d7 52 6a 14 c7 df 6e |S7.....h..Rj...n| +00000020 bb ce ae 31 d4 04 24 4d e9 c2 39 7b 68 a7 fa 90 |...1..$M..9{h...| +00000030 c1 30 14 a2 20 c0 8d e1 2a dc 22 17 03 01 00 20 |.0.. ...*.".... | +00000040 41 c5 03 05 20 53 e9 fa 0a 26 38 ab 84 6a 5e 36 |A... S...&8..j^6| +00000050 1b 03 80 2f c3 5c 0b 2c bd 7f 79 68 bb ab 4d 70 |.../.\.,..yh..Mp| +00000060 17 03 01 00 30 a1 04 3e f4 a2 54 7a e7 09 0f 20 |....0..>..Tz... | +00000070 38 f8 9e bb 1b 61 28 bf 46 e8 75 56 b4 c3 93 b9 |8....a(.F.uV....| +00000080 8c 18 3e 8e af 9f 59 1a 96 be db 61 80 56 c6 09 |..>...Y....a.V..| +00000090 3c 21 02 37 d2 15 03 01 00 20 13 d1 81 7d ca 04 |>> Flow 1 (client to server) -00000000 16 03 01 00 36 01 00 00 32 03 01 52 cc 57 59 cf |....6...2..R.WY.| -00000010 00 a1 49 a4 37 69 74 d8 a7 93 ea 8d e7 50 b7 b3 |..I.7it......P..| -00000020 8c ec e5 56 fb dc 5f 1a 2e ab 18 00 00 04 00 05 |...V.._.........| +00000000 16 03 01 00 36 01 00 00 32 03 01 c5 fc 32 c0 09 |....6...2....2..| +00000010 47 0b a9 f3 72 c9 6c 3a e0 94 33 48 35 ac b9 3b |G...r.l:..3H5..;| +00000020 da 5f 8b 6e 0c 54 c3 16 f0 39 bd 00 00 04 00 05 |._.n.T...9......| 00000030 00 ff 01 00 00 05 00 0f 00 01 01 |...........| >>> Flow 2 (server to client) 00000000 16 03 01 00 31 02 00 00 2d 03 01 00 00 00 00 00 |....1...-.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................| -00000030 05 ff 01 00 01 00 16 03 01 02 be 0b 00 02 ba 00 |................| -00000040 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......| -00000050 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..| -00000060 09 2a 86 48 86 f7 0d 01 01 05 05 00 30 45 31 0b |.*.H........0E1.| -00000070 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 |0...U....AU1.0..| -00000080 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 |.U....Some-State| -00000090 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 |1!0...U....Inter| -000000a0 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 |net Widgits Pty | -000000b0 4c 74 64 30 1e 17 0d 31 30 30 34 32 34 30 39 30 |Ltd0...100424090| -000000c0 39 33 38 5a 17 0d 31 31 30 34 32 34 30 39 30 39 |938Z..1104240909| -000000d0 33 38 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 |38Z0E1.0...U....| -000000e0 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som| -000000f0 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..| -00000100 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi| -00000110 74 73 20 50 74 79 20 4c 74 64 30 81 9f 30 0d 06 |ts Pty Ltd0..0..| -00000120 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 |.*.H............| -00000130 30 81 89 02 81 81 00 bb 79 d6 f5 17 b5 e5 bf 46 |0.......y......F| -00000140 10 d0 dc 69 be e6 2b 07 43 5a d0 03 2d 8a 7a 43 |...i..+.CZ..-.zC| -00000150 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 8c b5 b4 82 |...R..eL,x.#....| -00000160 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 fe 12 5c 7a |....;~b.,.3...\z| -00000170 56 fc f5 06 bf fa 58 7b 26 3f b5 cd 04 d3 d0 c9 |V.....X{&?......| -00000180 21 96 4a c7 f4 54 9f 5a bf ef 42 71 00 fe 18 99 |!.J..T.Z..Bq....| -00000190 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e db 51 c9 7c |..~.}}..9....Q.|| -000001a0 e3 c0 4c 3b 32 66 01 cf af b1 1d b8 71 9a 1d db |..L;2f......q...| -000001b0 db 89 6b ae da 2d 79 02 03 01 00 01 a3 81 a7 30 |..k..-y........0| -000001c0 81 a4 30 1d 06 03 55 1d 0e 04 16 04 14 b1 ad e2 |..0...U.........| -000001d0 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 88 |.Z..(.i.#i..&...| -000001e0 39 30 75 06 03 55 1d 23 04 6e 30 6c 80 14 b1 ad |90u..U.#.n0l....| -000001f0 e2 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 |..Z..(.i.#i..&..| -00000200 88 39 a1 49 a4 47 30 45 31 0b 30 09 06 03 55 04 |.9.I.G0E1.0...U.| -00000210 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a |...AU1.0...U....| -00000220 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 |Some-State1!0...| -00000230 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 |U....Internet Wi| -00000240 64 67 69 74 73 20 50 74 79 20 4c 74 64 82 09 00 |dgits Pty Ltd...| -00000250 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 55 1d 13 04 |........0...U...| -00000260 05 30 03 01 01 ff 30 0d 06 09 2a 86 48 86 f7 0d |.0....0...*.H...| -00000270 01 01 05 05 00 03 81 81 00 08 6c 45 24 c7 6b b1 |..........lE$.k.| -00000280 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a 64 75 b5 5a |Y..R.......zdu.Z| -00000290 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f 38 b3 6e 60 |.f..+...f..O8.n`| -000002a0 d3 92 fd f7 41 08 b5 25 13 b1 18 7a 24 fb 30 1d |....A..%...z$.0.| -000002b0 ba ed 98 b9 17 ec e7 d7 31 59 db 95 d3 1d 78 ea |........1Y....x.| -000002c0 50 56 5c d5 82 5a 2d 5a 5f 33 c4 b6 d8 c9 75 90 |PV\..Z-Z_3....u.| -000002d0 96 8c 0f 52 98 b5 cd 98 1f 89 20 5f f2 a0 1c a3 |...R...... _....| -000002e0 1b 96 94 dd a9 fd 57 e9 70 e8 26 6d 71 99 9b 26 |......W.p.&mq..&| -000002f0 6e 38 50 29 6c 90 a7 bd d9 16 03 01 00 04 0e 00 |n8P)l...........| -00000300 00 00 |..| +00000030 05 ff 01 00 01 00 16 03 01 02 71 0b 00 02 6d 00 |..........q...m.| +00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......| +00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..| +00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.| +00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google | +00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..| +00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150| +000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501| +000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..| +000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES| +000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G| +000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....| +000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........| +00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..| +00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.| +00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......| +00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....| +00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........| +00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K| +00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}| +00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....| +00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..| +00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%| +000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........| +000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...| +000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....| +000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.| +000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=| +000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.| +00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp| +00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H| +00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..| +00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....| +00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..| +00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w| +00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k| +00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..| +00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@| +00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...| +000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 01 00 |..A4......9.....| +000002b0 04 0e 00 00 00 |.....| >>> Flow 3 (client to server) -00000000 16 03 01 00 86 10 00 00 82 00 80 b1 96 7b 6f f5 |.............{o.| -00000010 a0 cb 0d 60 9b 64 d3 f5 17 76 47 7b bc a5 0e 96 |...`.d...vG{....| -00000020 53 af 68 0c 96 22 f7 28 0c 24 37 9c 51 69 ed b2 |S.h..".(.$7.Qi..| -00000030 47 14 ba 33 c5 79 6b 96 f2 ab 3c 02 5c 37 a4 97 |G..3.yk...<.\7..| -00000040 23 fc 7f d3 95 2d 85 99 1a 10 1b 38 e5 f1 83 55 |#....-.....8...U| -00000050 4a ab 60 f8 89 0a 6a c4 eb 45 f5 b0 f4 f8 09 31 |J.`...j..E.....1| -00000060 6e f0 25 30 fd 5e 68 61 bc cb 0d 9e 05 73 0a f4 |n.%0.^ha.....s..| -00000070 a5 2e d9 d5 4e 08 f6 3b 8d 2d 21 f5 79 b6 97 55 |....N..;.-!.y..U| -00000080 b9 99 03 49 ea 96 36 49 21 56 bf 14 03 01 00 01 |...I..6I!V......| -00000090 01 16 03 01 00 24 f0 4f 30 06 c3 25 01 93 34 ab |.....$.O0..%..4.| -000000a0 93 8f 59 26 83 6e 8a fd 5a a6 cf af ad b1 a2 83 |..Y&.n..Z.......| -000000b0 28 ff c2 66 5f ac e5 a5 a5 03 |(..f_.....| +00000000 16 03 01 00 86 10 00 00 82 00 80 6a ad 7f e3 26 |...........j...&| +00000010 71 da 48 af 11 63 de 2e e8 50 f9 6a be 04 3d 17 |q.H..c...P.j..=.| +00000020 d1 29 fe 2c 7f b6 26 c1 7e 0b 18 1c 41 62 5c 91 |.).,..&.~...Ab\.| +00000030 ee 26 9c 92 f5 d1 e9 29 e1 ca a7 01 6a 41 b9 00 |.&.....)....jA..| +00000040 34 1d 5b c6 28 0e 1a 8f 32 c5 03 e7 a1 8f 89 1b |4.[.(...2.......| +00000050 af 13 22 2b 5b e8 76 2d 00 ac da 27 75 95 75 e7 |.."+[.v-...'u.u.| +00000060 00 00 39 2c bf f2 01 57 e6 29 e3 26 b1 6b ae c5 |..9,...W.).&.k..| +00000070 8d ce d2 36 b2 94 1f 9c 30 5e b2 16 3d 20 cf 4d |...6....0^..= .M| +00000080 88 f5 ac 4c 27 e3 f5 86 ef 9e dc 14 03 01 00 01 |...L'...........| +00000090 01 16 03 01 00 24 48 d8 80 c4 37 22 31 99 53 30 |.....$H...7"1.S0| +000000a0 5b 00 07 7e 87 2e 59 9a d9 0c 42 9e dd ed da 89 |[..~..Y...B.....| +000000b0 1a 1f cb ab 55 0c ba d9 a9 c0 |....U.....| >>> Flow 4 (server to client) -00000000 14 03 01 00 01 01 16 03 01 00 24 9d b4 ea d8 be |..........$.....| -00000010 b5 9f 00 fd b5 99 04 12 6b 7a 3f b8 52 d7 52 a9 |........kz?.R.R.| -00000020 e9 bd 5b 63 ad b0 53 ac 46 80 be 48 6e dd ee 17 |..[c..S.F..Hn...| -00000030 03 01 00 21 07 ac c4 fb 21 e4 b8 6b 64 3b b5 27 |...!....!..kd;.'| -00000040 29 67 a1 10 2e d2 71 d5 59 5e fc 1d 84 31 15 6e |)g....q.Y^...1.n| -00000050 4d 4b dc a9 3a 15 03 01 00 16 25 22 a5 78 23 5a |MK..:.....%".x#Z| -00000060 69 6f 99 a1 b3 1c 8d bf f3 bd 1b c8 1c 57 15 75 |io...........W.u| +00000000 14 03 01 00 01 01 16 03 01 00 24 ae 00 c8 14 67 |..........$....g| +00000010 4b b5 21 96 98 91 d6 27 40 9b 5e a5 86 53 56 f3 |K.!....'@.^..SV.| +00000020 f6 dc 7e b2 49 78 4b 4d 57 7c 62 a5 f2 16 8f 17 |..~.IxKMW|b.....| +00000030 03 01 00 21 34 e3 48 58 1c 67 fb 3a 46 28 5d a1 |...!4.HX.g.:F(].| +00000040 19 66 58 b1 bb fb e7 17 71 07 3f 0a d0 7c c9 24 |.fX.....q.?..|.$| +00000050 c7 ef 41 af 62 15 03 01 00 16 dd dc 16 dc 16 cc |..A.b...........| +00000060 0d f3 2c 29 00 c0 4f 01 68 05 92 a0 f7 ad e2 63 |..,)..O.h......c| diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv11-RSA-RC4 b/libgo/go/crypto/tls/testdata/Server-TLSv11-RSA-RC4 index 9237db07863..dc5e765e543 100644 --- a/libgo/go/crypto/tls/testdata/Server-TLSv11-RSA-RC4 +++ b/libgo/go/crypto/tls/testdata/Server-TLSv11-RSA-RC4 @@ -1,76 +1,71 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 36 01 00 00 32 03 02 52 cc 57 59 bd |....6...2..R.WY.| -00000010 cd 9d 1e 17 38 43 a5 e3 e7 30 e4 2b 2a ef f7 5b |....8C...0.+*..[| -00000020 81 91 0c 0b 52 f8 2d 2c 61 d3 13 00 00 04 00 05 |....R.-,a.......| +00000000 16 03 01 00 36 01 00 00 32 03 02 ff e1 a1 04 0b |....6...2.......| +00000010 c2 dc fb 7d 07 61 44 9b 00 67 fe 38 73 f5 fc 4e |...}.aD..g.8s..N| +00000020 35 94 0a d5 c1 d0 e7 54 dc 44 1f 00 00 04 00 05 |5......T.D......| 00000030 00 ff 01 00 00 05 00 0f 00 01 01 |...........| >>> Flow 2 (server to client) 00000000 16 03 02 00 31 02 00 00 2d 03 02 00 00 00 00 00 |....1...-.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................| -00000030 05 ff 01 00 01 00 16 03 02 02 be 0b 00 02 ba 00 |................| -00000040 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......| -00000050 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..| -00000060 09 2a 86 48 86 f7 0d 01 01 05 05 00 30 45 31 0b |.*.H........0E1.| -00000070 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 |0...U....AU1.0..| -00000080 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 |.U....Some-State| -00000090 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 |1!0...U....Inter| -000000a0 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 |net Widgits Pty | -000000b0 4c 74 64 30 1e 17 0d 31 30 30 34 32 34 30 39 30 |Ltd0...100424090| -000000c0 39 33 38 5a 17 0d 31 31 30 34 32 34 30 39 30 39 |938Z..1104240909| -000000d0 33 38 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 |38Z0E1.0...U....| -000000e0 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som| -000000f0 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..| -00000100 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi| -00000110 74 73 20 50 74 79 20 4c 74 64 30 81 9f 30 0d 06 |ts Pty Ltd0..0..| -00000120 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 |.*.H............| -00000130 30 81 89 02 81 81 00 bb 79 d6 f5 17 b5 e5 bf 46 |0.......y......F| -00000140 10 d0 dc 69 be e6 2b 07 43 5a d0 03 2d 8a 7a 43 |...i..+.CZ..-.zC| -00000150 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 8c b5 b4 82 |...R..eL,x.#....| -00000160 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 fe 12 5c 7a |....;~b.,.3...\z| -00000170 56 fc f5 06 bf fa 58 7b 26 3f b5 cd 04 d3 d0 c9 |V.....X{&?......| -00000180 21 96 4a c7 f4 54 9f 5a bf ef 42 71 00 fe 18 99 |!.J..T.Z..Bq....| -00000190 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e db 51 c9 7c |..~.}}..9....Q.|| -000001a0 e3 c0 4c 3b 32 66 01 cf af b1 1d b8 71 9a 1d db |..L;2f......q...| -000001b0 db 89 6b ae da 2d 79 02 03 01 00 01 a3 81 a7 30 |..k..-y........0| -000001c0 81 a4 30 1d 06 03 55 1d 0e 04 16 04 14 b1 ad e2 |..0...U.........| -000001d0 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 88 |.Z..(.i.#i..&...| -000001e0 39 30 75 06 03 55 1d 23 04 6e 30 6c 80 14 b1 ad |90u..U.#.n0l....| -000001f0 e2 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 |..Z..(.i.#i..&..| -00000200 88 39 a1 49 a4 47 30 45 31 0b 30 09 06 03 55 04 |.9.I.G0E1.0...U.| -00000210 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a |...AU1.0...U....| -00000220 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 |Some-State1!0...| -00000230 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 |U....Internet Wi| -00000240 64 67 69 74 73 20 50 74 79 20 4c 74 64 82 09 00 |dgits Pty Ltd...| -00000250 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 55 1d 13 04 |........0...U...| -00000260 05 30 03 01 01 ff 30 0d 06 09 2a 86 48 86 f7 0d |.0....0...*.H...| -00000270 01 01 05 05 00 03 81 81 00 08 6c 45 24 c7 6b b1 |..........lE$.k.| -00000280 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a 64 75 b5 5a |Y..R.......zdu.Z| -00000290 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f 38 b3 6e 60 |.f..+...f..O8.n`| -000002a0 d3 92 fd f7 41 08 b5 25 13 b1 18 7a 24 fb 30 1d |....A..%...z$.0.| -000002b0 ba ed 98 b9 17 ec e7 d7 31 59 db 95 d3 1d 78 ea |........1Y....x.| -000002c0 50 56 5c d5 82 5a 2d 5a 5f 33 c4 b6 d8 c9 75 90 |PV\..Z-Z_3....u.| -000002d0 96 8c 0f 52 98 b5 cd 98 1f 89 20 5f f2 a0 1c a3 |...R...... _....| -000002e0 1b 96 94 dd a9 fd 57 e9 70 e8 26 6d 71 99 9b 26 |......W.p.&mq..&| -000002f0 6e 38 50 29 6c 90 a7 bd d9 16 03 02 00 04 0e 00 |n8P)l...........| -00000300 00 00 |..| +00000030 05 ff 01 00 01 00 16 03 02 02 71 0b 00 02 6d 00 |..........q...m.| +00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......| +00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..| +00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.| +00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google | +00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..| +00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150| +000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501| +000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..| +000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES| +000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G| +000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....| +000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........| +00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..| +00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.| +00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......| +00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....| +00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........| +00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K| +00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}| +00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....| +00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..| +00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%| +000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........| +000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...| +000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....| +000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.| +000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=| +000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.| +00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp| +00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H| +00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..| +00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....| +00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..| +00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w| +00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k| +00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..| +00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@| +00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...| +000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 02 00 |..A4......9.....| +000002b0 04 0e 00 00 00 |.....| >>> Flow 3 (client to server) -00000000 16 03 02 00 86 10 00 00 82 00 80 71 2b 19 25 86 |...........q+.%.| -00000010 a0 ff ba d5 1c a6 0c 8b 6b 0a b8 e9 42 93 2f 55 |........k...B./U| -00000020 a8 ee 62 fa ed bc 6d e2 9d e3 76 a6 73 d7 99 58 |..b...m...v.s..X| -00000030 cc 0b 14 42 96 7c b6 c7 8f 21 16 cf 71 9b 2b b9 |...B.|...!..q.+.| -00000040 e0 34 57 76 22 d5 87 8a ce 1f ea 26 6e 1e e6 ca |.4Wv"......&n...| -00000050 55 3b 20 cd cf 42 26 b1 51 3e 8c 1d a2 ae c4 63 |U; ..B&.Q>.....c| -00000060 f5 ce 27 3c 1e c3 e0 e3 b1 16 c1 8a 62 bd 21 7f |..'<........b.!.| -00000070 38 b5 b7 3a 3c bb 03 37 e1 a5 ff f1 29 e2 21 0a |8..:<..7....).!.| -00000080 8c 20 02 e0 c0 82 97 9d 18 6d f8 14 03 02 00 01 |. .......m......| -00000090 01 16 03 02 00 24 bc 19 16 6e fd 0b db 9e d5 1d |.....$...n......| -000000a0 65 b6 57 1c 58 b5 6a ac f7 4f f0 cd a1 a9 0c c0 |e.W.X.j..O......| -000000b0 df e6 eb d5 00 f7 fd 43 bb 27 |.......C.'| +00000000 16 03 02 00 86 10 00 00 82 00 80 4c e0 4d 6a 19 |...........L.Mj.| +00000010 a2 72 2a 3d 41 14 a7 b3 0a 25 11 bf c9 9f cf 8c |.r*=A....%......| +00000020 3c 0b 01 49 aa f1 59 4b 60 ac e5 72 9b ec 20 41 |<..I..YK`..r.. A| +00000030 2f 7e ef bf e0 fe 13 c0 1d fd 51 c5 08 c6 9a 9e |/~........Q.....| +00000040 74 88 c7 e3 36 99 73 fd 00 2d a2 6a bd 25 f2 d7 |t...6.s..-.j.%..| +00000050 24 fd fd ab 0c e0 18 38 ba 7b f0 c9 c0 58 a6 d0 |$......8.{...X..| +00000060 4e e2 59 70 aa f4 52 34 12 a0 ec a4 53 1e 8b ee |N.Yp..R4....S...| +00000070 3e bf a4 87 da 02 4c 95 bd 10 af e8 88 c9 ce 87 |>.....L.........| +00000080 3c 9e 91 70 91 a0 85 18 84 e4 e0 14 03 02 00 01 |<..p............| +00000090 01 16 03 02 00 24 c5 c0 27 71 49 ad ed 37 e6 5d |.....$..'qI..7.]| +000000a0 1b 78 3e 74 15 b7 61 e5 f3 af 1e d0 a2 85 b3 13 |.x>t..a.........| +000000b0 6e 5e 9a c7 3d 47 32 4d 1b 8d |n^..=G2M..| >>> Flow 4 (server to client) -00000000 14 03 02 00 01 01 16 03 02 00 24 cf 4f e4 27 b0 |..........$.O.'.| -00000010 3d 17 34 b1 3c 37 6e c5 2b 3d 4a c3 46 50 44 b4 |=.4.<7n.+=J.FPD.| -00000020 de 77 18 10 4f 60 b3 4e dc 06 fd 25 ec 05 15 17 |.w..O`.N...%....| -00000030 03 02 00 21 a5 c9 32 f2 21 fb 94 7e 0d 15 65 fd |...!..2.!..~..e.| -00000040 3e fe e4 c1 a5 e9 88 72 b2 f1 26 39 a6 48 59 97 |>......r..&9.HY.| -00000050 65 e3 f0 cb 46 15 03 02 00 16 4b 02 ec cd ca 30 |e...F.....K....0| -00000060 42 cf 3d a0 4a fa 8e 79 bb ed b0 59 40 9b 2c 1a |B.=.J..y...Y@.,.| +00000000 14 03 02 00 01 01 16 03 02 00 24 31 22 76 4d 43 |..........$1"vMC| +00000010 7a 8a 58 2c 7d 1c 41 39 bf 08 7e 82 17 55 52 b3 |z.X,}.A9..~..UR.| +00000020 81 bd 7a f8 3c bf 9c 2b f0 9b 3f 65 f5 42 15 17 |..z.<..+..?e.B..| +00000030 03 02 00 21 b1 cc e5 56 16 70 58 0b 91 3c 8c 46 |...!...V.pX..<.F| +00000040 0e 3b b6 fe 32 5d 2e b0 8c 6a 1c a0 82 c9 43 81 |.;..2]...j....C.| +00000050 cf 07 25 47 c9 15 03 02 00 16 53 91 04 70 ba 03 |..%G......S..p..| +00000060 53 69 57 86 3b 2f 8b 97 37 7c b8 85 46 b6 72 42 |SiW.;/..7|..F.rB| diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-ALPN b/libgo/go/crypto/tls/testdata/Server-TLSv12-ALPN index 106244d5a22..cbfeb42eb06 100644 --- a/libgo/go/crypto/tls/testdata/Server-TLSv12-ALPN +++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-ALPN @@ -1,122 +1,109 @@ >>> Flow 1 (client to server) -00000000 16 03 01 01 8a 01 00 01 86 03 03 34 54 69 f3 d7 |...........4Ti..| -00000010 20 9d 1d 74 db 72 e9 2f 51 7c c2 82 0a 9b cb 6d | ..t.r./Q|.....m| -00000020 90 b4 8e a2 1f 2f c7 66 74 8f 33 00 00 d6 c0 30 |...../.ft.3....0| -00000030 c0 2c c0 28 c0 24 c0 14 c0 0a c0 22 c0 21 c0 20 |.,.(.$.....".!. | -00000040 00 a5 00 a3 00 a1 00 9f 00 6b 00 6a 00 69 00 68 |.........k.j.i.h| -00000050 00 39 00 38 00 37 00 36 00 88 00 87 00 86 00 85 |.9.8.7.6........| -00000060 c0 32 c0 2e c0 2a c0 26 c0 0f c0 05 00 9d 00 3d |.2...*.&.......=| -00000070 00 35 00 84 c0 2f c0 2b c0 27 c0 23 c0 13 c0 09 |.5.../.+.'.#....| -00000080 c0 1f c0 1e c0 1d 00 a4 00 a2 00 a0 00 9e 00 67 |...............g| -00000090 00 40 00 3f 00 3e 00 33 00 32 00 31 00 30 00 9a |.@.?.>.3.2.1.0..| -000000a0 00 99 00 98 00 97 00 45 00 44 00 43 00 42 c0 31 |.......E.D.C.B.1| -000000b0 c0 2d c0 29 c0 25 c0 0e c0 04 00 9c 00 3c 00 2f |.-.).%.......<./| -000000c0 00 96 00 41 00 07 c0 11 c0 07 c0 0c c0 02 00 05 |...A............| -000000d0 00 04 c0 12 c0 08 c0 1c c0 1b c0 1a 00 16 00 13 |................| -000000e0 00 10 00 0d c0 0d c0 03 00 0a 00 15 00 12 00 0f |................| -000000f0 00 0c 00 09 00 14 00 11 00 0e 00 0b 00 08 00 06 |................| -00000100 00 03 00 ff 01 00 00 87 00 0b 00 04 03 00 01 02 |................| -00000110 00 0a 00 3a 00 38 00 0e 00 0d 00 19 00 1c 00 0b |...:.8..........| -00000120 00 0c 00 1b 00 18 00 09 00 0a 00 1a 00 16 00 17 |................| -00000130 00 08 00 06 00 07 00 14 00 15 00 04 00 05 00 12 |................| -00000140 00 13 00 01 00 02 00 03 00 0f 00 10 00 11 00 23 |...............#| -00000150 00 00 00 0d 00 20 00 1e 06 01 06 02 06 03 05 01 |..... ..........| -00000160 05 02 05 03 04 01 04 02 04 03 03 01 03 02 03 03 |................| -00000170 02 01 02 02 02 03 00 0f 00 01 01 00 10 00 10 00 |................| -00000180 0e 06 70 72 6f 74 6f 32 06 70 72 6f 74 6f 31 |..proto2.proto1| +00000000 16 03 01 01 4c 01 00 01 48 03 03 44 3b 24 ee 2f |....L...H..D;$./| +00000010 63 3d ca bd 3e c5 bf a2 24 f1 59 c3 54 dc f0 43 |c=..>...$.Y.T..C| +00000020 15 c4 51 f2 29 ea 1b ce 2c fe af 00 00 b6 c0 30 |..Q.)...,......0| +00000030 c0 2c c0 28 c0 24 c0 14 c0 0a 00 a5 00 a3 00 a1 |.,.(.$..........| +00000040 00 9f 00 6b 00 6a 00 69 00 68 00 39 00 38 00 37 |...k.j.i.h.9.8.7| +00000050 00 36 00 88 00 87 00 86 00 85 c0 32 c0 2e c0 2a |.6.........2...*| +00000060 c0 26 c0 0f c0 05 00 9d 00 3d 00 35 00 84 c0 2f |.&.......=.5.../| +00000070 c0 2b c0 27 c0 23 c0 13 c0 09 00 a4 00 a2 00 a0 |.+.'.#..........| +00000080 00 9e 00 67 00 40 00 3f 00 3e 00 33 00 32 00 31 |...g.@.?.>.3.2.1| +00000090 00 30 00 9a 00 99 00 98 00 97 00 45 00 44 00 43 |.0.........E.D.C| +000000a0 00 42 c0 31 c0 2d c0 29 c0 25 c0 0e c0 04 00 9c |.B.1.-.).%......| +000000b0 00 3c 00 2f 00 96 00 41 00 07 c0 11 c0 07 c0 0c |.<./...A........| +000000c0 c0 02 00 05 00 04 c0 12 c0 08 00 16 00 13 00 10 |................| +000000d0 00 0d c0 0d c0 03 00 0a 00 15 00 12 00 0f 00 0c |................| +000000e0 00 09 00 ff 01 00 00 69 00 0b 00 04 03 00 01 02 |.......i........| +000000f0 00 0a 00 1c 00 1a 00 17 00 19 00 1c 00 1b 00 18 |................| +00000100 00 1a 00 16 00 0e 00 0d 00 0b 00 0c 00 09 00 0a |................| +00000110 00 23 00 00 00 0d 00 20 00 1e 06 01 06 02 06 03 |.#..... ........| +00000120 05 01 05 02 05 03 04 01 04 02 04 03 03 01 03 02 |................| +00000130 03 03 02 01 02 02 02 03 00 0f 00 01 01 00 10 00 |................| +00000140 10 00 0e 06 70 72 6f 74 6f 32 06 70 72 6f 74 6f |....proto2.proto| +00000150 31 |1| >>> Flow 2 (server to client) 00000000 16 03 03 00 42 02 00 00 3e 03 03 00 00 00 00 00 |....B...>.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| -00000020 00 00 00 00 00 00 00 00 00 00 00 00 c0 14 00 00 |................| +00000020 00 00 00 00 00 00 00 00 00 00 00 00 c0 30 00 00 |.............0..| 00000030 16 00 23 00 00 ff 01 00 01 00 00 10 00 09 00 07 |..#.............| -00000040 06 70 72 6f 74 6f 31 16 03 03 02 be 0b 00 02 ba |.proto1.........| -00000050 00 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 |......0...0.....| -00000060 02 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d |..............0.| -00000070 06 09 2a 86 48 86 f7 0d 01 01 05 05 00 30 45 31 |..*.H........0E1| -00000080 0b 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 |.0...U....AU1.0.| -00000090 06 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 |..U....Some-Stat| -000000a0 65 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 |e1!0...U....Inte| -000000b0 72 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 |rnet Widgits Pty| -000000c0 20 4c 74 64 30 1e 17 0d 31 30 30 34 32 34 30 39 | Ltd0...10042409| -000000d0 30 39 33 38 5a 17 0d 31 31 30 34 32 34 30 39 30 |0938Z..110424090| -000000e0 39 33 38 5a 30 45 31 0b 30 09 06 03 55 04 06 13 |938Z0E1.0...U...| -000000f0 02 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f |.AU1.0...U....So| -00000100 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 |me-State1!0...U.| -00000110 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 |...Internet Widg| -00000120 69 74 73 20 50 74 79 20 4c 74 64 30 81 9f 30 0d |its Pty Ltd0..0.| -00000130 06 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d |..*.H...........| -00000140 00 30 81 89 02 81 81 00 bb 79 d6 f5 17 b5 e5 bf |.0.......y......| -00000150 46 10 d0 dc 69 be e6 2b 07 43 5a d0 03 2d 8a 7a |F...i..+.CZ..-.z| -00000160 43 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 8c b5 b4 |C...R..eL,x.#...| -00000170 82 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 fe 12 5c |.....;~b.,.3...\| -00000180 7a 56 fc f5 06 bf fa 58 7b 26 3f b5 cd 04 d3 d0 |zV.....X{&?.....| -00000190 c9 21 96 4a c7 f4 54 9f 5a bf ef 42 71 00 fe 18 |.!.J..T.Z..Bq...| -000001a0 99 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e db 51 c9 |...~.}}..9....Q.| -000001b0 7c e3 c0 4c 3b 32 66 01 cf af b1 1d b8 71 9a 1d ||..L;2f......q..| -000001c0 db db 89 6b ae da 2d 79 02 03 01 00 01 a3 81 a7 |...k..-y........| -000001d0 30 81 a4 30 1d 06 03 55 1d 0e 04 16 04 14 b1 ad |0..0...U........| -000001e0 e2 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 |..Z..(.i.#i..&..| -000001f0 88 39 30 75 06 03 55 1d 23 04 6e 30 6c 80 14 b1 |.90u..U.#.n0l...| -00000200 ad e2 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e |...Z..(.i.#i..&.| -00000210 18 88 39 a1 49 a4 47 30 45 31 0b 30 09 06 03 55 |..9.I.G0E1.0...U| -00000220 04 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 |....AU1.0...U...| -00000230 0a 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 |.Some-State1!0..| -00000240 03 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 |.U....Internet W| -00000250 69 64 67 69 74 73 20 50 74 79 20 4c 74 64 82 09 |idgits Pty Ltd..| -00000260 00 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 55 1d 13 |.........0...U..| -00000270 04 05 30 03 01 01 ff 30 0d 06 09 2a 86 48 86 f7 |..0....0...*.H..| -00000280 0d 01 01 05 05 00 03 81 81 00 08 6c 45 24 c7 6b |...........lE$.k| -00000290 b1 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a 64 75 b5 |.Y..R.......zdu.| -000002a0 5a 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f 38 b3 6e |Z.f..+...f..O8.n| -000002b0 60 d3 92 fd f7 41 08 b5 25 13 b1 18 7a 24 fb 30 |`....A..%...z$.0| -000002c0 1d ba ed 98 b9 17 ec e7 d7 31 59 db 95 d3 1d 78 |.........1Y....x| -000002d0 ea 50 56 5c d5 82 5a 2d 5a 5f 33 c4 b6 d8 c9 75 |.PV\..Z-Z_3....u| -000002e0 90 96 8c 0f 52 98 b5 cd 98 1f 89 20 5f f2 a0 1c |....R...... _...| -000002f0 a3 1b 96 94 dd a9 fd 57 e9 70 e8 26 6d 71 99 9b |.......W.p.&mq..| -00000300 26 6e 38 50 29 6c 90 a7 bd d9 16 03 03 00 cd 0c |&n8P)l..........| -00000310 00 00 c9 03 00 17 41 04 1e 18 37 ef 0d 19 51 88 |......A...7...Q.| -00000320 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd a7 24 20 |5uq..T[....g..$ | -00000330 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e f1 07 9f |>.V...(^.+-O....| -00000340 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 a6 b5 68 |lK[.V.2B.X..I..h| -00000350 1a 41 03 56 6b dc 5a 89 04 01 00 80 2d a0 6e 47 |.A.Vk.Z.....-.nG| -00000360 93 a2 19 17 32 f5 42 58 93 f6 4f d4 e9 4d a4 0f |....2.BX..O..M..| -00000370 fe 4e d7 2c 62 b6 fb 83 37 a3 09 60 4b 69 e2 4c |.N.,b...7..`Ki.L| -00000380 fc b8 4c d1 a6 9a 89 a0 c5 76 f5 62 b7 e8 eb c2 |..L......v.b....| -00000390 fa 0f 0e 61 86 bc 70 da 13 72 8d 87 94 16 9a 8d |...a..p..r......| -000003a0 5f 80 82 92 77 37 4f 9e 55 5d dc 35 42 a3 75 5c |_...w7O.U].5B.u\| -000003b0 ec a4 58 78 66 97 97 da 49 67 2e b6 7e 11 de fb |..Xxf...Ig..~...| -000003c0 e3 8f e8 bf 1d 91 1e 91 20 1b 2a df c6 58 e4 82 |........ .*..X..| -000003d0 ce 37 dd 6f a5 ac 51 3d 65 db 3f f5 16 03 03 00 |.7.o..Q=e.?.....| -000003e0 04 0e 00 00 00 |.....| +00000040 06 70 72 6f 74 6f 31 16 03 03 02 71 0b 00 02 6d |.proto1....q...m| +00000050 00 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 |..j..g0..c0.....| +00000060 02 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d |.......s......0.| +00000070 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 |..*.H........0+1| +00000080 17 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 |.0...U....Google| +00000090 20 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 | TESTING1.0...U.| +000000a0 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 |...Go Root0...15| +000000b0 30 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 |0101000000Z..250| +000000c0 31 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 |101000000Z0&1.0.| +000000d0 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 |..U....Google TE| +000000e0 53 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 |STING1.0...U....| +000000f0 47 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 |Go0..0...*.H....| +00000100 01 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af |........0.......| +00000110 87 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 |... ..el..D..;E.| +00000120 e3 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a |..m..cM...jb5..J| +00000130 f9 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 |..|..%^zd1f.....| +00000140 af c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 |..k.v.._A.nV....| +00000150 c1 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da |.<.9!f=+........| +00000160 b7 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 |.......!P.....k.| +00000170 4b 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 |K......l..D..!..| +00000180 7d 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 |}..M........G...| +00000190 03 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d |.......0..0...U.| +000001a0 0f 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d |..........0...U.| +000001b0 25 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 |%..0...+........| +000001c0 08 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 |.+.......0...U..| +000001d0 01 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 |.....0.0...U....| +000001e0 04 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e |...P..o...TMn.i^| +000001f0 06 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf |..0...U.#..0....| +00000200 3d b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 |=..f..@....xH.A0| +00000210 19 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d |...U....0...exam| +00000220 70 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 |ple.golang0...*.| +00000230 48 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af |H.............|.| +00000240 91 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 |.U...Y1.H@.-....| +00000250 a0 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 |....|..0}<.v.O=.| +00000260 fa ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc |..-3$k.{.gY.!...| +00000270 77 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 |w...n.-.5.d_">c.| +00000280 6b be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 |k....m...1..8.;.| +00000290 87 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 |.,...Qv..O......| +000002a0 40 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 |@.Q......F.F.O..| +000002b0 f9 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 |...A4......9....| +000002c0 00 cd 0c 00 00 c9 03 00 17 41 04 1e 18 37 ef 0d |.........A...7..| +000002d0 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.| +000002e0 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.| +000002f0 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I| +00000300 a6 b5 68 1a 41 03 56 6b dc 5a 89 05 01 00 80 40 |..h.A.Vk.Z.....@| +00000310 93 b2 1f 79 3d 56 c0 ae 94 87 c0 a7 28 ef 1d 15 |...y=V......(...| +00000320 be 4b fb 66 e0 60 2c a3 57 ee 56 7d d6 89 b8 8e |.K.f.`,.W.V}....| +00000330 8f 0f 3f 1b c6 9f a4 1d 34 60 b6 9c e9 9b a9 27 |..?.....4`.....'| +00000340 d0 45 7b 04 71 2d db 9c 67 1b d5 d4 fe 19 69 59 |.E{.q-..g.....iY| +00000350 71 8a 35 75 33 a8 c9 f2 4d c4 8f 40 17 a7 25 53 |q.5u3...M..@..%S| +00000360 57 c5 cd ee df a9 3b a3 61 ab e2 a2 ca de 5c 08 |W.....;.a.....\.| +00000370 3d 5b a2 ef cd c8 bc 16 1f 1d 0f 83 9e b7 20 f5 |=[............ .| +00000380 89 3f 09 ba 2e da 12 34 81 e5 2f 8d 3c 90 89 16 |.?.....4../.<...| +00000390 03 03 00 04 0e 00 00 00 |........| >>> Flow 3 (client to server) -00000000 16 03 03 00 46 10 00 00 42 41 04 f3 fc ea d8 50 |....F...BA.....P| -00000010 e6 15 b0 e7 11 c7 6d ee 09 ad 80 d5 54 eb 4f 62 |......m.....T.Ob| -00000020 7d bb a7 2d 28 0c 66 33 42 09 cf 2b 58 f8 58 41 |}..-(.f3B..+X.XA| -00000030 bd 46 51 0a f0 7d 8c 0c 98 9e 26 77 20 fd 5e c1 |.FQ..}....&w .^.| -00000040 a9 b3 e5 c3 6c 05 97 e3 81 fd db 14 03 03 00 01 |....l...........| -00000050 01 16 03 03 00 40 02 2a 28 41 e3 9c 5d 45 d4 45 |.....@.*(A..]E.E| -00000060 51 8c 7a c0 ba b1 8e a4 84 2c f3 83 cd c4 55 5c |Q.z......,....U\| -00000070 d6 5c 6f 72 ab 89 7a c6 d7 9c 2a 54 f0 c4 20 ee |.\or..z...*T.. .| -00000080 37 74 9b b6 8c f7 e4 37 2c eb d4 9f 5c 5e 55 a0 |7t.....7,...\^U.| -00000090 e2 5a fe 1e c8 67 |.Z...g| +00000000 16 03 03 00 46 10 00 00 42 41 04 8b a2 de a6 1e |....F...BA......| +00000010 d9 22 3c 03 4a be 49 2f 40 e3 1e e0 b4 76 7f 78 |."<.J.I/@....v.x| +00000020 96 22 8d 8d c9 45 3b d8 7a ce e3 16 3d 37 ec 80 |."...E;.z...=7..| +00000030 aa 3f d5 19 de c1 2c 7b 7f eb 3c fc 5d c3 52 3b |.?....,{..<.].R;| +00000040 d4 22 25 1c c7 1f 39 c5 23 bd 73 14 03 03 00 01 |."%...9.#.s.....| +00000050 01 16 03 03 00 28 c8 53 0a ad c2 f6 7e 18 08 a3 |.....(.S....~...| +00000060 29 27 20 1c 6c 1d 6c d8 8f 05 31 de e6 ab 7f 22 |)' .l.l...1...."| +00000070 93 6a fb ef b0 f8 43 a9 d3 4f 9d 04 b5 9a |.j....C..O....| >>> Flow 4 (server to client) -00000000 16 03 03 00 72 04 00 00 6e 00 00 00 00 00 68 00 |....r...n.....h.| -00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 65 |...............e| -00000020 ea 8b c0 ef ba 59 31 75 33 96 f1 f8 c9 e1 ef 30 |.....Y1u3......0| -00000030 00 a3 a9 1d ab c8 4b 29 94 f2 c8 c8 8d 03 57 ab |......K)......W.| -00000040 56 df 0f 4e 0d 30 13 09 c9 e4 fa 51 4e b3 26 ad |V..N.0.....QN.&.| -00000050 43 9f ae 62 d5 59 23 05 9b 69 8f 5b a8 ba 39 f1 |C..b.Y#..i.[..9.| -00000060 90 84 35 bf 8f 8d d5 39 93 98 ee b9 75 03 3f 91 |..5....9....u.?.| -00000070 e8 56 0b cb 44 a6 7a 14 03 03 00 01 01 16 03 03 |.V..D.z.........| -00000080 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |.@..............| -00000090 00 00 f9 a0 8e 23 34 f1 61 15 a8 4e ae c4 f3 2a |.....#4.a..N...*| -000000a0 a6 f8 ee 1b 65 c4 c0 ff 93 14 74 ed 82 ae 48 a8 |....e.....t...H.| -000000b0 42 fb a9 24 5d dd fd 98 b8 65 73 03 88 99 e1 ed |B..$]....es.....| -000000c0 02 95 17 03 03 00 40 00 00 00 00 00 00 00 00 00 |......@.........| -000000d0 00 00 00 00 00 00 00 b9 b3 f5 41 84 3b 2a a9 c3 |..........A.;*..| -000000e0 9c e3 d4 38 90 76 c1 8c f0 4f 10 1b 04 b5 07 fe |...8.v...O......| -000000f0 79 3d 7b 77 a4 17 0f 4e df 64 70 70 9e 34 8e b6 |y={w...N.dpp.4..| -00000100 db b2 b6 fd 41 fe b3 15 03 03 00 30 00 00 00 00 |....A......0....| -00000110 00 00 00 00 00 00 00 00 00 00 00 00 02 73 de fe |.............s..| -00000120 fa 4b 69 6d 30 69 79 96 7e 4f 2f 04 67 36 96 27 |.Kim0iy.~O/.g6.'| -00000130 67 23 2b dc 7a c4 6c 34 ea fc 79 fd |g#+.z.l4..y.| +00000000 16 03 03 00 82 04 00 00 7e 00 00 00 00 00 78 50 |........~.....xP| +00000010 46 ad c1 db a8 38 86 7b 2b bb fd d0 c3 42 3e 00 |F....8.{+....B>.| +00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 94 |................| +00000030 6f ec 80 83 61 8e d9 64 ac a2 ee 3b 69 31 79 e1 |o...a..d...;i1y.| +00000040 53 0a 92 1d aa 23 09 c2 49 02 2d 0d 1d c1 63 d6 |S....#..I.-...c.| +00000050 21 56 c7 24 02 28 d5 f1 11 b0 e7 1b 4a 7c 55 af |!V.$.(......J|U.| +00000060 1b c8 32 4c 5b 33 94 b0 ed b0 2f 52 c4 52 81 ee |..2L[3..../R.R..| +00000070 60 6f 66 fb f5 db dd f9 1e 30 11 d4 ca 75 0e 2b |`of......0...u.+| +00000080 ff d0 e5 f2 68 a4 e7 14 03 03 00 01 01 16 03 03 |....h...........| +00000090 00 28 00 00 00 00 00 00 00 00 67 3b 4a ba f3 27 |.(........g;J..'| +000000a0 c8 45 94 68 36 5a 40 e1 dc 67 9b d4 45 58 e9 24 |.E.h6Z@..g..EX.$| +000000b0 31 85 3a f8 5d cb 84 8e 64 05 17 03 03 00 25 00 |1.:.]...d.....%.| +000000c0 00 00 00 00 00 00 01 35 d9 ba 0a e2 3e fd a2 80 |.......5....>...| +000000d0 10 0e 38 7b ad 85 85 48 6a 2a ab 2a 46 c3 59 96 |..8{...Hj*.*F.Y.| +000000e0 fd 75 11 5d 15 03 03 00 1a 00 00 00 00 00 00 00 |.u.]............| +000000f0 02 0b 4d a5 89 4d 86 47 14 60 27 f8 09 bc c9 4d |..M..M.G.`'....M| +00000100 00 31 cb |.1.| diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-ALPN-NoMatch b/libgo/go/crypto/tls/testdata/Server-TLSv12-ALPN-NoMatch index db5881b7685..af75445dc55 100644 --- a/libgo/go/crypto/tls/testdata/Server-TLSv12-ALPN-NoMatch +++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-ALPN-NoMatch @@ -1,121 +1,108 @@ >>> Flow 1 (client to server) -00000000 16 03 01 01 8a 01 00 01 86 03 03 0a a8 82 53 61 |..............Sa| -00000010 68 e0 83 91 71 36 f9 c1 19 ff e8 09 fc 21 9f 03 |h...q6.......!..| -00000020 31 f3 87 4a 04 8c 3d c2 6e 00 32 00 00 d6 c0 30 |1..J..=.n.2....0| -00000030 c0 2c c0 28 c0 24 c0 14 c0 0a c0 22 c0 21 c0 20 |.,.(.$.....".!. | -00000040 00 a5 00 a3 00 a1 00 9f 00 6b 00 6a 00 69 00 68 |.........k.j.i.h| -00000050 00 39 00 38 00 37 00 36 00 88 00 87 00 86 00 85 |.9.8.7.6........| -00000060 c0 32 c0 2e c0 2a c0 26 c0 0f c0 05 00 9d 00 3d |.2...*.&.......=| -00000070 00 35 00 84 c0 2f c0 2b c0 27 c0 23 c0 13 c0 09 |.5.../.+.'.#....| -00000080 c0 1f c0 1e c0 1d 00 a4 00 a2 00 a0 00 9e 00 67 |...............g| -00000090 00 40 00 3f 00 3e 00 33 00 32 00 31 00 30 00 9a |.@.?.>.3.2.1.0..| -000000a0 00 99 00 98 00 97 00 45 00 44 00 43 00 42 c0 31 |.......E.D.C.B.1| -000000b0 c0 2d c0 29 c0 25 c0 0e c0 04 00 9c 00 3c 00 2f |.-.).%.......<./| -000000c0 00 96 00 41 00 07 c0 11 c0 07 c0 0c c0 02 00 05 |...A............| -000000d0 00 04 c0 12 c0 08 c0 1c c0 1b c0 1a 00 16 00 13 |................| -000000e0 00 10 00 0d c0 0d c0 03 00 0a 00 15 00 12 00 0f |................| -000000f0 00 0c 00 09 00 14 00 11 00 0e 00 0b 00 08 00 06 |................| -00000100 00 03 00 ff 01 00 00 87 00 0b 00 04 03 00 01 02 |................| -00000110 00 0a 00 3a 00 38 00 0e 00 0d 00 19 00 1c 00 0b |...:.8..........| -00000120 00 0c 00 1b 00 18 00 09 00 0a 00 1a 00 16 00 17 |................| -00000130 00 08 00 06 00 07 00 14 00 15 00 04 00 05 00 12 |................| -00000140 00 13 00 01 00 02 00 03 00 0f 00 10 00 11 00 23 |...............#| -00000150 00 00 00 0d 00 20 00 1e 06 01 06 02 06 03 05 01 |..... ..........| -00000160 05 02 05 03 04 01 04 02 04 03 03 01 03 02 03 03 |................| -00000170 02 01 02 02 02 03 00 0f 00 01 01 00 10 00 10 00 |................| -00000180 0e 06 70 72 6f 74 6f 32 06 70 72 6f 74 6f 31 |..proto2.proto1| +00000000 16 03 01 01 4c 01 00 01 48 03 03 1d 1a f7 e5 ad |....L...H.......| +00000010 a4 5c fd 61 b4 c2 25 33 c7 b9 fc fb 2b a5 4b fe |.\.a..%3....+.K.| +00000020 16 84 55 4b 9f 68 73 61 b8 92 4d 00 00 b6 c0 30 |..UK.hsa..M....0| +00000030 c0 2c c0 28 c0 24 c0 14 c0 0a 00 a5 00 a3 00 a1 |.,.(.$..........| +00000040 00 9f 00 6b 00 6a 00 69 00 68 00 39 00 38 00 37 |...k.j.i.h.9.8.7| +00000050 00 36 00 88 00 87 00 86 00 85 c0 32 c0 2e c0 2a |.6.........2...*| +00000060 c0 26 c0 0f c0 05 00 9d 00 3d 00 35 00 84 c0 2f |.&.......=.5.../| +00000070 c0 2b c0 27 c0 23 c0 13 c0 09 00 a4 00 a2 00 a0 |.+.'.#..........| +00000080 00 9e 00 67 00 40 00 3f 00 3e 00 33 00 32 00 31 |...g.@.?.>.3.2.1| +00000090 00 30 00 9a 00 99 00 98 00 97 00 45 00 44 00 43 |.0.........E.D.C| +000000a0 00 42 c0 31 c0 2d c0 29 c0 25 c0 0e c0 04 00 9c |.B.1.-.).%......| +000000b0 00 3c 00 2f 00 96 00 41 00 07 c0 11 c0 07 c0 0c |.<./...A........| +000000c0 c0 02 00 05 00 04 c0 12 c0 08 00 16 00 13 00 10 |................| +000000d0 00 0d c0 0d c0 03 00 0a 00 15 00 12 00 0f 00 0c |................| +000000e0 00 09 00 ff 01 00 00 69 00 0b 00 04 03 00 01 02 |.......i........| +000000f0 00 0a 00 1c 00 1a 00 17 00 19 00 1c 00 1b 00 18 |................| +00000100 00 1a 00 16 00 0e 00 0d 00 0b 00 0c 00 09 00 0a |................| +00000110 00 23 00 00 00 0d 00 20 00 1e 06 01 06 02 06 03 |.#..... ........| +00000120 05 01 05 02 05 03 04 01 04 02 04 03 03 01 03 02 |................| +00000130 03 03 02 01 02 02 02 03 00 0f 00 01 01 00 10 00 |................| +00000140 10 00 0e 06 70 72 6f 74 6f 32 06 70 72 6f 74 6f |....proto2.proto| +00000150 31 |1| >>> Flow 2 (server to client) 00000000 16 03 03 00 35 02 00 00 31 03 03 00 00 00 00 00 |....5...1.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| -00000020 00 00 00 00 00 00 00 00 00 00 00 00 c0 14 00 00 |................| -00000030 09 00 23 00 00 ff 01 00 01 00 16 03 03 02 be 0b |..#.............| -00000040 00 02 ba 00 02 b7 00 02 b4 30 82 02 b0 30 82 02 |.........0...0..| -00000050 19 a0 03 02 01 02 02 09 00 85 b0 bb a4 8a 7f b8 |................| -00000060 ca 30 0d 06 09 2a 86 48 86 f7 0d 01 01 05 05 00 |.0...*.H........| -00000070 30 45 31 0b 30 09 06 03 55 04 06 13 02 41 55 31 |0E1.0...U....AU1| -00000080 13 30 11 06 03 55 04 08 13 0a 53 6f 6d 65 2d 53 |.0...U....Some-S| -00000090 74 61 74 65 31 21 30 1f 06 03 55 04 0a 13 18 49 |tate1!0...U....I| -000000a0 6e 74 65 72 6e 65 74 20 57 69 64 67 69 74 73 20 |nternet Widgits | -000000b0 50 74 79 20 4c 74 64 30 1e 17 0d 31 30 30 34 32 |Pty Ltd0...10042| -000000c0 34 30 39 30 39 33 38 5a 17 0d 31 31 30 34 32 34 |4090938Z..110424| -000000d0 30 39 30 39 33 38 5a 30 45 31 0b 30 09 06 03 55 |090938Z0E1.0...U| -000000e0 04 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 |....AU1.0...U...| -000000f0 0a 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 |.Some-State1!0..| -00000100 03 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 |.U....Internet W| -00000110 69 64 67 69 74 73 20 50 74 79 20 4c 74 64 30 81 |idgits Pty Ltd0.| -00000120 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 00 |.0...*.H........| -00000130 03 81 8d 00 30 81 89 02 81 81 00 bb 79 d6 f5 17 |....0.......y...| -00000140 b5 e5 bf 46 10 d0 dc 69 be e6 2b 07 43 5a d0 03 |...F...i..+.CZ..| -00000150 2d 8a 7a 43 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 |-.zC...R..eL,x.#| -00000160 8c b5 b4 82 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 |........;~b.,.3.| -00000170 fe 12 5c 7a 56 fc f5 06 bf fa 58 7b 26 3f b5 cd |..\zV.....X{&?..| -00000180 04 d3 d0 c9 21 96 4a c7 f4 54 9f 5a bf ef 42 71 |....!.J..T.Z..Bq| -00000190 00 fe 18 99 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e |......~.}}..9...| -000001a0 db 51 c9 7c e3 c0 4c 3b 32 66 01 cf af b1 1d b8 |.Q.|..L;2f......| -000001b0 71 9a 1d db db 89 6b ae da 2d 79 02 03 01 00 01 |q.....k..-y.....| -000001c0 a3 81 a7 30 81 a4 30 1d 06 03 55 1d 0e 04 16 04 |...0..0...U.....| -000001d0 14 b1 ad e2 85 5a cf cb 28 db 69 ce 23 69 de d3 |.....Z..(.i.#i..| -000001e0 26 8e 18 88 39 30 75 06 03 55 1d 23 04 6e 30 6c |&...90u..U.#.n0l| -000001f0 80 14 b1 ad e2 85 5a cf cb 28 db 69 ce 23 69 de |......Z..(.i.#i.| -00000200 d3 26 8e 18 88 39 a1 49 a4 47 30 45 31 0b 30 09 |.&...9.I.G0E1.0.| -00000210 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 55 |..U....AU1.0...U| -00000220 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 21 |....Some-State1!| -00000230 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e 65 |0...U....Interne| -00000240 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c 74 |t Widgits Pty Lt| -00000250 64 82 09 00 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 |d...........0...| -00000260 55 1d 13 04 05 30 03 01 01 ff 30 0d 06 09 2a 86 |U....0....0...*.| -00000270 48 86 f7 0d 01 01 05 05 00 03 81 81 00 08 6c 45 |H.............lE| -00000280 24 c7 6b b1 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a |$.k.Y..R.......z| -00000290 64 75 b5 5a 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f |du.Z.f..+...f..O| -000002a0 38 b3 6e 60 d3 92 fd f7 41 08 b5 25 13 b1 18 7a |8.n`....A..%...z| -000002b0 24 fb 30 1d ba ed 98 b9 17 ec e7 d7 31 59 db 95 |$.0.........1Y..| -000002c0 d3 1d 78 ea 50 56 5c d5 82 5a 2d 5a 5f 33 c4 b6 |..x.PV\..Z-Z_3..| -000002d0 d8 c9 75 90 96 8c 0f 52 98 b5 cd 98 1f 89 20 5f |..u....R...... _| -000002e0 f2 a0 1c a3 1b 96 94 dd a9 fd 57 e9 70 e8 26 6d |..........W.p.&m| -000002f0 71 99 9b 26 6e 38 50 29 6c 90 a7 bd d9 16 03 03 |q..&n8P)l.......| -00000300 00 cd 0c 00 00 c9 03 00 17 41 04 1e 18 37 ef 0d |.........A...7..| -00000310 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.| -00000320 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.| -00000330 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I| -00000340 a6 b5 68 1a 41 03 56 6b dc 5a 89 04 01 00 80 b9 |..h.A.Vk.Z......| -00000350 0f 79 8a 16 f4 da 8f 27 b4 16 fc c0 51 db ae d1 |.y.....'....Q...| -00000360 af 79 77 d5 d5 a2 13 05 45 20 cc eb ac ed cb 30 |.yw.....E .....0| -00000370 32 2e 2c bd fa 1c 4d b5 32 a6 37 43 c8 5c 2d f8 |2.,...M.2.7C.\-.| -00000380 6e 85 f5 cd 54 92 29 ad 13 7d d5 9e 8c 1d b7 d0 |n...T.)..}......| -00000390 c1 c7 3d e8 ba 4a 0f 9a a6 3e 25 5f 27 62 b1 00 |..=..J...>%_'b..| -000003a0 91 d9 23 48 3f 10 fe c5 e3 07 9a 58 57 6d cc 10 |..#H?......XWm..| -000003b0 3b f8 1a d5 6e 8b 1f 03 6f 82 84 98 b5 f7 71 5d |;...n...o.....q]| -000003c0 c2 ad 60 14 c1 88 07 5a 3d 99 fd a8 c9 9a 03 16 |..`....Z=.......| -000003d0 03 03 00 04 0e 00 00 00 |........| +00000020 00 00 00 00 00 00 00 00 00 00 00 00 c0 30 00 00 |.............0..| +00000030 09 00 23 00 00 ff 01 00 01 00 16 03 03 02 71 0b |..#...........q.| +00000040 00 02 6d 00 02 6a 00 02 67 30 82 02 63 30 82 01 |..m..j..g0..c0..| +00000050 cc a0 03 02 01 02 02 09 00 a2 73 00 0c 81 00 cb |..........s.....| +00000060 f3 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |.0...*.H........| +00000070 30 2b 31 17 30 15 06 03 55 04 0a 13 0e 47 6f 6f |0+1.0...U....Goo| +00000080 67 6c 65 20 54 45 53 54 49 4e 47 31 10 30 0e 06 |gle TESTING1.0..| +00000090 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..| +000000a0 0d 31 35 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.150101000000Z..| +000000b0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 26 31 |250101000000Z0&1| +000000c0 17 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 |.0...U....Google| +000000d0 20 54 45 53 54 49 4e 47 31 0b 30 09 06 03 55 04 | TESTING1.0...U.| +000000e0 03 13 02 47 6f 30 81 9f 30 0d 06 09 2a 86 48 86 |...Go0..0...*.H.| +000000f0 f7 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 |...........0....| +00000100 81 00 af 87 88 f6 20 1b 95 65 6c 14 ab 44 05 af |...... ..el..D..| +00000110 3b 45 14 e3 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 |;E...m..cM...jb5| +00000120 86 c0 4a f9 18 7c f6 aa 25 5e 7a 64 31 66 00 ba |..J..|..%^zd1f..| +00000130 f4 8e 92 af c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 |.....k.v.._A.nV.| +00000140 97 1b 97 c1 3c 12 39 21 66 3d 2b 16 d1 bc db 1c |....<.9!f=+.....| +00000150 c0 a7 da b7 ca ad ba da cb d5 21 50 ec de 8d ab |..........!P....| +00000160 d1 6b 81 4b 89 02 f3 c4 be c1 6c 89 b1 44 84 bd |.k.K......l..D..| +00000170 21 d1 04 7d 9d 16 4d f9 82 15 f6 ef fa d6 09 47 |!..}..M........G| +00000180 f2 fb 02 03 01 00 01 a3 81 93 30 81 90 30 0e 06 |..........0..0..| +00000190 03 55 1d 0f 01 01 ff 04 04 03 02 05 a0 30 1d 06 |.U...........0..| +000001a0 03 55 1d 25 04 16 30 14 06 08 2b 06 01 05 05 07 |.U.%..0...+.....| +000001b0 03 01 06 08 2b 06 01 05 05 07 03 02 30 0c 06 03 |....+.......0...| +000001c0 55 1d 13 01 01 ff 04 02 30 00 30 19 06 03 55 1d |U.......0.0...U.| +000001d0 0e 04 12 04 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e |......P..o...TMn| +000001e0 cb 69 5e 06 f4 30 1b 06 03 55 1d 23 04 14 30 12 |.i^..0...U.#..0.| +000001f0 80 10 bf 3d b6 a9 66 f2 b8 40 cf ea b4 03 78 48 |...=..f..@....xH| +00000200 1a 41 30 19 06 03 55 1d 11 04 12 30 10 82 0e 65 |.A0...U....0...e| +00000210 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 |xample.golang0..| +00000220 09 2a 86 48 86 f7 0d 01 01 0b 05 00 03 81 81 00 |.*.H............| +00000230 92 7c af 91 55 12 18 96 59 31 a6 48 40 d5 2d d5 |.|..U...Y1.H@.-.| +00000240 ee bb 02 a0 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da |.......|..0}<.v.| +00000250 4f 3d c0 fa ae 2d 33 24 6b 03 7b 1b 67 59 11 21 |O=...-3$k.{.gY.!| +00000260 b5 11 bc 77 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 |...w...n.-.5.d_"| +00000270 3e 63 10 6b be ff 14 86 6d 0d f0 15 31 a8 14 38 |>c.k....m...1..8| +00000280 1e 3b 84 87 2c cb 98 ed 51 76 b9 b1 4f dd db 9b |.;..,...Qv..O...| +00000290 84 04 86 40 fa 51 dd ba b4 8d eb e3 46 de 46 b9 |...@.Q......F.F.| +000002a0 4f 86 c7 f9 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 |O.....A4......9.| +000002b0 16 03 03 00 cd 0c 00 00 c9 03 00 17 41 04 1e 18 |............A...| +000002c0 37 ef 0d 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f |7...Q.5uq..T[...| +000002d0 09 67 fd a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b |.g..$ >.V...(^.+| +000002e0 2d 4f 9e f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 |-O....lK[.V.2B.X| +000002f0 b6 d7 49 a6 b5 68 1a 41 03 56 6b dc 5a 89 05 01 |..I..h.A.Vk.Z...| +00000300 00 80 36 d2 96 c8 27 66 d8 bd 6c 28 29 30 b3 be |..6...'f..l()0..| +00000310 0a bb b2 fe 9d c3 59 47 34 cf de fe f4 ab 5d 79 |......YG4.....]y| +00000320 24 a9 9d c9 b5 e9 50 6a 3b 96 e3 29 cb d7 37 06 |$.....Pj;..)..7.| +00000330 19 08 88 15 29 c2 55 03 62 75 1d 35 c2 8e 25 a2 |....).U.bu.5..%.| +00000340 86 20 bf 18 46 15 81 f2 74 4b bb dd 3d e3 a5 f6 |. ..F...tK..=...| +00000350 28 18 41 89 c8 39 13 f9 c0 88 fd cc f0 6e 9e 3d |(.A..9.......n.=| +00000360 cb 29 ad 26 5b d1 e6 11 5c 64 7d b6 df d7 39 87 |.).&[...\d}...9.| +00000370 24 df 9f 62 17 ef f2 b3 3a b3 88 a4 f0 91 ea f2 |$..b....:.......| +00000380 5d c9 16 03 03 00 04 0e 00 00 00 |]..........| >>> Flow 3 (client to server) -00000000 16 03 03 00 46 10 00 00 42 41 04 76 aa 4e b9 f9 |....F...BA.v.N..| -00000010 68 85 81 74 7c d9 f9 64 7f bd 09 83 08 5b 4f 76 |h..t|..d.....[Ov| -00000020 6e be 79 b6 4e 97 17 63 e4 b5 1c 77 e5 85 76 8a |n.y.N..c...w..v.| -00000030 5d 9f f1 21 88 ec f9 a7 7c 41 af f9 c5 fe 11 81 |]..!....|A......| -00000040 11 51 8e a7 20 33 5f cf e7 90 90 14 03 03 00 01 |.Q.. 3_.........| -00000050 01 16 03 03 00 40 44 3e 32 01 71 ac 5a b5 1f 2c |.....@D>2.q.Z..,| -00000060 37 d9 4b 70 72 91 89 d4 d7 c2 c3 e7 ff dc 72 2a |7.Kpr.........r*| -00000070 ba f5 30 b0 e9 dd 48 10 3d cd 98 48 a3 e3 ca de |..0...H.=..H....| -00000080 15 0e 90 8e e5 04 14 74 42 b8 b0 12 cc 68 7b 7d |.......tB....h{}| -00000090 6c 43 72 60 05 0d |lCr`..| +00000000 16 03 03 00 46 10 00 00 42 41 04 b0 22 15 73 fc |....F...BA..".s.| +00000010 1c fd 24 4a 36 69 8a be ac bd 72 30 bb 6b e1 9b |..$J6i....r0.k..| +00000020 42 e8 56 7a 86 b1 8d cb 9c 3e 2d 63 13 57 a8 13 |B.Vz.....>-c.W..| +00000030 71 3b a2 01 86 af f8 76 40 0b 44 4f 0a 0f 5a da |q;.....v@.DO..Z.| +00000040 31 36 3b 13 c0 10 6c 96 64 a7 24 14 03 03 00 01 |16;...l.d.$.....| +00000050 01 16 03 03 00 28 10 2d 45 93 5c 37 34 d9 2a a0 |.....(.-E.\74.*.| +00000060 b6 37 13 bc a6 1f 0c ce 2e 55 c1 ad 36 b8 60 72 |.7.......U..6.`r| +00000070 81 cb 1a 7a 5b 26 49 ad 77 ef 62 e8 fc 00 |...z[&I.w.b...| >>> Flow 4 (server to client) -00000000 16 03 03 00 72 04 00 00 6e 00 00 00 00 00 68 00 |....r...n.....h.| -00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 65 |...............e| -00000020 ea 8b c0 ef ba 12 45 17 61 24 cd d2 4c 22 bb 3b |......E.a$..L".;| -00000030 e3 0e d0 ff 83 e9 7c b7 8f 10 3c 16 1c fc c2 44 |......|...<....D| -00000040 ef 45 f8 27 30 56 db ea eb ae f5 b6 17 b2 ef f9 |.E.'0V..........| -00000050 96 0d 2d db e4 59 23 0a fc fa e3 13 48 57 e5 b3 |..-..Y#.....HW..| -00000060 3a d1 f5 5e ca ef d7 3f 7b b5 f4 69 85 c3 bd da |:..^...?{..i....| -00000070 fd 9c 50 05 2f 86 ce 14 03 03 00 01 01 16 03 03 |..P./...........| -00000080 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |.@..............| -00000090 00 00 60 25 1c ed 6f c6 a5 bd b2 29 39 4e 09 d1 |..`%..o....)9N..| -000000a0 64 cc 75 cd df 91 a8 90 9d 03 aa 92 07 f2 d0 8a |d.u.............| -000000b0 60 bb 3e 85 21 22 fe f8 dc 52 3c 4e 82 77 14 14 |`.>.!"...R.>}t| -000000e0 0d ac c4 a9 df 67 1c 5a ad 3e 01 34 03 88 2f 39 |.....g.Z.>.4../9| -000000f0 f7 3c 06 e4 f6 81 43 66 b1 1b ed a5 e5 b6 a8 43 |.<....Cf.......C| -00000100 7f 36 2f b2 da 45 9a 15 03 03 00 30 00 00 00 00 |.6/..E.....0....| -00000110 00 00 00 00 00 00 00 00 00 00 00 00 fa 63 4e c5 |.............cN.| -00000120 77 89 71 56 e3 0a cf 98 da 2f 89 8f 74 8e 76 24 |w.qV...../..t.v$| -00000130 e2 40 a5 9f 29 1b b2 11 ef 7a 55 7f |.@..)....zU.| +00000000 16 03 03 00 82 04 00 00 7e 00 00 00 00 00 78 50 |........~.....xP| +00000010 46 ad c1 db a8 38 86 7b 2b bb fd d0 c3 42 3e 00 |F....8.{+....B>.| +00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 94 |................| +00000030 6f ec 80 83 61 05 33 d2 9d 95 89 7b 28 54 50 50 |o...a.3....{(TPP| +00000040 b3 3c 99 5c 82 ab cf 88 24 e8 48 81 db 4a 22 79 |.<.\....$.H..J"y| +00000050 0b fa 33 50 ed 82 a1 7c 33 0e f2 ff 6d a7 d6 88 |..3P...|3...m...| +00000060 29 65 74 e3 27 33 94 97 66 0c 86 ce fc ca 0e 2a |)et.'3..f......*| +00000070 96 fa fe 19 a3 01 64 d9 4d 8e 58 95 5b 74 a6 aa |......d.M.X.[t..| +00000080 f4 9f c1 34 97 2d e5 14 03 03 00 01 01 16 03 03 |...4.-..........| +00000090 00 28 00 00 00 00 00 00 00 00 4d 56 6d d5 6f cc |.(........MVm.o.| +000000a0 3d d4 85 32 3c 07 ea 3c 52 61 88 8e dd d5 d3 d0 |=..2<..D.{n6| +00000100 ae 66 87 |.f.| diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA b/libgo/go/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA index 0ab8b8d74c5..344d9737b25 100644 --- a/libgo/go/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA +++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA @@ -1,91 +1,98 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 ca 01 00 00 c6 03 03 53 04 f1 3f 5f |...........S..?_| -00000010 f4 ef 1f b3 41 0b 54 e4 4d 56 0a 31 22 b8 5c 73 |....A.T.MV.1".\s| -00000020 a3 cb b5 b2 9d 43 f1 83 bc d3 bd 00 00 32 c0 30 |.....C.......2.0| -00000030 c0 2c c0 28 c0 24 c0 14 c0 0a c0 22 c0 21 00 a3 |.,.(.$.....".!..| -00000040 00 9f 00 6b 00 6a 00 39 00 38 00 88 00 87 c0 32 |...k.j.9.8.....2| -00000050 c0 2e c0 2a c0 26 c0 0f c0 05 00 9d 00 3d 00 35 |...*.&.......=.5| -00000060 01 00 00 6b 00 0b 00 04 03 00 01 02 00 0a 00 34 |...k...........4| -00000070 00 32 00 0e 00 0d 00 19 00 0b 00 0c 00 18 00 09 |.2..............| -00000080 00 0a 00 16 00 17 00 08 00 06 00 07 00 14 00 15 |................| -00000090 00 04 00 05 00 12 00 13 00 01 00 02 00 03 00 0f |................| -000000a0 00 10 00 11 00 0d 00 22 00 20 06 01 06 02 06 03 |.......". ......| -000000b0 05 01 05 02 05 03 04 01 04 02 04 03 03 01 03 02 |................| -000000c0 03 03 02 01 02 02 02 03 01 01 00 0f 00 01 01 |...............| +00000000 16 03 01 01 34 01 00 01 30 03 03 78 08 b2 d4 18 |....4...0..x....| +00000010 8e b1 6b a2 d2 e0 c6 41 02 c5 93 f1 b9 60 94 e8 |..k....A.....`..| +00000020 f2 64 6c 97 50 2d 24 a3 cd c0 36 00 00 b6 c0 30 |.dl.P-$...6....0| +00000030 c0 2c c0 28 c0 24 c0 14 c0 0a 00 a5 00 a3 00 a1 |.,.(.$..........| +00000040 00 9f 00 6b 00 6a 00 69 00 68 00 39 00 38 00 37 |...k.j.i.h.9.8.7| +00000050 00 36 00 88 00 87 00 86 00 85 c0 32 c0 2e c0 2a |.6.........2...*| +00000060 c0 26 c0 0f c0 05 00 9d 00 3d 00 35 00 84 c0 2f |.&.......=.5.../| +00000070 c0 2b c0 27 c0 23 c0 13 c0 09 00 a4 00 a2 00 a0 |.+.'.#..........| +00000080 00 9e 00 67 00 40 00 3f 00 3e 00 33 00 32 00 31 |...g.@.?.>.3.2.1| +00000090 00 30 00 9a 00 99 00 98 00 97 00 45 00 44 00 43 |.0.........E.D.C| +000000a0 00 42 c0 31 c0 2d c0 29 c0 25 c0 0e c0 04 00 9c |.B.1.-.).%......| +000000b0 00 3c 00 2f 00 96 00 41 00 07 c0 11 c0 07 c0 0c |.<./...A........| +000000c0 c0 02 00 05 00 04 c0 12 c0 08 00 16 00 13 00 10 |................| +000000d0 00 0d c0 0d c0 03 00 0a 00 15 00 12 00 0f 00 0c |................| +000000e0 00 09 00 ff 01 00 00 51 00 0b 00 04 03 00 01 02 |.......Q........| +000000f0 00 0a 00 1c 00 1a 00 17 00 19 00 1c 00 1b 00 18 |................| +00000100 00 1a 00 16 00 0e 00 0d 00 0b 00 0c 00 09 00 0a |................| +00000110 00 0d 00 20 00 1e 06 01 06 02 06 03 05 01 05 02 |... ............| +00000120 05 03 04 01 04 02 04 03 03 01 03 02 03 03 02 01 |................| +00000130 02 02 02 03 00 0f 00 01 01 |.........| >>> Flow 2 (server to client) -00000000 16 03 03 00 2a 02 00 00 26 03 03 00 00 00 00 00 |....*...&.......| +00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| -00000020 00 00 00 00 00 00 00 00 00 00 00 00 c0 0a 00 16 |................| -00000030 03 03 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 |..............0.| -00000040 02 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb |..0..b.....-G...| -00000050 f4 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 0b |.0...*.H.=..0E1.| -00000060 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 |0...U....AU1.0..| -00000070 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 |.U....Some-State| -00000080 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 |1!0...U....Inter| -00000090 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 |net Widgits Pty | -000000a0 4c 74 64 30 1e 17 0d 31 32 31 31 32 32 31 35 30 |Ltd0...121122150| -000000b0 36 33 32 5a 17 0d 32 32 31 31 32 30 31 35 30 36 |632Z..2211201506| -000000c0 33 32 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 |32Z0E1.0...U....| -000000d0 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som| -000000e0 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..| -000000f0 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi| -00000100 74 73 20 50 74 79 20 4c 74 64 30 81 9b 30 10 06 |ts Pty Ltd0..0..| -00000110 07 2a 86 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 |.*.H.=....+...#.| -00000120 81 86 00 04 00 c4 a1 ed be 98 f9 0b 48 73 36 7e |............Hs6~| -00000130 c3 16 56 11 22 f2 3d 53 c3 3b 4d 21 3d cd 6b 75 |..V.".=S.;M!=.ku| -00000140 e6 f6 b0 dc 9a df 26 c1 bc b2 87 f0 72 32 7c b3 |......&.....r2|.| -00000150 64 2f 1c 90 bc ea 68 23 10 7e fe e3 25 c0 48 3a |d/....h#.~..%.H:| -00000160 69 e0 28 6d d3 37 00 ef 04 62 dd 0d a0 9c 70 62 |i.(m.7...b....pb| -00000170 83 d8 81 d3 64 31 aa 9e 97 31 bd 96 b0 68 c0 9b |....d1...1...h..| -00000180 23 de 76 64 3f 1a 5c 7f e9 12 0e 58 58 b6 5f 70 |#.vd?.\....XX._p| -00000190 dd 9b d8 ea d5 d7 f5 d5 cc b9 b6 9f 30 66 5b 66 |............0f[f| -000001a0 9a 20 e2 27 e5 bf fe 3b 30 09 06 07 2a 86 48 ce |. .'...;0...*.H.| -000001b0 3d 04 01 03 81 8c 00 30 81 88 02 42 01 88 a2 4f |=......0...B...O| -000001c0 eb e2 45 c5 48 7d 1b ac f5 ed 98 9d ae 47 70 c0 |..E.H}.......Gp.| -000001d0 5e 1b b6 2f bd f1 b6 4d b7 61 40 d3 11 a2 ce ee |^../...M.a@.....| -000001e0 0b 7e 92 7e ff 76 9d c3 3b 7e a5 3f ce fa 10 e2 |.~.~.v..;~.?....| -000001f0 59 ec 47 2d 7c ac da 4e 97 0e 15 a0 6f d0 02 42 |Y.G-|..N....o..B| -00000200 01 4d fc be 67 13 9c 2d 05 0e bd 3f a3 8c 25 c1 |.M..g..-...?..%.| -00000210 33 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e |3.......7z..z...| -00000220 dd d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 |...i..|V..1x+..x| -00000230 0d ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 |.....N6$1{j.9...| -00000240 8f 2a 16 03 03 00 d8 0c 00 00 d4 03 00 17 41 04 |.*............A.| -00000250 1e 18 37 ef 0d 19 51 88 35 75 71 b5 e5 54 5b 12 |..7...Q.5uq..T[.| -00000260 2e 8f 09 67 fd a7 24 20 3e b2 56 1c ce 97 28 5e |...g..$ >.V...(^| -00000270 f8 2b 2d 4f 9e f1 07 9f 6c 4b 5b 83 56 e2 32 42 |.+-O....lK[.V.2B| -00000280 e9 58 b6 d7 49 a6 b5 68 1a 41 03 56 6b dc 5a 89 |.X..I..h.A.Vk.Z.| -00000290 04 03 00 8b 30 81 88 02 42 00 c6 85 8e 06 b7 04 |....0...B.......| -000002a0 04 e9 cd 9e 3e cb 66 23 95 b4 42 9c 64 81 39 05 |....>.f#..B.d.9.| -000002b0 3f b5 21 f8 28 af 60 6b 4d 3d ba a1 4b 5e 77 ef |?.!.(.`kM=..K^w.| -000002c0 e7 59 28 fe 1d c1 27 a2 ff a8 de 33 48 b3 c1 85 |.Y(...'....3H...| -000002d0 6a 42 9b f9 7e 7e 31 c2 e5 bd 66 02 42 00 ad 7d |jB..~~1...f.B..}| -000002e0 06 35 ab ec 8d ac d4 ba 1b 49 5e 05 5f f0 97 93 |.5.......I^._...| -000002f0 82 b8 2b 8d 91 98 63 8e b4 14 62 db 1e c9 2b 64 |..+...c...b...+d| -00000300 e9 e6 bf 15 5b 67 c2 40 90 c6 1f b7 92 db 4b f6 |....[g.@......K.| -00000310 f4 db ae 82 f1 4f 02 75 52 40 38 10 ff 35 f0 16 |.....O.uR@8..5..| -00000320 03 03 00 04 0e 00 00 00 |........| +00000020 00 00 00 00 00 00 00 00 00 00 00 00 c0 0a 00 00 |................| +00000030 05 ff 01 00 01 00 16 03 03 02 0e 0b 00 02 0a 00 |................| +00000040 02 07 00 02 04 30 82 02 00 30 82 01 62 02 09 00 |.....0...0..b...| +00000050 b8 bf 2d 47 a0 d2 eb f4 30 09 06 07 2a 86 48 ce |..-G....0...*.H.| +00000060 3d 04 01 30 45 31 0b 30 09 06 03 55 04 06 13 02 |=..0E1.0...U....| +00000070 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som| +00000080 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..| +00000090 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi| +000000a0 74 73 20 50 74 79 20 4c 74 64 30 1e 17 0d 31 32 |ts Pty Ltd0...12| +000000b0 31 31 32 32 31 35 30 36 33 32 5a 17 0d 32 32 31 |1122150632Z..221| +000000c0 31 32 30 31 35 30 36 33 32 5a 30 45 31 0b 30 09 |120150632Z0E1.0.| +000000d0 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 55 |..U....AU1.0...U| +000000e0 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 21 |....Some-State1!| +000000f0 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e 65 |0...U....Interne| +00000100 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c 74 |t Widgits Pty Lt| +00000110 64 30 81 9b 30 10 06 07 2a 86 48 ce 3d 02 01 06 |d0..0...*.H.=...| +00000120 05 2b 81 04 00 23 03 81 86 00 04 00 c4 a1 ed be |.+...#..........| +00000130 98 f9 0b 48 73 36 7e c3 16 56 11 22 f2 3d 53 c3 |...Hs6~..V.".=S.| +00000140 3b 4d 21 3d cd 6b 75 e6 f6 b0 dc 9a df 26 c1 bc |;M!=.ku......&..| +00000150 b2 87 f0 72 32 7c b3 64 2f 1c 90 bc ea 68 23 10 |...r2|.d/....h#.| +00000160 7e fe e3 25 c0 48 3a 69 e0 28 6d d3 37 00 ef 04 |~..%.H:i.(m.7...| +00000170 62 dd 0d a0 9c 70 62 83 d8 81 d3 64 31 aa 9e 97 |b....pb....d1...| +00000180 31 bd 96 b0 68 c0 9b 23 de 76 64 3f 1a 5c 7f e9 |1...h..#.vd?.\..| +00000190 12 0e 58 58 b6 5f 70 dd 9b d8 ea d5 d7 f5 d5 cc |..XX._p.........| +000001a0 b9 b6 9f 30 66 5b 66 9a 20 e2 27 e5 bf fe 3b 30 |...0f[f. .'...;0| +000001b0 09 06 07 2a 86 48 ce 3d 04 01 03 81 8c 00 30 81 |...*.H.=......0.| +000001c0 88 02 42 01 88 a2 4f eb e2 45 c5 48 7d 1b ac f5 |..B...O..E.H}...| +000001d0 ed 98 9d ae 47 70 c0 5e 1b b6 2f bd f1 b6 4d b7 |....Gp.^../...M.| +000001e0 61 40 d3 11 a2 ce ee 0b 7e 92 7e ff 76 9d c3 3b |a@......~.~.v..;| +000001f0 7e a5 3f ce fa 10 e2 59 ec 47 2d 7c ac da 4e 97 |~.?....Y.G-|..N.| +00000200 0e 15 a0 6f d0 02 42 01 4d fc be 67 13 9c 2d 05 |...o..B.M..g..-.| +00000210 0e bd 3f a3 8c 25 c1 33 13 83 0d 94 06 bb d4 37 |..?..%.3.......7| +00000220 7a f6 ec 7a c9 86 2e dd d7 11 69 7f 85 7c 56 de |z..z......i..|V.| +00000230 fb 31 78 2b e4 c7 78 0d ae cb be 9e 4e 36 24 31 |.1x+..x.....N6$1| +00000240 7b 6a 0f 39 95 12 07 8f 2a 16 03 03 00 d8 0c 00 |{j.9....*.......| +00000250 00 d4 03 00 17 41 04 1e 18 37 ef 0d 19 51 88 35 |.....A...7...Q.5| +00000260 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd a7 24 20 3e |uq..T[....g..$ >| +00000270 b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e f1 07 9f 6c |.V...(^.+-O....l| +00000280 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 a6 b5 68 1a |K[.V.2B.X..I..h.| +00000290 41 03 56 6b dc 5a 89 05 03 00 8b 30 81 88 02 42 |A.Vk.Z.....0...B| +000002a0 00 91 b4 4a f2 9d 13 a1 6d 3b ee 46 2f 3b 97 50 |...J....m;.F/;.P| +000002b0 b9 3e 28 7a 51 7a 8b 3b a6 16 03 d6 1f 92 0a ec |.>(zQz.;........| +000002c0 5b 9b b5 48 98 ce d8 22 bd 7d eb cb 14 7b 14 73 |[..H...".}...{.s| +000002d0 2d 5f 01 8c dc 5a 63 34 92 4e 59 4a 90 f9 b1 c9 |-_...Zc4.NYJ....| +000002e0 d8 18 02 42 01 89 e4 e4 39 d0 52 d1 70 19 fe d7 |...B....9.R.p...| +000002f0 c6 70 10 36 94 1e 45 fd b4 03 37 79 c7 db cf 6d |.p.6..E...7y...m| +00000300 33 5d 80 fe 04 de d1 78 bf c4 dd cf 91 82 57 14 |3].....x......W.| +00000310 14 09 e3 2d dd d2 78 9c 53 cc 1f f7 40 6c 4a 59 |...-..x.S...@lJY| +00000320 49 a8 a1 06 24 18 16 03 03 00 04 0e 00 00 00 |I...$..........| >>> Flow 3 (client to server) -00000000 16 03 03 00 46 10 00 00 42 41 04 d8 94 c4 05 26 |....F...BA.....&| -00000010 76 29 2d 0e ec 47 b6 50 d5 a3 da 2a ba 02 11 37 |v)-..G.P...*...7| -00000020 3d ef e6 2a db d0 47 47 a7 9a 5f 43 2d 98 78 26 |=..*..GG.._C-.x&| -00000030 81 e2 f1 ba fe f7 66 c6 61 cb c1 b7 60 62 34 a5 |......f.a...`b4.| -00000040 78 67 50 3d 9a 0e 4a 8c 8f d7 10 14 03 03 00 01 |xgP=..J.........| -00000050 01 16 03 03 00 40 5e 46 b0 5d 30 f6 da 8f 9e 67 |.....@^F.]0....g| -00000060 f5 3e bd fe c9 b8 53 b2 10 d5 7c 0e 34 e3 93 6d |.>....S...|.4..m| -00000070 0e 8e 8a 2b df fb 9a 0f a5 23 55 e7 0a 4b e2 d3 |...+.....#U..K..| -00000080 db 15 e8 52 74 26 78 b3 b0 56 65 63 ac ae 1e c0 |...Rt&x..Vec....| -00000090 0b f4 92 56 a9 04 |...V..| +00000000 16 03 03 00 46 10 00 00 42 41 04 66 37 3a ce 68 |....F...BA.f7:.h| +00000010 23 0f b2 d0 cb 20 24 26 37 d5 84 46 4a 2e 59 80 |#.... $&7..FJ.Y.| +00000020 87 b3 10 7e 36 fd af 7c 99 07 99 dd 18 af 6d 7c |...~6..|......m|| +00000030 b5 b2 b7 93 45 95 d9 98 1a 13 5b a2 12 e8 b7 95 |....E.....[.....| +00000040 ed a1 3a 6d aa 8f fc b6 b5 b4 41 14 03 03 00 01 |..:m......A.....| +00000050 01 16 03 03 00 40 b0 12 69 00 a4 3a 6d bd 56 40 |.....@..i..:m.V@| +00000060 6e 9d 5e a8 1b 0f 59 c5 09 48 b2 07 d8 bc 7b 02 |n.^...Y..H....{.| +00000070 70 61 f6 1b a9 27 55 8c 16 4d 69 4c ca 31 30 9f |pa...'U..MiL.10.| +00000080 d3 62 ba d4 1b 11 ee 0a a0 f3 61 be c6 64 c3 dc |.b........a..d..| +00000090 97 50 47 27 ed 09 |.PG'..| >>> Flow 4 (server to client) 00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |..........@.....| -00000010 00 00 00 00 00 00 00 00 00 00 00 16 a9 63 0a 99 |.............c..| -00000020 21 8a fc 5c b3 ee 05 71 4e 75 c0 d9 40 54 0d 3e |!..\...qNu..@T.>| -00000030 4e 5d 44 b7 4b 5d a9 e7 5a 30 ed b6 d5 08 50 b1 |N]D.K]..Z0....P.| -00000040 e8 8c 54 eb 1b 39 7a f9 3b ac 2e 17 03 03 00 40 |..T..9z.;......@| +00000010 00 00 00 00 00 00 00 00 00 00 00 09 34 9a eb 7c |............4..|| +00000020 6a 6d 6a 02 7b 50 14 b8 f7 b0 93 30 ea 0b 61 4a |jmj.{P.....0..aJ| +00000030 0b 75 10 39 41 78 46 9d ba 8e d3 e9 e4 ab dc 1f |.u.9AxF.........| +00000040 c9 43 95 e8 f9 d6 3a d3 5d 7d 09 17 03 03 00 40 |.C....:.]}.....@| 00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| -00000060 96 03 20 2b 20 c4 c1 9a 76 7b f3 96 bd 33 ed e6 |.. + ...v{...3..| -00000070 38 48 ea 53 d5 e0 62 b5 7e 1a 36 a8 dd 9f 2d 4b |8H.S..b.~.6...-K| -00000080 06 0d ae f6 bc 99 14 b3 93 14 27 63 e2 a0 c8 76 |..........'c...v| +00000060 b4 64 88 d5 53 f9 1e 47 d4 d8 c4 fa 0e c2 76 a6 |.d..S..G......v.| +00000070 ed 5c 17 ba ea 76 72 cb c5 73 a3 c5 44 21 3c 40 |.\...vr..s..D!<@| +00000080 33 27 09 37 73 3b 0e a3 7b 95 72 10 8d 74 85 19 |3'.7s;..{.r..t..| 00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........| -000000a0 00 00 00 00 00 48 af e1 e4 11 e1 b7 03 19 b0 e3 |.....H..........| -000000b0 e6 a9 66 d8 ac af aa 03 f6 0d 51 df 9a 27 78 3a |..f.......Q..'x:| -000000c0 56 5a 03 1a 4c |VZ..L| +000000a0 00 00 00 00 00 b3 c0 05 e9 ec 05 06 52 ef 09 b7 |............R...| +000000b0 52 29 04 88 ed 11 bb bd 36 a3 0f ce 2c 55 a2 87 |R)......6...,U..| +000000c0 7e 2b 0c aa 83 |~+...| diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA b/libgo/go/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA index 88abb15a7e6..10624c02591 100644 --- a/libgo/go/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA +++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA @@ -1,101 +1,104 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 ca 01 00 00 c6 03 03 53 04 f1 3f cc |...........S..?.| -00000010 41 74 00 07 cb ae 3b 30 79 48 51 60 41 a3 8c ab |At....;0yHQ`A...| -00000020 dc 76 f9 74 52 1e c5 fb a9 69 c2 00 00 32 c0 30 |.v.tR....i...2.0| -00000030 c0 2c c0 28 c0 24 c0 14 c0 0a c0 22 c0 21 00 a3 |.,.(.$.....".!..| -00000040 00 9f 00 6b 00 6a 00 39 00 38 00 88 00 87 c0 32 |...k.j.9.8.....2| -00000050 c0 2e c0 2a c0 26 c0 0f c0 05 00 9d 00 3d 00 35 |...*.&.......=.5| -00000060 01 00 00 6b 00 0b 00 04 03 00 01 02 00 0a 00 34 |...k...........4| -00000070 00 32 00 0e 00 0d 00 19 00 0b 00 0c 00 18 00 09 |.2..............| -00000080 00 0a 00 16 00 17 00 08 00 06 00 07 00 14 00 15 |................| -00000090 00 04 00 05 00 12 00 13 00 01 00 02 00 03 00 0f |................| -000000a0 00 10 00 11 00 0d 00 22 00 20 06 01 06 02 06 03 |.......". ......| -000000b0 05 01 05 02 05 03 04 01 04 02 04 03 03 01 03 02 |................| -000000c0 03 03 02 01 02 02 02 03 01 01 00 0f 00 01 01 |...............| +00000000 16 03 01 01 34 01 00 01 30 03 03 10 5e c8 3f c6 |....4...0...^.?.| +00000010 fe 44 c4 f0 13 c5 bd ad 06 21 65 e5 a8 40 b5 1d |.D.......!e..@..| +00000020 21 07 99 34 5b ef 70 85 29 92 7d 00 00 b6 c0 30 |!..4[.p.).}....0| +00000030 c0 2c c0 28 c0 24 c0 14 c0 0a 00 a5 00 a3 00 a1 |.,.(.$..........| +00000040 00 9f 00 6b 00 6a 00 69 00 68 00 39 00 38 00 37 |...k.j.i.h.9.8.7| +00000050 00 36 00 88 00 87 00 86 00 85 c0 32 c0 2e c0 2a |.6.........2...*| +00000060 c0 26 c0 0f c0 05 00 9d 00 3d 00 35 00 84 c0 2f |.&.......=.5.../| +00000070 c0 2b c0 27 c0 23 c0 13 c0 09 00 a4 00 a2 00 a0 |.+.'.#..........| +00000080 00 9e 00 67 00 40 00 3f 00 3e 00 33 00 32 00 31 |...g.@.?.>.3.2.1| +00000090 00 30 00 9a 00 99 00 98 00 97 00 45 00 44 00 43 |.0.........E.D.C| +000000a0 00 42 c0 31 c0 2d c0 29 c0 25 c0 0e c0 04 00 9c |.B.1.-.).%......| +000000b0 00 3c 00 2f 00 96 00 41 00 07 c0 11 c0 07 c0 0c |.<./...A........| +000000c0 c0 02 00 05 00 04 c0 12 c0 08 00 16 00 13 00 10 |................| +000000d0 00 0d c0 0d c0 03 00 0a 00 15 00 12 00 0f 00 0c |................| +000000e0 00 09 00 ff 01 00 00 51 00 0b 00 04 03 00 01 02 |.......Q........| +000000f0 00 0a 00 1c 00 1a 00 17 00 19 00 1c 00 1b 00 18 |................| +00000100 00 1a 00 16 00 0e 00 0d 00 0b 00 0c 00 09 00 0a |................| +00000110 00 0d 00 20 00 1e 06 01 06 02 06 03 05 01 05 02 |... ............| +00000120 05 03 04 01 04 02 04 03 03 01 03 02 03 03 02 01 |................| +00000130 02 02 02 03 00 0f 00 01 01 |.........| >>> Flow 2 (server to client) -00000000 16 03 03 00 2a 02 00 00 26 03 03 00 00 00 00 00 |....*...&.......| +00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| -00000020 00 00 00 00 00 00 00 00 00 00 00 00 c0 14 00 16 |................| -00000030 03 03 02 be 0b 00 02 ba 00 02 b7 00 02 b4 30 82 |..............0.| -00000040 02 b0 30 82 02 19 a0 03 02 01 02 02 09 00 85 b0 |..0.............| -00000050 bb a4 8a 7f b8 ca 30 0d 06 09 2a 86 48 86 f7 0d |......0...*.H...| -00000060 01 01 05 05 00 30 45 31 0b 30 09 06 03 55 04 06 |.....0E1.0...U..| -00000070 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 |..AU1.0...U....S| -00000080 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 |ome-State1!0...U| -00000090 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 |....Internet Wid| -000000a0 67 69 74 73 20 50 74 79 20 4c 74 64 30 1e 17 0d |gits Pty Ltd0...| -000000b0 31 30 30 34 32 34 30 39 30 39 33 38 5a 17 0d 31 |100424090938Z..1| -000000c0 31 30 34 32 34 30 39 30 39 33 38 5a 30 45 31 0b |10424090938Z0E1.| -000000d0 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 |0...U....AU1.0..| -000000e0 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 |.U....Some-State| -000000f0 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 |1!0...U....Inter| -00000100 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 |net Widgits Pty | -00000110 4c 74 64 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d |Ltd0..0...*.H...| -00000120 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 |.........0......| -00000130 bb 79 d6 f5 17 b5 e5 bf 46 10 d0 dc 69 be e6 2b |.y......F...i..+| -00000140 07 43 5a d0 03 2d 8a 7a 43 85 b7 14 52 e7 a5 65 |.CZ..-.zC...R..e| -00000150 4c 2c 78 b8 23 8c b5 b4 82 e5 de 1f 95 3b 7e 62 |L,x.#........;~b| -00000160 a5 2c a5 33 d6 fe 12 5c 7a 56 fc f5 06 bf fa 58 |.,.3...\zV.....X| -00000170 7b 26 3f b5 cd 04 d3 d0 c9 21 96 4a c7 f4 54 9f |{&?......!.J..T.| -00000180 5a bf ef 42 71 00 fe 18 99 07 7f 7e 88 7d 7d f1 |Z..Bq......~.}}.| -00000190 04 39 c4 a2 2e db 51 c9 7c e3 c0 4c 3b 32 66 01 |.9....Q.|..L;2f.| -000001a0 cf af b1 1d b8 71 9a 1d db db 89 6b ae da 2d 79 |.....q.....k..-y| -000001b0 02 03 01 00 01 a3 81 a7 30 81 a4 30 1d 06 03 55 |........0..0...U| -000001c0 1d 0e 04 16 04 14 b1 ad e2 85 5a cf cb 28 db 69 |..........Z..(.i| -000001d0 ce 23 69 de d3 26 8e 18 88 39 30 75 06 03 55 1d |.#i..&...90u..U.| -000001e0 23 04 6e 30 6c 80 14 b1 ad e2 85 5a cf cb 28 db |#.n0l......Z..(.| -000001f0 69 ce 23 69 de d3 26 8e 18 88 39 a1 49 a4 47 30 |i.#i..&...9.I.G0| -00000200 45 31 0b 30 09 06 03 55 04 06 13 02 41 55 31 13 |E1.0...U....AU1.| -00000210 30 11 06 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 |0...U....Some-St| -00000220 61 74 65 31 21 30 1f 06 03 55 04 0a 13 18 49 6e |ate1!0...U....In| -00000230 74 65 72 6e 65 74 20 57 69 64 67 69 74 73 20 50 |ternet Widgits P| -00000240 74 79 20 4c 74 64 82 09 00 85 b0 bb a4 8a 7f b8 |ty Ltd..........| -00000250 ca 30 0c 06 03 55 1d 13 04 05 30 03 01 01 ff 30 |.0...U....0....0| -00000260 0d 06 09 2a 86 48 86 f7 0d 01 01 05 05 00 03 81 |...*.H..........| -00000270 81 00 08 6c 45 24 c7 6b b1 59 ab 0c 52 cc f2 b0 |...lE$.k.Y..R...| -00000280 14 d7 87 9d 7a 64 75 b5 5a 95 66 e4 c5 2b 8e ae |....zdu.Z.f..+..| -00000290 12 66 1f eb 4f 38 b3 6e 60 d3 92 fd f7 41 08 b5 |.f..O8.n`....A..| -000002a0 25 13 b1 18 7a 24 fb 30 1d ba ed 98 b9 17 ec e7 |%...z$.0........| -000002b0 d7 31 59 db 95 d3 1d 78 ea 50 56 5c d5 82 5a 2d |.1Y....x.PV\..Z-| -000002c0 5a 5f 33 c4 b6 d8 c9 75 90 96 8c 0f 52 98 b5 cd |Z_3....u....R...| -000002d0 98 1f 89 20 5f f2 a0 1c a3 1b 96 94 dd a9 fd 57 |... _..........W| -000002e0 e9 70 e8 26 6d 71 99 9b 26 6e 38 50 29 6c 90 a7 |.p.&mq..&n8P)l..| -000002f0 bd d9 16 03 03 00 cd 0c 00 00 c9 03 00 17 41 04 |..............A.| -00000300 1e 18 37 ef 0d 19 51 88 35 75 71 b5 e5 54 5b 12 |..7...Q.5uq..T[.| -00000310 2e 8f 09 67 fd a7 24 20 3e b2 56 1c ce 97 28 5e |...g..$ >.V...(^| -00000320 f8 2b 2d 4f 9e f1 07 9f 6c 4b 5b 83 56 e2 32 42 |.+-O....lK[.V.2B| -00000330 e9 58 b6 d7 49 a6 b5 68 1a 41 03 56 6b dc 5a 89 |.X..I..h.A.Vk.Z.| -00000340 04 01 00 80 9d 84 09 35 73 fb f6 ea 94 7b 49 fb |.......5s....{I.| -00000350 c2 70 b1 11 64 5b 93 9f d9 8c f5 56 98 f6 d3 66 |.p..d[.....V...f| -00000360 a6 1d 18 56 88 87 71 3f b0 38 9d 44 1f ad 2c 0d |...V..q?.8.D..,.| -00000370 3a a7 e8 d4 3e 33 3c 41 20 f3 3f 5c e5 fb e3 23 |:...>36as.d...mP| -000003b0 33 55 c7 e1 c5 a5 4c 32 5c 95 dc 07 43 60 49 11 |3U....L2\...C`I.| -000003c0 e9 98 cc ba 16 03 03 00 04 0e 00 00 00 |.............| +00000020 00 00 00 00 00 00 00 00 00 00 00 00 c0 14 00 00 |................| +00000030 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.| +00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......| +00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..| +00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.| +00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google | +00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..| +00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150| +000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501| +000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..| +000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES| +000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G| +000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....| +000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........| +00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..| +00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.| +00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......| +00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....| +00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........| +00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K| +00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}| +00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....| +00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..| +00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%| +000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........| +000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...| +000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....| +000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.| +000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=| +000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.| +00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp| +00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H| +00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..| +00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....| +00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..| +00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w| +00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k| +00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..| +00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@| +00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...| +000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....| +000002b0 cd 0c 00 00 c9 03 00 17 41 04 1e 18 37 ef 0d 19 |........A...7...| +000002c0 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd a7 |Q.5uq..T[....g..| +000002d0 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e f1 |$ >.V...(^.+-O..| +000002e0 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 a6 |..lK[.V.2B.X..I.| +000002f0 b5 68 1a 41 03 56 6b dc 5a 89 05 01 00 80 6a 4b |.h.A.Vk.Z.....jK| +00000300 b1 7d 23 cd 0e cb 26 02 d4 ee 90 f2 e0 4a 47 3d |.}#...&......JG=| +00000310 b3 36 90 8d 01 42 98 92 ad 75 87 71 02 70 02 a8 |.6...B...u.q.p..| +00000320 0c b0 06 ee bd 6a 1f 3f 6c 4b 4b 6b 75 41 23 b4 |.....j.?lKKkuA#.| +00000330 f9 c2 a6 60 e2 de 55 b6 d4 85 62 e9 8f 20 70 ed |...`..U...b.. p.| +00000340 9a b8 bb dd 1f 19 87 e9 ad b3 30 3f 7c 63 51 f1 |..........0?|cQ.| +00000350 59 ab d1 a0 a1 80 22 56 ca 68 52 f8 0f 80 c6 a6 |Y....."V.hR.....| +00000360 9e 12 51 ed 29 d0 6d c2 1a e5 37 dc 76 e3 f3 53 |..Q.).m...7.v..S| +00000370 1b 07 0b ea a6 11 af dc 54 d3 ee 25 cc 27 16 03 |........T..%.'..| +00000380 03 00 04 0e 00 00 00 |.......| >>> Flow 3 (client to server) -00000000 16 03 03 00 46 10 00 00 42 41 04 28 02 84 d5 b4 |....F...BA.(....| -00000010 58 07 47 d5 a0 d6 0b 1d 37 91 e6 34 a4 ad 0b ad |X.G.....7..4....| -00000020 22 01 82 77 a7 32 86 78 83 3a da 75 2f e5 68 7a |"..w.2.x.:.u/.hz| -00000030 de e4 05 e0 02 47 40 4e 38 d2 2c c3 7b da 53 73 |.....G@N8.,.{.Ss| -00000040 19 cb 8b 73 34 72 4d 33 71 39 c8 14 03 03 00 01 |...s4rM3q9......| -00000050 01 16 03 03 00 40 10 63 43 76 83 bd 36 e4 1e 4d |.....@.cCv..6..M| -00000060 7e 13 b0 ac aa c8 ec 90 31 df 84 46 49 68 39 5a |~.......1..FIh9Z| -00000070 05 8b 73 32 86 15 3a 18 57 d8 e2 2c 2d 05 89 93 |..s2..:.W..,-...| -00000080 37 b8 dd 73 33 92 ff a7 b2 53 27 94 b7 25 56 64 |7..s3....S'..%Vd| -00000090 a1 d3 2c f7 6b 71 |..,.kq| +00000000 16 03 03 00 46 10 00 00 42 41 04 2d 4b 0c 6b 65 |....F...BA.-K.ke| +00000010 82 32 95 8b 77 ec f0 f2 b2 ba d1 38 74 ed 82 49 |.2..w......8t..I| +00000020 fb ce 8f 66 97 9d b6 97 d8 ae f5 19 af ad 47 b9 |...f..........G.| +00000030 db 7b d2 c9 4e 10 68 14 ed 23 a5 98 94 f9 2a 00 |.{..N.h..#....*.| +00000040 b6 44 b3 44 01 29 6c 56 da bb a8 14 03 03 00 01 |.D.D.)lV........| +00000050 01 16 03 03 00 40 f4 fd de d6 20 2e 18 80 4e 73 |.....@.... ...Ns| +00000060 af dd 97 42 08 3b 51 80 e9 26 00 48 6b 8b 21 99 |...B.;Q..&.Hk.!.| +00000070 a8 60 1f 64 51 d0 5a 90 8b b0 69 b8 6b 29 59 21 |.`.dQ.Z...i.k)Y!| +00000080 b1 13 19 13 07 01 e1 2c c3 6b 17 2d 01 a5 be d6 |.......,.k.-....| +00000090 b0 0d 3d 6a 8c fe |..=j..| >>> Flow 4 (server to client) 00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |..........@.....| -00000010 00 00 00 00 00 00 00 00 00 00 00 21 5c 31 b1 4b |...........!\1.K| -00000020 96 96 30 8f 79 35 3a 3a 2d 26 67 d0 70 48 be 30 |..0.y5::-&g.pH.0| -00000030 f8 3e e8 c1 cb 1d d5 89 f6 9c 72 bb 1c f9 4d 90 |.>........r...M.| -00000040 9c d7 c6 fa 40 76 a5 61 46 61 24 17 03 03 00 40 |....@v.aFa$....@| +00000010 00 00 00 00 00 00 00 00 00 00 00 84 e2 7f e3 b4 |................| +00000020 53 d7 d0 30 c4 e5 ea 09 df ba 33 b0 02 34 eb 2e |S..0......3..4..| +00000030 b2 ec 47 0d e7 20 76 12 fa 53 3b 44 86 e1 e1 63 |..G.. v..S;D...c| +00000040 06 29 57 98 ce 87 18 ad 02 17 01 17 03 03 00 40 |.)W............@| 00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| -00000060 94 8a 14 04 06 b9 30 a0 67 fd b2 4c 84 f4 10 93 |......0.g..L....| -00000070 7d d4 2b 23 f0 e9 62 93 c2 20 a2 f2 7c 07 21 4b |}.+#..b.. ..|.!K| -00000080 94 ba 7b 7d cb 77 da 85 93 bd 53 ee ca db 9b 3e |..{}.w....S....>| +00000060 b0 3a f5 90 90 30 9c b3 39 5b b4 56 f6 b9 30 7e |.:...0..9[.V..0~| +00000070 8e a8 2d 60 47 b6 57 8a 20 61 02 f2 8e 43 c2 01 |..-`G.W. a...C..| +00000080 ee f0 be 5a 93 52 2f ea 03 2a 4f 01 ea 9e 1c a2 |...Z.R/..*O.....| 00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........| -000000a0 00 00 00 00 00 17 3f 53 8d b3 35 b4 84 ed bb 12 |......?S..5.....| -000000b0 cf 73 25 25 7c c3 d3 bb 1f 5a 6b 73 9a 8a b1 a2 |.s%%|....Zks....| -000000c0 ba 99 f8 0e 43 |....C| +000000a0 00 00 00 00 00 c0 7e 61 51 a1 76 15 8a 7e 20 5f |......~aQ.v..~ _| +000000b0 d4 a4 c6 3e 6c 50 18 c6 63 88 d0 ac 4c fa 31 b3 |...>lP..c...L.1.| +000000c0 e7 c9 77 11 7a |..w.z| diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndECDSAGiven b/libgo/go/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndECDSAGiven index 547f79834d9..56c3c822e35 100644 --- a/libgo/go/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndECDSAGiven +++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndECDSAGiven @@ -1,62 +1,57 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 5c 01 00 00 58 03 03 52 cc 57 59 65 |....\...X..R.WYe| -00000010 ae b3 ec a4 7a 05 f7 ec 39 22 7d 8c 91 96 6b e0 |....z...9"}...k.| -00000020 69 81 ff 88 28 17 60 ac 94 19 ff 00 00 04 00 05 |i...(.`.........| -00000030 00 ff 01 00 00 2b 00 0d 00 22 00 20 06 01 06 02 |.....+...". ....| +00000000 16 03 01 00 5a 01 00 00 56 03 03 80 13 c8 83 43 |....Z...V......C| +00000010 94 79 15 01 6e 0a 9f c5 0f e7 f6 d8 b1 94 de b4 |.y..n...........| +00000020 57 8c 4f a8 08 48 ee 9b b4 d2 43 00 00 04 00 05 |W.O..H....C.....| +00000030 00 ff 01 00 00 29 00 0d 00 20 00 1e 06 01 06 02 |.....)... ......| 00000040 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 |................| -00000050 03 02 03 03 02 01 02 02 02 03 01 01 00 0f 00 01 |................| -00000060 01 |.| +00000050 03 02 03 03 02 01 02 02 02 03 00 0f 00 01 01 |...............| >>> Flow 2 (server to client) 00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................| -00000030 05 ff 01 00 01 00 16 03 03 02 be 0b 00 02 ba 00 |................| -00000040 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......| -00000050 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..| -00000060 09 2a 86 48 86 f7 0d 01 01 05 05 00 30 45 31 0b |.*.H........0E1.| -00000070 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 |0...U....AU1.0..| -00000080 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 |.U....Some-State| -00000090 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 |1!0...U....Inter| -000000a0 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 |net Widgits Pty | -000000b0 4c 74 64 30 1e 17 0d 31 30 30 34 32 34 30 39 30 |Ltd0...100424090| -000000c0 39 33 38 5a 17 0d 31 31 30 34 32 34 30 39 30 39 |938Z..1104240909| -000000d0 33 38 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 |38Z0E1.0...U....| -000000e0 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som| -000000f0 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..| -00000100 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi| -00000110 74 73 20 50 74 79 20 4c 74 64 30 81 9f 30 0d 06 |ts Pty Ltd0..0..| -00000120 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 |.*.H............| -00000130 30 81 89 02 81 81 00 bb 79 d6 f5 17 b5 e5 bf 46 |0.......y......F| -00000140 10 d0 dc 69 be e6 2b 07 43 5a d0 03 2d 8a 7a 43 |...i..+.CZ..-.zC| -00000150 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 8c b5 b4 82 |...R..eL,x.#....| -00000160 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 fe 12 5c 7a |....;~b.,.3...\z| -00000170 56 fc f5 06 bf fa 58 7b 26 3f b5 cd 04 d3 d0 c9 |V.....X{&?......| -00000180 21 96 4a c7 f4 54 9f 5a bf ef 42 71 00 fe 18 99 |!.J..T.Z..Bq....| -00000190 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e db 51 c9 7c |..~.}}..9....Q.|| -000001a0 e3 c0 4c 3b 32 66 01 cf af b1 1d b8 71 9a 1d db |..L;2f......q...| -000001b0 db 89 6b ae da 2d 79 02 03 01 00 01 a3 81 a7 30 |..k..-y........0| -000001c0 81 a4 30 1d 06 03 55 1d 0e 04 16 04 14 b1 ad e2 |..0...U.........| -000001d0 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 88 |.Z..(.i.#i..&...| -000001e0 39 30 75 06 03 55 1d 23 04 6e 30 6c 80 14 b1 ad |90u..U.#.n0l....| -000001f0 e2 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 |..Z..(.i.#i..&..| -00000200 88 39 a1 49 a4 47 30 45 31 0b 30 09 06 03 55 04 |.9.I.G0E1.0...U.| -00000210 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a |...AU1.0...U....| -00000220 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 |Some-State1!0...| -00000230 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 |U....Internet Wi| -00000240 64 67 69 74 73 20 50 74 79 20 4c 74 64 82 09 00 |dgits Pty Ltd...| -00000250 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 55 1d 13 04 |........0...U...| -00000260 05 30 03 01 01 ff 30 0d 06 09 2a 86 48 86 f7 0d |.0....0...*.H...| -00000270 01 01 05 05 00 03 81 81 00 08 6c 45 24 c7 6b b1 |..........lE$.k.| -00000280 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a 64 75 b5 5a |Y..R.......zdu.Z| -00000290 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f 38 b3 6e 60 |.f..+...f..O8.n`| -000002a0 d3 92 fd f7 41 08 b5 25 13 b1 18 7a 24 fb 30 1d |....A..%...z$.0.| -000002b0 ba ed 98 b9 17 ec e7 d7 31 59 db 95 d3 1d 78 ea |........1Y....x.| -000002c0 50 56 5c d5 82 5a 2d 5a 5f 33 c4 b6 d8 c9 75 90 |PV\..Z-Z_3....u.| -000002d0 96 8c 0f 52 98 b5 cd 98 1f 89 20 5f f2 a0 1c a3 |...R...... _....| -000002e0 1b 96 94 dd a9 fd 57 e9 70 e8 26 6d 71 99 9b 26 |......W.p.&mq..&| -000002f0 6e 38 50 29 6c 90 a7 bd d9 16 03 03 00 0f 0d 00 |n8P)l...........| -00000300 00 0b 02 01 40 00 04 04 01 04 03 00 00 16 03 03 |....@...........| -00000310 00 04 0e 00 00 00 |......| +00000030 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.| +00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......| +00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..| +00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.| +00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google | +00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..| +00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150| +000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501| +000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..| +000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES| +000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G| +000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....| +000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........| +00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..| +00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.| +00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......| +00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....| +00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........| +00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K| +00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}| +00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....| +00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..| +00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%| +000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........| +000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...| +000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....| +000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.| +000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=| +000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.| +00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp| +00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H| +00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..| +00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....| +00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..| +00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w| +00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k| +00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..| +00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@| +00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...| +000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....| +000002b0 17 0d 00 00 13 02 01 40 00 0c 04 01 04 03 05 01 |.......@........| +000002c0 05 03 02 01 02 03 00 00 16 03 03 00 04 0e 00 00 |................| +000002d0 00 |.| >>> Flow 3 (client to server) 00000000 16 03 03 02 0a 0b 00 02 06 00 02 03 00 02 00 30 |...............0| 00000010 82 01 fc 30 82 01 5e 02 09 00 9a 30 84 6c 26 35 |...0..^....0.l&5| @@ -91,32 +86,32 @@ 000001e0 be e8 91 b3 da 1a f5 5d a3 23 f5 26 8b 45 70 8d |.......].#.&.Ep.| 000001f0 65 62 9b 7e 01 99 3d 18 f6 10 9a 38 61 9b 2e 57 |eb.~..=....8a..W| 00000200 e4 fa cc b1 8a ce e2 23 a0 87 f0 e1 67 51 eb 16 |.......#....gQ..| -00000210 03 03 00 86 10 00 00 82 00 80 47 5a 2f b8 78 46 |..........GZ/.xF| -00000220 9f 3c fc ab 8b 35 c9 77 da c3 96 78 31 7c 2b 4f |.<...5.w...x1|+O| -00000230 56 be 0f 33 bd 17 bc 1c 86 5a ae b3 0f 8b 18 2f |V..3.....Z...../| -00000240 48 0d e0 0a 20 d3 53 96 88 d2 8a 7d b6 58 13 44 |H... .S....}.X.D| -00000250 a5 e8 19 6d 02 df a6 1b 79 c5 54 c2 ef 4d 41 4f |...m....y.T..MAO| -00000260 04 1c eb 37 55 b7 2b f4 7c 6d 37 9c f1 89 a0 2c |...7U.+.|m7....,| -00000270 0f ba 10 09 e4 a1 ee 0a 7e 9a fd 2c 32 63 1c 55 |........~..,2c.U| -00000280 85 38 de d0 7b 5f 46 03 1f cc 4d 69 51 97 d8 d7 |.8..{_F...MiQ...| -00000290 88 6f ba 43 04 b0 42 09 61 5e 16 03 03 00 92 0f |.o.C..B.a^......| -000002a0 00 00 8e 04 03 00 8a 30 81 87 02 41 14 3d 4c 71 |.......0...A.=Lq| -000002b0 c2 32 4a 20 ee b7 69 17 55 e8 99 55 11 76 51 7a |.2J ..i.U..U.vQz| -000002c0 74 55 e7 e8 c3 3b b3 70 db 1c 8e f6 8a d4 99 40 |tU...;.p.......@| -000002d0 6e da 04 fd 7a 47 41 d6 ae c0 63 ad fd 91 a8 58 |n...zGA...c....X| -000002e0 24 b9 ac 2f 7a 4c bf 5b 24 12 cb 3a f3 02 42 00 |$../zL.[$..:..B.| -000002f0 90 f9 48 97 0e d4 33 99 09 9f 1d a8 97 16 60 82 |..H...3.......`.| -00000300 85 cc 5a 5d 79 f7 2f 03 2a c0 b8 12 61 ac 9f 88 |..Z]y./.*...a...| -00000310 1d 0d 9e 0a ee 28 a8 5a e2 42 b7 94 e2 e6 0e 13 |.....(.Z.B......| -00000320 c8 64 dc 4e d3 6b 10 d6 83 41 9c dc d4 53 c3 08 |.d.N.k...A...S..| -00000330 19 14 03 03 00 01 01 16 03 03 00 24 ef bd e3 23 |...........$...#| -00000340 10 23 ae 6e b5 12 eb 9c 21 78 db 36 fd bf 7f ee |.#.n....!x.6....| -00000350 6f c8 00 2d b6 35 cc 2f 38 73 ae a4 34 cf 0d df |o..-.5./8s..4...| +00000210 03 03 00 86 10 00 00 82 00 80 88 00 24 23 a5 c7 |............$#..| +00000220 03 2d 86 37 91 f1 71 a9 5f fb 97 49 88 04 9b 0e |.-.7..q._..I....| +00000230 89 da 65 d0 56 71 e7 76 22 ef 8e 11 0e 6b 50 3d |..e.Vq.v"....kP=| +00000240 64 3f f7 9b e4 45 01 d9 12 cb da fe 10 da 4e b5 |d?...E........N.| +00000250 b8 6a b5 bc 74 19 d3 4f a9 bb ee 54 37 e4 70 d0 |.j..t..O...T7.p.| +00000260 b6 e7 35 96 70 fe a5 2b 14 ac fb c6 1a fa 7d 12 |..5.p..+......}.| +00000270 87 1b 63 9d 72 30 4d 2c 1a c9 29 32 72 b6 13 53 |..c.r0M,..)2r..S| +00000280 96 05 de 78 bc f0 1a 74 e2 31 b9 ea db 62 62 6e |...x...t.1...bbn| +00000290 a0 a6 b2 c0 3e 2a 94 0d 6a f7 16 03 03 00 92 0f |....>*..j.......| +000002a0 00 00 8e 04 03 00 8a 30 81 87 02 42 01 71 5b 3b |.......0...B.q[;| +000002b0 a3 35 58 c0 b6 08 09 4f ac af 89 e0 b3 d5 3d 45 |.5X....O......=E| +000002c0 1f 49 7f 4a c9 bc 9d 0e 50 3a f5 79 bc 54 5d a9 |.I.J....P:.y.T].| +000002d0 62 ed 85 c5 f3 47 36 03 cc f1 cd 33 c3 70 2a a6 |b....G6....3.p*.| +000002e0 7c d9 6e 0c db 0d 1b 4f 6a 39 ba 77 bd ea 02 41 ||.n....Oj9.w...A| +000002f0 00 f2 b7 06 df 2f 81 7e 98 24 46 06 59 4e 86 6a |...../.~.$F.YN.j| +00000300 b7 4f b6 4b 95 40 88 f0 8f f8 bd 16 f5 d5 82 7e |.O.K.@.........~| +00000310 82 51 6f 05 49 43 59 cd 1d 40 69 67 ff 65 a8 68 |.Qo.ICY..@ig.e.h| +00000320 39 2f a1 ad a7 6a ef 5c d5 69 5e 16 50 bb 2a b2 |9/...j.\.i^.P.*.| +00000330 2f 14 03 03 00 01 01 16 03 03 00 24 55 f6 74 21 |/..........$U.t!| +00000340 b4 08 a0 7f a2 dc 86 44 e3 f8 e3 0d e1 d6 5c 1c |.......D......\.| +00000350 22 1e 41 2b 30 cc 34 0f a4 a1 7c a0 27 21 01 e0 |".A+0.4...|.'!..| >>> Flow 4 (server to client) -00000000 14 03 03 00 01 01 16 03 03 00 24 a7 50 0f 50 b4 |..........$.P.P.| -00000010 1c c3 4d f3 7a 64 df 65 ac 35 22 13 46 cc ec 36 |..M.zd.e.5".F..6| -00000020 e6 d2 f3 67 94 6a 18 85 9f 4a 3c 44 a3 58 b0 17 |...g.j...J>> Flow 1 (client to server) -00000000 16 03 01 00 5c 01 00 00 58 03 03 52 cc 57 59 6b |....\...X..R.WYk| -00000010 11 07 04 39 77 20 c2 b4 3f cb 0a c9 53 fe 5b 3e |...9w ..?...S.[>| -00000020 5f 58 2c 7e 30 69 e1 8e 6c 9d c8 00 00 04 00 05 |_X,~0i..l.......| -00000030 00 ff 01 00 00 2b 00 0d 00 22 00 20 06 01 06 02 |.....+...". ....| +00000000 16 03 01 00 5a 01 00 00 56 03 03 b0 80 f6 7c 13 |....Z...V.....|.| +00000010 30 5d 57 f0 11 3b 30 4b 0e 01 50 9a 44 0b 89 6f |0]W..;0K..P.D..o| +00000020 b6 f1 a3 34 b4 f1 b9 bf fe 66 a5 00 00 04 00 05 |...4.....f......| +00000030 00 ff 01 00 00 29 00 0d 00 20 00 1e 06 01 06 02 |.....)... ......| 00000040 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 |................| -00000050 03 02 03 03 02 01 02 02 02 03 01 01 00 0f 00 01 |................| -00000060 01 |.| +00000050 03 02 03 03 02 01 02 02 02 03 00 0f 00 01 01 |...............| >>> Flow 2 (server to client) 00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................| -00000030 05 ff 01 00 01 00 16 03 03 02 be 0b 00 02 ba 00 |................| -00000040 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......| -00000050 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..| -00000060 09 2a 86 48 86 f7 0d 01 01 05 05 00 30 45 31 0b |.*.H........0E1.| -00000070 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 |0...U....AU1.0..| -00000080 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 |.U....Some-State| -00000090 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 |1!0...U....Inter| -000000a0 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 |net Widgits Pty | -000000b0 4c 74 64 30 1e 17 0d 31 30 30 34 32 34 30 39 30 |Ltd0...100424090| -000000c0 39 33 38 5a 17 0d 31 31 30 34 32 34 30 39 30 39 |938Z..1104240909| -000000d0 33 38 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 |38Z0E1.0...U....| -000000e0 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som| -000000f0 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..| -00000100 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi| -00000110 74 73 20 50 74 79 20 4c 74 64 30 81 9f 30 0d 06 |ts Pty Ltd0..0..| -00000120 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 |.*.H............| -00000130 30 81 89 02 81 81 00 bb 79 d6 f5 17 b5 e5 bf 46 |0.......y......F| -00000140 10 d0 dc 69 be e6 2b 07 43 5a d0 03 2d 8a 7a 43 |...i..+.CZ..-.zC| -00000150 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 8c b5 b4 82 |...R..eL,x.#....| -00000160 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 fe 12 5c 7a |....;~b.,.3...\z| -00000170 56 fc f5 06 bf fa 58 7b 26 3f b5 cd 04 d3 d0 c9 |V.....X{&?......| -00000180 21 96 4a c7 f4 54 9f 5a bf ef 42 71 00 fe 18 99 |!.J..T.Z..Bq....| -00000190 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e db 51 c9 7c |..~.}}..9....Q.|| -000001a0 e3 c0 4c 3b 32 66 01 cf af b1 1d b8 71 9a 1d db |..L;2f......q...| -000001b0 db 89 6b ae da 2d 79 02 03 01 00 01 a3 81 a7 30 |..k..-y........0| -000001c0 81 a4 30 1d 06 03 55 1d 0e 04 16 04 14 b1 ad e2 |..0...U.........| -000001d0 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 88 |.Z..(.i.#i..&...| -000001e0 39 30 75 06 03 55 1d 23 04 6e 30 6c 80 14 b1 ad |90u..U.#.n0l....| -000001f0 e2 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 |..Z..(.i.#i..&..| -00000200 88 39 a1 49 a4 47 30 45 31 0b 30 09 06 03 55 04 |.9.I.G0E1.0...U.| -00000210 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a |...AU1.0...U....| -00000220 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 |Some-State1!0...| -00000230 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 |U....Internet Wi| -00000240 64 67 69 74 73 20 50 74 79 20 4c 74 64 82 09 00 |dgits Pty Ltd...| -00000250 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 55 1d 13 04 |........0...U...| -00000260 05 30 03 01 01 ff 30 0d 06 09 2a 86 48 86 f7 0d |.0....0...*.H...| -00000270 01 01 05 05 00 03 81 81 00 08 6c 45 24 c7 6b b1 |..........lE$.k.| -00000280 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a 64 75 b5 5a |Y..R.......zdu.Z| -00000290 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f 38 b3 6e 60 |.f..+...f..O8.n`| -000002a0 d3 92 fd f7 41 08 b5 25 13 b1 18 7a 24 fb 30 1d |....A..%...z$.0.| -000002b0 ba ed 98 b9 17 ec e7 d7 31 59 db 95 d3 1d 78 ea |........1Y....x.| -000002c0 50 56 5c d5 82 5a 2d 5a 5f 33 c4 b6 d8 c9 75 90 |PV\..Z-Z_3....u.| -000002d0 96 8c 0f 52 98 b5 cd 98 1f 89 20 5f f2 a0 1c a3 |...R...... _....| -000002e0 1b 96 94 dd a9 fd 57 e9 70 e8 26 6d 71 99 9b 26 |......W.p.&mq..&| -000002f0 6e 38 50 29 6c 90 a7 bd d9 16 03 03 00 0f 0d 00 |n8P)l...........| -00000300 00 0b 02 01 40 00 04 04 01 04 03 00 00 16 03 03 |....@...........| -00000310 00 04 0e 00 00 00 |......| +00000030 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.| +00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......| +00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..| +00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.| +00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google | +00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..| +00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150| +000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501| +000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..| +000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES| +000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G| +000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....| +000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........| +00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..| +00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.| +00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......| +00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....| +00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........| +00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K| +00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}| +00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....| +00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..| +00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%| +000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........| +000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...| +000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....| +000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.| +000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=| +000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.| +00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp| +00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H| +00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..| +00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....| +00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..| +00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w| +00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k| +00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..| +00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@| +00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...| +000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....| +000002b0 17 0d 00 00 13 02 01 40 00 0c 04 01 04 03 05 01 |.......@........| +000002c0 05 03 02 01 02 03 00 00 16 03 03 00 04 0e 00 00 |................| +000002d0 00 |.| >>> Flow 3 (client to server) 00000000 16 03 03 01 fb 0b 00 01 f7 00 01 f4 00 01 f1 30 |...............0| 00000010 82 01 ed 30 82 01 58 a0 03 02 01 02 02 01 00 30 |...0..X........0| @@ -90,32 +85,32 @@ 000001d0 8b ec ab 67 be c8 64 b0 11 50 46 58 17 6b 99 1c |...g..d..PFX.k..| 000001e0 d3 1d fc 06 f1 0e e5 96 a8 0c f9 78 20 b7 44 18 |...........x .D.| 000001f0 51 8d 10 7e 4f 94 67 df a3 4e 70 73 8e 90 91 85 |Q..~O.g..Nps....| -00000200 16 03 03 00 86 10 00 00 82 00 80 44 89 7d aa 26 |...........D.}.&| -00000210 30 ce 6b db 25 70 b0 1e 16 fa 5b 3a dd 4a 4b bd |0.k.%p....[:.JK.| -00000220 ec ee 50 9d 21 ba 52 b5 51 4f a8 65 d8 2e 41 e2 |..P.!.R.QO.e..A.| -00000230 e1 dc f3 1a df 58 4f 87 7a d3 e1 e1 1c 13 b2 0b |.....XO.z.......| -00000240 b7 43 b7 92 f2 df 19 bb 79 71 e0 71 44 ab 19 2f |.C......yq.qD../| -00000250 37 11 ac 62 50 b6 f1 53 fe aa b4 bc 29 8e 0b 4c |7..bP..S....)..L| -00000260 0b 12 8d d5 84 a9 fa a9 ea 16 aa c3 0d da 32 c8 |..............2.| -00000270 e0 4c 9f 99 f8 69 cd a8 c3 b1 76 42 67 f3 ff 15 |.L...i....vBg...| -00000280 52 95 43 66 da 49 43 25 9d e5 eb 16 03 03 00 88 |R.Cf.IC%........| -00000290 0f 00 00 84 04 01 00 80 01 d5 0e 1c 75 97 89 52 |............u..R| -000002a0 1a f0 cc ef 93 6e 71 b2 b1 38 8c 50 11 f7 a3 02 |.....nq..8.P....| -000002b0 71 c4 d5 6f 8d 01 83 06 2e ea 5a 10 8a 0d d0 fc |q..o......Z.....| -000002c0 b6 a2 63 af 4f 99 b5 eb ab fd 01 c2 fb 26 fc fd |..c.O........&..| -000002d0 ad 2c b3 63 b3 87 a6 f5 14 ea 7d e7 fe a8 e7 7e |.,.c......}....~| -000002e0 20 ab b9 f6 c3 58 bd c0 f3 96 eb 83 dc 42 6c 0d | ....X.......Bl.| -000002f0 5e e8 09 55 c7 b8 24 05 dd e1 7c af 9f 2c 22 6c |^..U..$...|..,"l| -00000300 fa b8 94 13 3b f1 09 e1 38 59 fc a1 8c cb aa ca |....;...8Y......| -00000310 f8 e0 2a 9c 36 f9 c3 2b 14 03 03 00 01 01 16 03 |..*.6..+........| -00000320 03 00 24 d0 12 7c cc d2 3e 37 1f f4 7d b4 c0 fc |..$..|..>7..}...| -00000330 19 f6 c8 ea 62 12 e0 0d af 62 d4 69 f7 96 5a c0 |....b....b.i..Z.| -00000340 97 d3 bb b0 a3 f7 3f |......?| +00000200 16 03 03 00 86 10 00 00 82 00 80 98 61 16 34 c4 |............a.4.| +00000210 c6 0a 47 c1 de 87 b1 b7 70 1b 24 8d 7e 35 90 35 |..G.....p.$.~5.5| +00000220 f7 a5 6f c7 c9 91 ad 46 4c 50 e5 7e 61 7c 49 66 |..o....FLP.~a|If| +00000230 e9 fe 1e 2c 30 fa 22 03 36 8f 44 27 a7 d2 14 84 |...,0.".6.D'....| +00000240 d0 1f 21 ca 40 35 d1 7d 31 3f e1 73 de 69 bc da |..!.@5.}1?.s.i..| +00000250 a5 96 8a b5 50 2b 4b 87 5a b3 fb e1 11 0a 29 59 |....P+K.Z.....)Y| +00000260 13 2e e3 c2 05 d3 23 e8 09 0c 42 f6 8e 26 67 89 |......#...B..&g.| +00000270 24 0f 08 2f 3d 24 2b 0c a2 98 38 02 5c 95 9f ce |$../=$+...8.\...| +00000280 e3 75 ba 05 b5 f8 f0 07 e9 a1 44 16 03 03 00 88 |.u........D.....| +00000290 0f 00 00 84 04 01 00 80 04 c0 bc 4b 23 59 ed 26 |...........K#Y.&| +000002a0 8d 90 35 da 5b 55 88 e7 12 10 7b d7 1c 27 d1 c4 |..5.[U....{..'..| +000002b0 d8 1b e2 e7 54 ad a4 be 00 6b 5b 61 2d ec 97 0c |....T....k[a-...| +000002c0 a5 9b ae ab 13 fa 94 53 1c 65 28 21 7d b5 c5 be |.......S.e(!}...| +000002d0 22 62 91 78 fc e3 de 84 5c 4e 0d f5 73 5e 20 49 |"b.x....\N..s^ I| +000002e0 5a e2 f9 d3 2f 36 23 91 31 5b ee c7 0b 6f b3 35 |Z.../6#.1[...o.5| +000002f0 2f 8a 51 84 3c fe 78 34 1f 8c 68 d3 fc 4f c6 5e |/.Q.<.x4..h..O.^| +00000300 7b fe b2 81 79 91 37 ee 7f f1 9b a4 88 5f 1b 44 |{...y.7......_.D| +00000310 dc e9 36 bb d1 45 bb 1f 14 03 03 00 01 01 16 03 |..6..E..........| +00000320 03 00 24 12 e7 8a 31 36 26 9f fe 45 95 cf 41 56 |..$...16&..E..AV| +00000330 b4 69 ef e4 22 14 5a 4d c8 79 a7 18 7b 68 a8 02 |.i..".ZM.y..{h..| +00000340 75 ea 42 fe c4 a1 32 |u.B...2| >>> Flow 4 (server to client) -00000000 14 03 03 00 01 01 16 03 03 00 24 cd 20 85 1e 74 |..........$. ..t| -00000010 18 b2 71 48 d5 10 61 c6 b0 18 26 83 c2 7f f1 b1 |..qH..a...&.....| -00000020 2f b5 35 d0 47 a8 99 9a 9a a5 62 64 fb f9 29 17 |/.5.G.....bd..).| -00000030 03 03 00 21 22 7b ed 61 e3 9b 6d 98 b9 23 98 e3 |...!"{.a..m..#..| -00000040 55 11 b8 0f 7e 2b e1 c1 d4 f1 83 79 c3 f8 03 f0 |U...~+.....y....| -00000050 02 5c 61 24 d7 15 03 03 00 16 14 2b a3 5a 56 f0 |.\a$.......+.ZV.| -00000060 92 da d0 e6 32 91 d8 30 7a b4 d0 a2 93 f5 01 ea |....2..0z.......| +00000000 14 03 03 00 01 01 16 03 03 00 24 ae 6d 7b ac b6 |..........$.m{..| +00000010 62 5c 40 65 6b 0e 5c 12 68 61 14 90 54 3e 24 78 |b\@ek.\.ha..T>$x| +00000020 be 85 17 a0 9b de a0 00 e9 80 1b a9 0f e4 d7 17 |................| +00000030 03 03 00 21 86 06 17 6b 62 02 a7 a0 71 fe c0 e4 |...!...kb...q...| +00000040 44 00 54 dd cc a9 70 cf bc 92 0d 40 07 62 f5 39 |D.T...p....@.b.9| +00000050 2a 30 ab 7f cd 15 03 03 00 16 6f 8d c9 d4 62 02 |*0........o...b.| +00000060 da 64 4c 89 32 86 9f 29 24 05 ed cc 77 9d e5 55 |.dL.2..)$...w..U| diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedNotGiven b/libgo/go/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedNotGiven index 562fe1aaa0a..5de6dd82ec0 100644 --- a/libgo/go/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedNotGiven +++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedNotGiven @@ -1,81 +1,76 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 5c 01 00 00 58 03 03 52 cc 57 59 1b |....\...X..R.WY.| -00000010 08 fe f7 8a bf 07 84 2b 60 a6 13 2d 15 13 f8 b6 |.......+`..-....| -00000020 d4 b6 3b f2 7a 98 ff 32 a0 68 7c 00 00 04 00 05 |..;.z..2.h|.....| -00000030 00 ff 01 00 00 2b 00 0d 00 22 00 20 06 01 06 02 |.....+...". ....| +00000000 16 03 01 00 5a 01 00 00 56 03 03 52 b6 c5 b4 e3 |....Z...V..R....| +00000010 35 ce 4e b2 9c e0 38 09 e7 fe 00 a2 1a 0a 43 eb |5.N...8.......C.| +00000020 df 98 6a 34 71 f9 d0 f8 5d e7 5e 00 00 04 00 05 |..j4q...].^.....| +00000030 00 ff 01 00 00 29 00 0d 00 20 00 1e 06 01 06 02 |.....)... ......| 00000040 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 |................| -00000050 03 02 03 03 02 01 02 02 02 03 01 01 00 0f 00 01 |................| -00000060 01 |.| +00000050 03 02 03 03 02 01 02 02 02 03 00 0f 00 01 01 |...............| >>> Flow 2 (server to client) 00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................| -00000030 05 ff 01 00 01 00 16 03 03 02 be 0b 00 02 ba 00 |................| -00000040 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......| -00000050 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..| -00000060 09 2a 86 48 86 f7 0d 01 01 05 05 00 30 45 31 0b |.*.H........0E1.| -00000070 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 |0...U....AU1.0..| -00000080 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 |.U....Some-State| -00000090 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 |1!0...U....Inter| -000000a0 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 |net Widgits Pty | -000000b0 4c 74 64 30 1e 17 0d 31 30 30 34 32 34 30 39 30 |Ltd0...100424090| -000000c0 39 33 38 5a 17 0d 31 31 30 34 32 34 30 39 30 39 |938Z..1104240909| -000000d0 33 38 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 |38Z0E1.0...U....| -000000e0 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som| -000000f0 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..| -00000100 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi| -00000110 74 73 20 50 74 79 20 4c 74 64 30 81 9f 30 0d 06 |ts Pty Ltd0..0..| -00000120 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 |.*.H............| -00000130 30 81 89 02 81 81 00 bb 79 d6 f5 17 b5 e5 bf 46 |0.......y......F| -00000140 10 d0 dc 69 be e6 2b 07 43 5a d0 03 2d 8a 7a 43 |...i..+.CZ..-.zC| -00000150 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 8c b5 b4 82 |...R..eL,x.#....| -00000160 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 fe 12 5c 7a |....;~b.,.3...\z| -00000170 56 fc f5 06 bf fa 58 7b 26 3f b5 cd 04 d3 d0 c9 |V.....X{&?......| -00000180 21 96 4a c7 f4 54 9f 5a bf ef 42 71 00 fe 18 99 |!.J..T.Z..Bq....| -00000190 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e db 51 c9 7c |..~.}}..9....Q.|| -000001a0 e3 c0 4c 3b 32 66 01 cf af b1 1d b8 71 9a 1d db |..L;2f......q...| -000001b0 db 89 6b ae da 2d 79 02 03 01 00 01 a3 81 a7 30 |..k..-y........0| -000001c0 81 a4 30 1d 06 03 55 1d 0e 04 16 04 14 b1 ad e2 |..0...U.........| -000001d0 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 88 |.Z..(.i.#i..&...| -000001e0 39 30 75 06 03 55 1d 23 04 6e 30 6c 80 14 b1 ad |90u..U.#.n0l....| -000001f0 e2 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 |..Z..(.i.#i..&..| -00000200 88 39 a1 49 a4 47 30 45 31 0b 30 09 06 03 55 04 |.9.I.G0E1.0...U.| -00000210 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a |...AU1.0...U....| -00000220 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 |Some-State1!0...| -00000230 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 |U....Internet Wi| -00000240 64 67 69 74 73 20 50 74 79 20 4c 74 64 82 09 00 |dgits Pty Ltd...| -00000250 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 55 1d 13 04 |........0...U...| -00000260 05 30 03 01 01 ff 30 0d 06 09 2a 86 48 86 f7 0d |.0....0...*.H...| -00000270 01 01 05 05 00 03 81 81 00 08 6c 45 24 c7 6b b1 |..........lE$.k.| -00000280 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a 64 75 b5 5a |Y..R.......zdu.Z| -00000290 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f 38 b3 6e 60 |.f..+...f..O8.n`| -000002a0 d3 92 fd f7 41 08 b5 25 13 b1 18 7a 24 fb 30 1d |....A..%...z$.0.| -000002b0 ba ed 98 b9 17 ec e7 d7 31 59 db 95 d3 1d 78 ea |........1Y....x.| -000002c0 50 56 5c d5 82 5a 2d 5a 5f 33 c4 b6 d8 c9 75 90 |PV\..Z-Z_3....u.| -000002d0 96 8c 0f 52 98 b5 cd 98 1f 89 20 5f f2 a0 1c a3 |...R...... _....| -000002e0 1b 96 94 dd a9 fd 57 e9 70 e8 26 6d 71 99 9b 26 |......W.p.&mq..&| -000002f0 6e 38 50 29 6c 90 a7 bd d9 16 03 03 00 0f 0d 00 |n8P)l...........| -00000300 00 0b 02 01 40 00 04 04 01 04 03 00 00 16 03 03 |....@...........| -00000310 00 04 0e 00 00 00 |......| +00000030 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.| +00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......| +00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..| +00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.| +00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google | +00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..| +00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150| +000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501| +000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..| +000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES| +000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G| +000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....| +000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........| +00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..| +00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.| +00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......| +00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....| +00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........| +00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K| +00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}| +00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....| +00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..| +00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%| +000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........| +000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...| +000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....| +000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.| +000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=| +000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.| +00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp| +00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H| +00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..| +00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....| +00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..| +00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w| +00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k| +00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..| +00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@| +00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...| +000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....| +000002b0 17 0d 00 00 13 02 01 40 00 0c 04 01 04 03 05 01 |.......@........| +000002c0 05 03 02 01 02 03 00 00 16 03 03 00 04 0e 00 00 |................| +000002d0 00 |.| >>> Flow 3 (client to server) 00000000 16 03 03 00 07 0b 00 00 03 00 00 00 16 03 03 00 |................| -00000010 86 10 00 00 82 00 80 6b 51 48 d3 18 7d 30 e0 0c |.......kQH..}0..| -00000020 20 8d f3 e4 39 47 30 0e a5 85 79 f9 8b 11 50 9e | ...9G0...y...P.| -00000030 81 71 5c 26 c6 bb cb aa d5 00 d1 89 79 b1 77 2d |.q\&........y.w-| -00000040 eb 9b 86 7c 52 c6 f7 b7 10 b0 b6 94 22 51 b8 12 |...|R......."Q..| -00000050 3c 09 35 8e 1b cc f4 3b b7 b8 78 ab 89 59 41 49 |<.5....;..x..YAI| -00000060 21 31 eb f0 f8 94 63 3d e6 96 8f b6 63 95 05 dd |!1....c=....c...| -00000070 46 b3 00 8a d6 83 75 99 1b 5a 48 0a 23 b5 10 c1 |F.....u..ZH.#...| -00000080 95 b5 bc 15 72 b5 f5 a0 62 e2 1d c0 ff d2 87 a5 |....r...b.......| -00000090 97 5c 33 49 a7 26 35 14 03 03 00 01 01 16 03 03 |.\3I.&5.........| -000000a0 00 24 61 38 1f 9d fb d9 65 2e 02 07 fb be f9 85 |.$a8....e.......| -000000b0 8d 15 34 c0 d1 0e 4e 10 3c 25 60 2f ac 04 21 66 |..4...N.<%`/..!f| -000000c0 04 9d 9a 60 31 72 |...`1r| +00000010 86 10 00 00 82 00 80 2e 8e cb 6c f5 db 45 5b f0 |..........l..E[.| +00000020 67 7d b1 ac 87 c2 d6 e9 ea 37 40 15 2a ea a1 af |g}.......7@.*...| +00000030 ed 71 68 18 9c 6c 84 20 52 3e 38 94 8e d9 cd b3 |.qh..l. R>8.....| +00000040 15 73 8b db d7 ff 1d 8a ed a6 f4 00 7d d0 0a 1e |.s..........}...| +00000050 9a 1b 5c 59 f6 a0 29 62 03 a1 c6 bf 8a 57 14 06 |..\Y..)b.....W..| +00000060 9a e8 03 72 bc cd cd 6f 6d e2 ce a8 41 7a f0 65 |...r...om...Az.e| +00000070 42 0c 7b dd 93 d7 ab 37 f8 2a b3 c4 72 95 61 e1 |B.{....7.*..r.a.| +00000080 75 98 f5 99 69 ef 0a d0 00 41 0f 05 87 13 d3 7d |u...i....A.....}| +00000090 ba 74 34 43 9a 6c d0 14 03 03 00 01 01 16 03 03 |.t4C.l..........| +000000a0 00 24 87 7e 7d 48 ca 17 9c ad 30 b8 6a 05 2f d3 |.$.~}H....0.j./.| +000000b0 fc 18 2e df fd f5 0e 38 c3 06 57 4c 27 66 02 af |.......8..WL'f..| +000000c0 6d 78 4d 2e b6 dc |mxM...| >>> Flow 4 (server to client) -00000000 14 03 03 00 01 01 16 03 03 00 24 fe 0e 3e 84 af |..........$..>..| -00000010 e5 6b 10 ed 41 9c 2b e0 ba e0 2b 53 61 36 1b 40 |.k..A.+...+Sa6.@| -00000020 35 de 3a c7 c3 5c df 74 67 f7 05 74 84 f5 e1 17 |5.:..\.tg..t....| -00000030 03 03 00 21 d3 8d 81 85 b7 1f 30 bd 89 33 f9 81 |...!......0..3..| -00000040 89 f7 af d1 be b0 c1 46 e3 df 32 f6 dc 2f 4d 82 |.......F..2../M.| -00000050 0a 84 9f 5b 03 15 03 03 00 16 13 af 37 91 82 67 |...[........7..g| -00000060 b0 7c 5e 0e ec 8e cc 31 a0 ea a5 72 a4 2b 0b 73 |.|^....1...r.+.s| +00000000 14 03 03 00 01 01 16 03 03 00 24 cf ee f6 28 ea |..........$...(.| +00000010 df e2 7e 9a 75 e0 f9 b4 c4 c2 57 3a 54 26 db 7f |..~.u.....W:T&..| +00000020 c4 19 6d b6 d6 c7 b1 05 7f 92 21 9e 51 1a 0a 17 |..m.......!.Q...| +00000030 03 03 00 21 87 48 77 c4 eb 7c 5d 13 3b f4 8d 08 |...!.Hw..|].;...| +00000040 f9 35 c3 d2 e5 c0 8c ea 15 c9 2d c5 e0 70 fd 7c |.5........-..p.|| +00000050 de 93 4f 8c 8d 15 03 03 00 16 d4 8a d5 6a fc db |..O..........j..| +00000060 c7 1d 1f 76 64 b9 31 68 72 cc 58 de 9f 2a a6 45 |...vd.1hr.X..*.E| diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES b/libgo/go/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES index aacbb86705a..3b7238ad299 100644 --- a/libgo/go/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES +++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES @@ -1,15 +1,15 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 9c 01 00 00 98 03 03 53 04 f0 f9 09 |...........S....| -00000010 13 56 01 37 84 b1 32 59 4c 73 b1 8e bb 02 1a 32 |.V.7..2YLs.....2| -00000020 db ab 8c e6 ed ad 7f 52 9a 59 39 00 00 04 c0 0a |.......R.Y9.....| -00000030 00 ff 01 00 00 6b 00 0b 00 04 03 00 01 02 00 0a |.....k..........| -00000040 00 34 00 32 00 0e 00 0d 00 19 00 0b 00 0c 00 18 |.4.2............| -00000050 00 09 00 0a 00 16 00 17 00 08 00 06 00 07 00 14 |................| -00000060 00 15 00 04 00 05 00 12 00 13 00 01 00 02 00 03 |................| -00000070 00 0f 00 10 00 11 00 0d 00 22 00 20 06 01 06 02 |.........". ....| -00000080 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 |................| -00000090 03 02 03 03 02 01 02 02 02 03 01 01 00 0f 00 01 |................| -000000a0 01 |.| +00000000 16 03 01 00 a1 01 00 00 9d 03 03 0f b7 07 5f c7 |.............._.| +00000010 18 b8 39 6d 92 b3 90 ed bf 5c 48 7c 6a 56 ee e9 |..9m.....\H|jV..| +00000020 7a 5b 5f 71 a4 f0 7f 47 57 73 78 00 00 04 c0 0a |z[_q...GWsx.....| +00000030 00 ff 02 01 00 00 6f 00 0b 00 04 03 00 01 02 00 |......o.........| +00000040 0a 00 3a 00 38 00 0e 00 0d 00 19 00 1c 00 0b 00 |..:.8...........| +00000050 0c 00 1b 00 18 00 09 00 0a 00 1a 00 16 00 17 00 |................| +00000060 08 00 06 00 07 00 14 00 15 00 04 00 05 00 12 00 |................| +00000070 13 00 01 00 02 00 03 00 0f 00 10 00 11 00 0d 00 |................| +00000080 20 00 1e 06 01 06 02 06 03 05 01 05 02 05 03 04 | ...............| +00000090 01 04 02 04 03 03 01 03 02 03 03 02 01 02 02 02 |................| +000000a0 03 00 0f 00 01 01 |......| >>> Flow 2 (server to client) 00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| @@ -52,38 +52,38 @@ 00000260 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd a7 24 20 3e |uq..T[....g..$ >| 00000270 b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e f1 07 9f 6c |.V...(^.+-O....l| 00000280 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 a6 b5 68 1a |K[.V.2B.X..I..h.| -00000290 41 03 56 6b dc 5a 89 04 03 00 8b 30 81 88 02 42 |A.Vk.Z.....0...B| -000002a0 00 c6 85 8e 06 b7 04 04 e9 cd 9e 3e cb 66 23 95 |...........>.f#.| -000002b0 b4 42 9c 64 81 39 05 3f b5 21 f8 28 af 60 6b 4d |.B.d.9.?.!.(.`kM| -000002c0 3d ba a1 4b 5e 77 ef e7 59 28 fe 1d c1 27 a2 ff |=..K^w..Y(...'..| -000002d0 a8 de 33 48 b3 c1 85 6a 42 9b f9 7e 7e 31 c2 e5 |..3H...jB..~~1..| -000002e0 bd 66 02 42 00 ad 7d 06 35 ab ec 8d ac d4 ba 1b |.f.B..}.5.......| -000002f0 49 5e 05 5f f0 97 93 82 b8 2b 8d 91 98 63 8e b4 |I^._.....+...c..| -00000300 14 62 db 1e c9 2c 13 ae b7 d3 17 38 23 2f f6 7f |.b...,.....8#/..| -00000310 0c 4d d3 33 d2 79 d1 77 ee cb b1 c2 fc 34 b8 69 |.M.3.y.w.....4.i| -00000320 f9 10 8b 61 89 85 16 03 03 00 04 0e 00 00 00 |...a...........| +00000290 41 03 56 6b dc 5a 89 05 03 00 8b 30 81 88 02 42 |A.Vk.Z.....0...B| +000002a0 00 d3 cf 21 cd 3c 2e 11 f5 f8 1d c8 c1 57 4b f8 |...!.<.......WK.| +000002b0 1a c0 2b 1d 47 0f 2d a5 ac a1 c8 83 5d 76 87 05 |..+.G.-.....]v..| +000002c0 2b 0d 36 d5 57 9f b9 8a a0 a2 94 67 6a cd 29 db |+.6.W......gj.).| +000002d0 04 b0 6b 06 d9 f7 17 9f 1c 60 92 e7 4e 50 48 7f |..k......`..NPH.| +000002e0 dc d0 02 42 01 56 fd 38 bd 05 a5 16 6d 91 d1 ce |...B.V.8....m...| +000002f0 bb 8c 45 b2 76 2f 92 9c 8b 94 57 7d de 53 8b 7b |..E.v/....W}.S.{| +00000300 80 26 6c 4a 43 4b a6 c9 46 49 08 ab c7 57 f3 d9 |.&lJCK..FI...W..| +00000310 fa 1d 55 fe 91 de 8a 0d 8b d1 44 96 87 85 cb 02 |..U.......D.....| +00000320 76 9c 00 ad 5f b8 16 03 03 00 04 0e 00 00 00 |v..._..........| >>> Flow 3 (client to server) -00000000 16 03 03 00 46 10 00 00 42 41 04 dd 22 68 a1 4e |....F...BA.."h.N| -00000010 04 1b 47 f9 c5 7d 04 1d d8 fe 84 fa be 31 2e a7 |..G..}.......1..| -00000020 f8 e5 b8 14 92 44 99 11 0e 34 97 fc e5 b1 91 cf |.....D...4......| -00000030 a4 d1 3f b4 71 94 c6 06 16 f0 98 c0 3e 05 f9 2f |..?.q.......>../| -00000040 0a 97 78 3d ef dc fa a2 d7 ee 7d 14 03 03 00 01 |..x=......}.....| -00000050 01 16 03 03 00 40 90 bf 7f e9 c9 6e d1 80 f5 12 |.....@.....n....| -00000060 6d c5 b7 c5 15 4b 18 a5 d3 18 1e f8 8c 4d 7e 6d |m....K.......M~m| -00000070 03 60 29 7c 45 7c b2 ca 8c 07 71 70 aa 23 fa 6e |.`)|E|....qp.#.n| -00000080 d9 0b 0a 32 4c 9e e5 00 f9 19 9b b6 8d dc d3 67 |...2L..........g| -00000090 3d 0f bb b8 4b 9e |=...K.| +00000000 16 03 03 00 46 10 00 00 42 41 04 0b dc ea 22 05 |....F...BA....".| +00000010 44 c2 09 47 65 31 3b 0b e1 05 1a 87 8c 2d 3b 56 |D..Ge1;......-;V| +00000020 49 34 27 3e d6 3b 93 e2 12 7f 5d 7b dc 85 c8 96 |I4'>.;....]{....| +00000030 4c 8c f9 18 6f 15 cf db 6e 2c 14 6a c9 dd 1c 70 |L...o...n,.j...p| +00000040 7e 05 c4 17 71 76 df 10 ee 8c b1 14 03 03 00 01 |~...qv..........| +00000050 01 16 03 03 00 40 ff 12 88 36 3c 00 17 d1 b9 41 |.....@...6<....A| +00000060 7a 12 25 94 4c 90 65 62 d8 09 ab f9 b4 ee c3 de |z.%.L.eb........| +00000070 46 2f cb ee 18 76 4f 76 8e dd 89 fc 7a 21 3b 5f |F/...vOv....z!;_| +00000080 ff ac 1c 03 aa be 96 82 82 ea 2e 22 2a 80 b3 86 |..........."*...| +00000090 38 e4 4d 90 91 46 |8.M..F| >>> Flow 4 (server to client) 00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |..........@.....| -00000010 00 00 00 00 00 00 00 00 00 00 00 a1 6e e5 d1 ca |............n...| -00000020 03 f4 77 dc ec ee 5d f0 22 5e 7f 55 1a 8d ad 45 |..w...]."^.U...E| -00000030 09 f1 3b b2 61 36 dc 3d 2a 1e 1f e5 a7 84 76 a9 |..;.a6.=*.....v.| -00000040 41 5b 86 03 ac 22 18 20 9b a9 29 17 03 03 00 40 |A[...". ..)....@| +00000010 00 00 00 00 00 00 00 00 00 00 00 e5 c1 f0 6a db |..............j.| +00000020 05 98 ed 33 94 73 7f 13 7f 78 17 7f d1 9e c5 a7 |...3.s...x......| +00000030 62 7f 85 14 2c 7d b2 8e ef 75 a9 df 92 cc 22 20 |b...,}...u...." | +00000040 66 08 85 22 d3 ea 5c 4c 4c c8 d7 17 03 03 00 40 |f.."..\LL......@| 00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| -00000060 f5 cb 28 1e b5 bc 82 7f 82 38 54 14 e8 b9 6d 3b |..(......8T...m;| -00000070 bc 99 d6 0e f9 00 96 99 a8 92 2e 86 9d 62 4e 90 |.............bN.| -00000080 27 52 58 45 20 93 90 a1 f3 a8 89 2b e7 21 24 16 |'RXE ......+.!$.| +00000060 f2 20 07 d2 13 ca ed 01 c9 7b 91 14 01 2c 08 f5 |. .......{...,..| +00000070 8a 69 94 bc 19 9a d9 65 6b 15 04 b4 45 17 ec 6f |.i.....ek...E..o| +00000080 85 de 31 dc a2 de 8b 4d 53 57 66 4a 29 21 5a 20 |..1....MSWfJ)!Z | 00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........| -000000a0 00 00 00 00 00 a8 2a ab 8f b0 ce 49 8b fd a5 c9 |......*....I....| -000000b0 11 b2 04 83 18 f3 1d 6c 82 34 1d df dd 2f 45 3b |.......l.4.../E;| -000000c0 27 8a 0f 16 69 |'...i| +000000a0 00 00 00 00 00 55 15 f7 89 8d 75 57 7e 92 db ec |.....U....uW~...| +000000b0 32 ec 07 5c 83 32 36 59 61 f1 9d a6 7a eb 76 c1 |2..\.26Ya...z.v.| +000000c0 c7 96 3f 4d 0a |..?M.| diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-IssueTicket b/libgo/go/crypto/tls/testdata/Server-TLSv12-IssueTicket index e3e62f22423..20a0731091a 100644 --- a/libgo/go/crypto/tls/testdata/Server-TLSv12-IssueTicket +++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-IssueTicket @@ -1,87 +1,83 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 60 01 00 00 5c 03 03 52 cc 57 59 7e |....`...\..R.WY~| -00000010 43 5c 3b fd 50 ab 61 3f 64 a4 f9 bd ba 8c 28 e1 |C\;.P.a?d.....(.| -00000020 f9 a1 45 7e 48 9e 62 af 25 de 0e 00 00 04 00 05 |..E~H.b.%.......| -00000030 00 ff 01 00 00 2f 00 23 00 00 00 0d 00 22 00 20 |...../.#.....". | +00000000 16 03 01 00 5e 01 00 00 5a 03 03 f0 0a 06 d0 65 |....^...Z......e| +00000010 1c c3 90 ac dc 61 42 e5 b8 a9 17 fb e7 c3 1e bd |.....aB.........| +00000020 d9 09 5a 63 71 e2 f9 58 db 26 6e 00 00 04 00 05 |..Zcq..X.&n.....| +00000030 00 ff 01 00 00 2d 00 23 00 00 00 0d 00 20 00 1e |.....-.#..... ..| 00000040 06 01 06 02 06 03 05 01 05 02 05 03 04 01 04 02 |................| -00000050 04 03 03 01 03 02 03 03 02 01 02 02 02 03 01 01 |................| -00000060 00 0f 00 01 01 |.....| +00000050 04 03 03 01 03 02 03 03 02 01 02 02 02 03 00 0f |................| +00000060 00 01 01 |...| >>> Flow 2 (server to client) 00000000 16 03 03 00 35 02 00 00 31 03 03 00 00 00 00 00 |....5...1.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................| -00000030 09 00 23 00 00 ff 01 00 01 00 16 03 03 02 be 0b |..#.............| -00000040 00 02 ba 00 02 b7 00 02 b4 30 82 02 b0 30 82 02 |.........0...0..| -00000050 19 a0 03 02 01 02 02 09 00 85 b0 bb a4 8a 7f b8 |................| -00000060 ca 30 0d 06 09 2a 86 48 86 f7 0d 01 01 05 05 00 |.0...*.H........| -00000070 30 45 31 0b 30 09 06 03 55 04 06 13 02 41 55 31 |0E1.0...U....AU1| -00000080 13 30 11 06 03 55 04 08 13 0a 53 6f 6d 65 2d 53 |.0...U....Some-S| -00000090 74 61 74 65 31 21 30 1f 06 03 55 04 0a 13 18 49 |tate1!0...U....I| -000000a0 6e 74 65 72 6e 65 74 20 57 69 64 67 69 74 73 20 |nternet Widgits | -000000b0 50 74 79 20 4c 74 64 30 1e 17 0d 31 30 30 34 32 |Pty Ltd0...10042| -000000c0 34 30 39 30 39 33 38 5a 17 0d 31 31 30 34 32 34 |4090938Z..110424| -000000d0 30 39 30 39 33 38 5a 30 45 31 0b 30 09 06 03 55 |090938Z0E1.0...U| -000000e0 04 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 |....AU1.0...U...| -000000f0 0a 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 |.Some-State1!0..| -00000100 03 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 |.U....Internet W| -00000110 69 64 67 69 74 73 20 50 74 79 20 4c 74 64 30 81 |idgits Pty Ltd0.| -00000120 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 00 |.0...*.H........| -00000130 03 81 8d 00 30 81 89 02 81 81 00 bb 79 d6 f5 17 |....0.......y...| -00000140 b5 e5 bf 46 10 d0 dc 69 be e6 2b 07 43 5a d0 03 |...F...i..+.CZ..| -00000150 2d 8a 7a 43 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 |-.zC...R..eL,x.#| -00000160 8c b5 b4 82 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 |........;~b.,.3.| -00000170 fe 12 5c 7a 56 fc f5 06 bf fa 58 7b 26 3f b5 cd |..\zV.....X{&?..| -00000180 04 d3 d0 c9 21 96 4a c7 f4 54 9f 5a bf ef 42 71 |....!.J..T.Z..Bq| -00000190 00 fe 18 99 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e |......~.}}..9...| -000001a0 db 51 c9 7c e3 c0 4c 3b 32 66 01 cf af b1 1d b8 |.Q.|..L;2f......| -000001b0 71 9a 1d db db 89 6b ae da 2d 79 02 03 01 00 01 |q.....k..-y.....| -000001c0 a3 81 a7 30 81 a4 30 1d 06 03 55 1d 0e 04 16 04 |...0..0...U.....| -000001d0 14 b1 ad e2 85 5a cf cb 28 db 69 ce 23 69 de d3 |.....Z..(.i.#i..| -000001e0 26 8e 18 88 39 30 75 06 03 55 1d 23 04 6e 30 6c |&...90u..U.#.n0l| -000001f0 80 14 b1 ad e2 85 5a cf cb 28 db 69 ce 23 69 de |......Z..(.i.#i.| -00000200 d3 26 8e 18 88 39 a1 49 a4 47 30 45 31 0b 30 09 |.&...9.I.G0E1.0.| -00000210 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 55 |..U....AU1.0...U| -00000220 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 21 |....Some-State1!| -00000230 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e 65 |0...U....Interne| -00000240 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c 74 |t Widgits Pty Lt| -00000250 64 82 09 00 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 |d...........0...| -00000260 55 1d 13 04 05 30 03 01 01 ff 30 0d 06 09 2a 86 |U....0....0...*.| -00000270 48 86 f7 0d 01 01 05 05 00 03 81 81 00 08 6c 45 |H.............lE| -00000280 24 c7 6b b1 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a |$.k.Y..R.......z| -00000290 64 75 b5 5a 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f |du.Z.f..+...f..O| -000002a0 38 b3 6e 60 d3 92 fd f7 41 08 b5 25 13 b1 18 7a |8.n`....A..%...z| -000002b0 24 fb 30 1d ba ed 98 b9 17 ec e7 d7 31 59 db 95 |$.0.........1Y..| -000002c0 d3 1d 78 ea 50 56 5c d5 82 5a 2d 5a 5f 33 c4 b6 |..x.PV\..Z-Z_3..| -000002d0 d8 c9 75 90 96 8c 0f 52 98 b5 cd 98 1f 89 20 5f |..u....R...... _| -000002e0 f2 a0 1c a3 1b 96 94 dd a9 fd 57 e9 70 e8 26 6d |..........W.p.&m| -000002f0 71 99 9b 26 6e 38 50 29 6c 90 a7 bd d9 16 03 03 |q..&n8P)l.......| -00000300 00 04 0e 00 00 00 |......| +00000030 09 00 23 00 00 ff 01 00 01 00 16 03 03 02 71 0b |..#...........q.| +00000040 00 02 6d 00 02 6a 00 02 67 30 82 02 63 30 82 01 |..m..j..g0..c0..| +00000050 cc a0 03 02 01 02 02 09 00 a2 73 00 0c 81 00 cb |..........s.....| +00000060 f3 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |.0...*.H........| +00000070 30 2b 31 17 30 15 06 03 55 04 0a 13 0e 47 6f 6f |0+1.0...U....Goo| +00000080 67 6c 65 20 54 45 53 54 49 4e 47 31 10 30 0e 06 |gle TESTING1.0..| +00000090 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..| +000000a0 0d 31 35 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.150101000000Z..| +000000b0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 26 31 |250101000000Z0&1| +000000c0 17 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 |.0...U....Google| +000000d0 20 54 45 53 54 49 4e 47 31 0b 30 09 06 03 55 04 | TESTING1.0...U.| +000000e0 03 13 02 47 6f 30 81 9f 30 0d 06 09 2a 86 48 86 |...Go0..0...*.H.| +000000f0 f7 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 |...........0....| +00000100 81 00 af 87 88 f6 20 1b 95 65 6c 14 ab 44 05 af |...... ..el..D..| +00000110 3b 45 14 e3 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 |;E...m..cM...jb5| +00000120 86 c0 4a f9 18 7c f6 aa 25 5e 7a 64 31 66 00 ba |..J..|..%^zd1f..| +00000130 f4 8e 92 af c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 |.....k.v.._A.nV.| +00000140 97 1b 97 c1 3c 12 39 21 66 3d 2b 16 d1 bc db 1c |....<.9!f=+.....| +00000150 c0 a7 da b7 ca ad ba da cb d5 21 50 ec de 8d ab |..........!P....| +00000160 d1 6b 81 4b 89 02 f3 c4 be c1 6c 89 b1 44 84 bd |.k.K......l..D..| +00000170 21 d1 04 7d 9d 16 4d f9 82 15 f6 ef fa d6 09 47 |!..}..M........G| +00000180 f2 fb 02 03 01 00 01 a3 81 93 30 81 90 30 0e 06 |..........0..0..| +00000190 03 55 1d 0f 01 01 ff 04 04 03 02 05 a0 30 1d 06 |.U...........0..| +000001a0 03 55 1d 25 04 16 30 14 06 08 2b 06 01 05 05 07 |.U.%..0...+.....| +000001b0 03 01 06 08 2b 06 01 05 05 07 03 02 30 0c 06 03 |....+.......0...| +000001c0 55 1d 13 01 01 ff 04 02 30 00 30 19 06 03 55 1d |U.......0.0...U.| +000001d0 0e 04 12 04 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e |......P..o...TMn| +000001e0 cb 69 5e 06 f4 30 1b 06 03 55 1d 23 04 14 30 12 |.i^..0...U.#..0.| +000001f0 80 10 bf 3d b6 a9 66 f2 b8 40 cf ea b4 03 78 48 |...=..f..@....xH| +00000200 1a 41 30 19 06 03 55 1d 11 04 12 30 10 82 0e 65 |.A0...U....0...e| +00000210 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 |xample.golang0..| +00000220 09 2a 86 48 86 f7 0d 01 01 0b 05 00 03 81 81 00 |.*.H............| +00000230 92 7c af 91 55 12 18 96 59 31 a6 48 40 d5 2d d5 |.|..U...Y1.H@.-.| +00000240 ee bb 02 a0 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da |.......|..0}<.v.| +00000250 4f 3d c0 fa ae 2d 33 24 6b 03 7b 1b 67 59 11 21 |O=...-3$k.{.gY.!| +00000260 b5 11 bc 77 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 |...w...n.-.5.d_"| +00000270 3e 63 10 6b be ff 14 86 6d 0d f0 15 31 a8 14 38 |>c.k....m...1..8| +00000280 1e 3b 84 87 2c cb 98 ed 51 76 b9 b1 4f dd db 9b |.;..,...Qv..O...| +00000290 84 04 86 40 fa 51 dd ba b4 8d eb e3 46 de 46 b9 |...@.Q......F.F.| +000002a0 4f 86 c7 f9 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 |O.....A4......9.| +000002b0 16 03 03 00 04 0e 00 00 00 |.........| >>> Flow 3 (client to server) -00000000 16 03 03 00 86 10 00 00 82 00 80 6e 2e 79 82 3a |...........n.y.:| -00000010 c4 68 72 f5 a2 42 3d 71 f9 ec 22 8c 0b fa f0 82 |.hr..B=q..".....| -00000020 82 c0 cb fc 52 0a 51 03 04 8c eb 4a 4e 4f b6 49 |....R.Q....JNO.I| -00000030 ef 94 65 21 3c f7 9d 46 85 6e 35 d5 17 6b ff a3 |..e!<..F.n5..k..| -00000040 5e 4d c1 36 1a 2f 68 f5 06 d4 2d 73 4f 1c 3b 7b |^M.6./h...-sO.;{| -00000050 c1 fa 4e 7e 7c f9 6c 13 a6 f4 3a 43 e9 aa be 22 |..N~|.l...:C..."| -00000060 85 6f 2f 7c 5b b0 08 e2 86 b2 ae cb a9 12 d8 32 |.o/|[..........2| -00000070 80 1d e4 2e 5d c3 66 d1 19 e5 89 33 2a 88 24 40 |....].f....3*.$@| -00000080 2a 6d 6b b5 f1 92 4b 66 06 b8 49 14 03 03 00 01 |*mk...Kf..I.....| -00000090 01 16 03 03 00 24 16 49 e2 a0 67 31 cf 0d 72 cb |.....$.I..g1..r.| -000000a0 ac 16 2c 80 37 71 69 f7 5f c4 d3 00 19 b7 4b fb |..,.7qi._.....K.| -000000b0 e5 e9 74 8e 30 b3 1c c5 ae e6 |..t.0.....| +00000000 16 03 03 00 86 10 00 00 82 00 80 87 06 ba d7 1f |................| +00000010 68 0c f2 a6 51 b4 ae af 8c c5 5d d4 bd f1 82 6d |h...Q.....]....m| +00000020 1d dd ce 69 be 07 62 13 af 06 71 3a 47 a9 bd f7 |...i..b...q:G...| +00000030 bb 27 f0 38 df 88 01 40 29 c9 bb 7b 5d 6d 28 bd |.'.8...@)..{]m(.| +00000040 c8 28 e6 6d ff 5c c9 d3 c6 f5 06 17 e5 e5 1c 5b |.(.m.\.........[| +00000050 a1 18 7a 34 92 0a 39 20 5a 22 44 6c cc 5c 8c 83 |..z4..9 Z"Dl.\..| +00000060 d0 19 4c bb 4e dc e2 64 ec b2 b8 3f 18 3f 9d 65 |..L.N..d...?.?.e| +00000070 5b 89 26 ae f6 fd 54 71 c4 45 e9 56 6a 28 42 a9 |[.&...Tq.E.Vj(B.| +00000080 5b 9f 12 69 a4 08 83 53 95 04 18 14 03 03 00 01 |[..i...S........| +00000090 01 16 03 03 00 24 55 80 0f 43 c3 08 45 99 c9 1b |.....$U..C..E...| +000000a0 fd fe dd e8 48 f2 89 99 86 ef f7 fd 5f 2a 4b 0b |....H......._*K.| +000000b0 33 0e 5f 17 bb b7 a2 3c 9d 30 |3._....<.0| >>> Flow 4 (server to client) -00000000 16 03 03 00 72 04 00 00 6e 00 00 00 00 00 68 00 |....r...n.....h.| -00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 65 |...............e| -00000020 ea 4b d1 ef ba 06 38 1e e1 88 82 3a cd 03 ac 3b |.K....8....:...;| -00000030 39 0a e0 19 fd af 6c 57 30 df 31 6e f7 92 38 4b |9.....lW0.1n..8K| -00000040 5d 77 90 39 ff 32 51 f5 ed 12 d7 b0 7c 4d 6c c5 |]w.9.2Q.....|Ml.| -00000050 76 e4 72 48 3e 59 23 fe 0d 15 df f4 ba ea b9 67 |v.rH>Y#........g| -00000060 16 23 8f 7d 15 b6 11 f1 ab d7 d4 cd a3 21 82 92 |.#.}.........!..| -00000070 2a 12 cf 95 f3 60 b2 14 03 03 00 01 01 16 03 03 |*....`..........| -00000080 00 24 89 ad 87 04 4f 08 dc 2a 71 37 fb f1 95 d1 |.$....O..*q7....| -00000090 2e 3c c2 6e 0f 38 5d e4 0e c3 f7 27 d0 46 a3 c1 |.<.n.8]....'.F..| -000000a0 a8 3b 06 ed 96 ec 17 03 03 00 21 30 d4 9f 0b 49 |.;........!0...I| -000000b0 9f a2 a8 a1 2c 0a 79 93 56 2d 8a ee 85 ed 62 42 |....,.y.V-....bB| -000000c0 8c 18 fe 7a 09 3a 24 c4 5e ed 7d 2a 15 03 03 00 |...z.:$.^.}*....| -000000d0 16 a0 24 0a 8b 90 4c fc 99 ba 67 bb 04 1e 59 69 |..$...L...g...Yi| -000000e0 c2 98 49 b5 00 0b e0 |..I....| +00000000 16 03 03 00 82 04 00 00 7e 00 00 00 00 00 78 50 |........~.....xP| +00000010 46 ad c1 db a8 38 86 7b 2b bb fd d0 c3 42 3e 00 |F....8.{+....B>.| +00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 94 |................| +00000030 6f 2c b5 83 61 c4 74 90 94 e5 6c fd 70 64 57 3a |o,..a.t...l.pdW:| +00000040 25 78 bf 9f a0 7c 51 bc 2a 69 1e b3 fd 71 34 b7 |%x...|Q.*i...q4.| +00000050 9a ef cb 49 37 f8 5d 5e 7c cf 6d fc 13 c1 52 79 |...I7.]^|.m...Ry| +00000060 8e ed c3 84 01 33 94 10 65 34 64 5e b4 9c 07 46 |.....3..e4d^...F| +00000070 5b 9e d7 5e 55 df fd c0 e9 d2 e8 d3 c6 42 18 ef |[..^U........B..| +00000080 a5 6c be e8 d2 49 c6 14 03 03 00 01 01 16 03 03 |.l...I..........| +00000090 00 24 66 94 4b b5 3f 5d 59 db 36 c1 dd 55 8c ee |.$f.K.?]Y.6..U..| +000000a0 de a4 bc d0 12 44 31 3e e4 e7 4a 51 e3 62 69 ab |.....D1>..JQ.bi.| +000000b0 14 78 85 49 a3 97 17 03 03 00 21 dd 96 5d 21 e0 |.x.I......!..]!.| +000000c0 2e 3d 33 dd 6c df bb 41 d7 bd 50 c7 1c 6f 97 34 |.=3.l..A..P..o.4| +000000d0 6a 6e d6 1d 27 81 2d f7 fb 32 85 02 15 03 03 00 |jn..'.-..2......| +000000e0 16 5e 4e 62 15 97 a7 a3 9b 1b 50 44 85 fb 28 66 |.^Nb......PD..(f| +000000f0 aa 66 54 45 c9 dc 61 |.fTE..a| diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-IssueTicketPreDisable b/libgo/go/crypto/tls/testdata/Server-TLSv12-IssueTicketPreDisable index 30f00268155..a8f7edfa2c0 100644 --- a/libgo/go/crypto/tls/testdata/Server-TLSv12-IssueTicketPreDisable +++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-IssueTicketPreDisable @@ -1,87 +1,83 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 60 01 00 00 5c 03 03 54 23 54 02 17 |....`...\..T#T..| -00000010 f3 53 13 3d 48 88 c3 19 b9 d1 3d 33 7f f5 99 56 |.S.=H.....=3...V| -00000020 04 71 1b d9 d5 64 8a 0d 4a 54 00 00 00 04 00 05 |.q...d..JT......| -00000030 00 ff 01 00 00 2f 00 23 00 00 00 0d 00 22 00 20 |...../.#.....". | +00000000 16 03 01 00 5e 01 00 00 5a 03 03 62 f6 20 66 23 |....^...Z..b. f#| +00000010 d5 71 0a c0 57 92 2e 80 b6 06 0c 54 5b 1c 77 a0 |.q..W......T[.w.| +00000020 ce 0b b2 52 4a b9 f2 c6 97 33 42 00 00 04 00 05 |...RJ....3B.....| +00000030 00 ff 01 00 00 2d 00 23 00 00 00 0d 00 20 00 1e |.....-.#..... ..| 00000040 06 01 06 02 06 03 05 01 05 02 05 03 04 01 04 02 |................| -00000050 04 03 03 01 03 02 03 03 02 01 02 02 02 03 01 01 |................| -00000060 00 0f 00 01 01 |.....| +00000050 04 03 03 01 03 02 03 03 02 01 02 02 02 03 00 0f |................| +00000060 00 01 01 |...| >>> Flow 2 (server to client) 00000000 16 03 03 00 35 02 00 00 31 03 03 00 00 00 00 00 |....5...1.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................| -00000030 09 00 23 00 00 ff 01 00 01 00 16 03 03 02 be 0b |..#.............| -00000040 00 02 ba 00 02 b7 00 02 b4 30 82 02 b0 30 82 02 |.........0...0..| -00000050 19 a0 03 02 01 02 02 09 00 85 b0 bb a4 8a 7f b8 |................| -00000060 ca 30 0d 06 09 2a 86 48 86 f7 0d 01 01 05 05 00 |.0...*.H........| -00000070 30 45 31 0b 30 09 06 03 55 04 06 13 02 41 55 31 |0E1.0...U....AU1| -00000080 13 30 11 06 03 55 04 08 13 0a 53 6f 6d 65 2d 53 |.0...U....Some-S| -00000090 74 61 74 65 31 21 30 1f 06 03 55 04 0a 13 18 49 |tate1!0...U....I| -000000a0 6e 74 65 72 6e 65 74 20 57 69 64 67 69 74 73 20 |nternet Widgits | -000000b0 50 74 79 20 4c 74 64 30 1e 17 0d 31 30 30 34 32 |Pty Ltd0...10042| -000000c0 34 30 39 30 39 33 38 5a 17 0d 31 31 30 34 32 34 |4090938Z..110424| -000000d0 30 39 30 39 33 38 5a 30 45 31 0b 30 09 06 03 55 |090938Z0E1.0...U| -000000e0 04 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 |....AU1.0...U...| -000000f0 0a 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 |.Some-State1!0..| -00000100 03 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 |.U....Internet W| -00000110 69 64 67 69 74 73 20 50 74 79 20 4c 74 64 30 81 |idgits Pty Ltd0.| -00000120 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 00 |.0...*.H........| -00000130 03 81 8d 00 30 81 89 02 81 81 00 bb 79 d6 f5 17 |....0.......y...| -00000140 b5 e5 bf 46 10 d0 dc 69 be e6 2b 07 43 5a d0 03 |...F...i..+.CZ..| -00000150 2d 8a 7a 43 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 |-.zC...R..eL,x.#| -00000160 8c b5 b4 82 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 |........;~b.,.3.| -00000170 fe 12 5c 7a 56 fc f5 06 bf fa 58 7b 26 3f b5 cd |..\zV.....X{&?..| -00000180 04 d3 d0 c9 21 96 4a c7 f4 54 9f 5a bf ef 42 71 |....!.J..T.Z..Bq| -00000190 00 fe 18 99 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e |......~.}}..9...| -000001a0 db 51 c9 7c e3 c0 4c 3b 32 66 01 cf af b1 1d b8 |.Q.|..L;2f......| -000001b0 71 9a 1d db db 89 6b ae da 2d 79 02 03 01 00 01 |q.....k..-y.....| -000001c0 a3 81 a7 30 81 a4 30 1d 06 03 55 1d 0e 04 16 04 |...0..0...U.....| -000001d0 14 b1 ad e2 85 5a cf cb 28 db 69 ce 23 69 de d3 |.....Z..(.i.#i..| -000001e0 26 8e 18 88 39 30 75 06 03 55 1d 23 04 6e 30 6c |&...90u..U.#.n0l| -000001f0 80 14 b1 ad e2 85 5a cf cb 28 db 69 ce 23 69 de |......Z..(.i.#i.| -00000200 d3 26 8e 18 88 39 a1 49 a4 47 30 45 31 0b 30 09 |.&...9.I.G0E1.0.| -00000210 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 55 |..U....AU1.0...U| -00000220 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 21 |....Some-State1!| -00000230 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e 65 |0...U....Interne| -00000240 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c 74 |t Widgits Pty Lt| -00000250 64 82 09 00 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 |d...........0...| -00000260 55 1d 13 04 05 30 03 01 01 ff 30 0d 06 09 2a 86 |U....0....0...*.| -00000270 48 86 f7 0d 01 01 05 05 00 03 81 81 00 08 6c 45 |H.............lE| -00000280 24 c7 6b b1 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a |$.k.Y..R.......z| -00000290 64 75 b5 5a 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f |du.Z.f..+...f..O| -000002a0 38 b3 6e 60 d3 92 fd f7 41 08 b5 25 13 b1 18 7a |8.n`....A..%...z| -000002b0 24 fb 30 1d ba ed 98 b9 17 ec e7 d7 31 59 db 95 |$.0.........1Y..| -000002c0 d3 1d 78 ea 50 56 5c d5 82 5a 2d 5a 5f 33 c4 b6 |..x.PV\..Z-Z_3..| -000002d0 d8 c9 75 90 96 8c 0f 52 98 b5 cd 98 1f 89 20 5f |..u....R...... _| -000002e0 f2 a0 1c a3 1b 96 94 dd a9 fd 57 e9 70 e8 26 6d |..........W.p.&m| -000002f0 71 99 9b 26 6e 38 50 29 6c 90 a7 bd d9 16 03 03 |q..&n8P)l.......| -00000300 00 04 0e 00 00 00 |......| +00000030 09 00 23 00 00 ff 01 00 01 00 16 03 03 02 71 0b |..#...........q.| +00000040 00 02 6d 00 02 6a 00 02 67 30 82 02 63 30 82 01 |..m..j..g0..c0..| +00000050 cc a0 03 02 01 02 02 09 00 a2 73 00 0c 81 00 cb |..........s.....| +00000060 f3 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |.0...*.H........| +00000070 30 2b 31 17 30 15 06 03 55 04 0a 13 0e 47 6f 6f |0+1.0...U....Goo| +00000080 67 6c 65 20 54 45 53 54 49 4e 47 31 10 30 0e 06 |gle TESTING1.0..| +00000090 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..| +000000a0 0d 31 35 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.150101000000Z..| +000000b0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 26 31 |250101000000Z0&1| +000000c0 17 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 |.0...U....Google| +000000d0 20 54 45 53 54 49 4e 47 31 0b 30 09 06 03 55 04 | TESTING1.0...U.| +000000e0 03 13 02 47 6f 30 81 9f 30 0d 06 09 2a 86 48 86 |...Go0..0...*.H.| +000000f0 f7 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 |...........0....| +00000100 81 00 af 87 88 f6 20 1b 95 65 6c 14 ab 44 05 af |...... ..el..D..| +00000110 3b 45 14 e3 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 |;E...m..cM...jb5| +00000120 86 c0 4a f9 18 7c f6 aa 25 5e 7a 64 31 66 00 ba |..J..|..%^zd1f..| +00000130 f4 8e 92 af c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 |.....k.v.._A.nV.| +00000140 97 1b 97 c1 3c 12 39 21 66 3d 2b 16 d1 bc db 1c |....<.9!f=+.....| +00000150 c0 a7 da b7 ca ad ba da cb d5 21 50 ec de 8d ab |..........!P....| +00000160 d1 6b 81 4b 89 02 f3 c4 be c1 6c 89 b1 44 84 bd |.k.K......l..D..| +00000170 21 d1 04 7d 9d 16 4d f9 82 15 f6 ef fa d6 09 47 |!..}..M........G| +00000180 f2 fb 02 03 01 00 01 a3 81 93 30 81 90 30 0e 06 |..........0..0..| +00000190 03 55 1d 0f 01 01 ff 04 04 03 02 05 a0 30 1d 06 |.U...........0..| +000001a0 03 55 1d 25 04 16 30 14 06 08 2b 06 01 05 05 07 |.U.%..0...+.....| +000001b0 03 01 06 08 2b 06 01 05 05 07 03 02 30 0c 06 03 |....+.......0...| +000001c0 55 1d 13 01 01 ff 04 02 30 00 30 19 06 03 55 1d |U.......0.0...U.| +000001d0 0e 04 12 04 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e |......P..o...TMn| +000001e0 cb 69 5e 06 f4 30 1b 06 03 55 1d 23 04 14 30 12 |.i^..0...U.#..0.| +000001f0 80 10 bf 3d b6 a9 66 f2 b8 40 cf ea b4 03 78 48 |...=..f..@....xH| +00000200 1a 41 30 19 06 03 55 1d 11 04 12 30 10 82 0e 65 |.A0...U....0...e| +00000210 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 |xample.golang0..| +00000220 09 2a 86 48 86 f7 0d 01 01 0b 05 00 03 81 81 00 |.*.H............| +00000230 92 7c af 91 55 12 18 96 59 31 a6 48 40 d5 2d d5 |.|..U...Y1.H@.-.| +00000240 ee bb 02 a0 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da |.......|..0}<.v.| +00000250 4f 3d c0 fa ae 2d 33 24 6b 03 7b 1b 67 59 11 21 |O=...-3$k.{.gY.!| +00000260 b5 11 bc 77 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 |...w...n.-.5.d_"| +00000270 3e 63 10 6b be ff 14 86 6d 0d f0 15 31 a8 14 38 |>c.k....m...1..8| +00000280 1e 3b 84 87 2c cb 98 ed 51 76 b9 b1 4f dd db 9b |.;..,...Qv..O...| +00000290 84 04 86 40 fa 51 dd ba b4 8d eb e3 46 de 46 b9 |...@.Q......F.F.| +000002a0 4f 86 c7 f9 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 |O.....A4......9.| +000002b0 16 03 03 00 04 0e 00 00 00 |.........| >>> Flow 3 (client to server) -00000000 16 03 03 00 86 10 00 00 82 00 80 27 e9 a4 f7 e7 |...........'....| -00000010 df 25 de 84 8c 1f d6 e6 c3 11 28 55 9a c1 91 37 |.%........(U...7| -00000020 84 f5 ba f8 80 0d ca 50 cb 1e 72 f7 97 6f c2 b2 |.......P..r..o..| -00000030 04 4d 13 7c e0 6e a0 1f 91 e1 38 1b a2 c0 55 16 |.M.|.n....8...U.| -00000040 7f 29 fc ed 1c 1a cf 72 14 c3 00 c1 dd 36 36 af |.).....r.....66.| -00000050 a6 e4 a8 be ba ec 13 d0 1e d0 1d fd e1 5b 27 fd |.............['.| -00000060 9a da 2e 12 c8 b0 b9 c2 b9 76 ec 7f 3c 98 b6 63 |.........v..<..c| -00000070 bc da f0 07 7a 3d e7 61 f4 2f 12 80 3b f9 3b cc |....z=.a./..;.;.| -00000080 05 c8 2f 7e 28 b2 73 bf 97 61 29 14 03 03 00 01 |../~(.s..a).....| -00000090 01 16 03 03 00 24 17 59 a9 45 53 46 33 96 50 dd |.....$.Y.ESF3.P.| -000000a0 3e 23 aa 91 38 f8 56 4a 2f 1a f2 b1 44 9b ce 17 |>#..8.VJ/...D...| -000000b0 6b 8a 89 76 bc 67 b8 8b ba 90 |k..v.g....| +00000000 16 03 03 00 86 10 00 00 82 00 80 5b 43 6f db 52 |...........[Co.R| +00000010 56 e3 d9 4b 1e c8 95 8b 78 a6 19 00 44 9c 44 b4 |V..K....x...D.D.| +00000020 f7 fe d4 3f 69 ea 9c 67 d3 48 b8 c5 93 bc 22 f1 |...?i..g.H....".| +00000030 a9 0e 81 82 d0 cf dc 0b ea f0 02 67 92 8d 72 40 |...........g..r@| +00000040 25 bb f3 88 53 c0 2f ba 38 ef da d1 7c 73 84 ec |%...S./.8...|s..| +00000050 61 96 b9 d4 93 06 4a 06 7b 6d 40 e7 bb 15 59 6e |a.....J.{m@...Yn| +00000060 ad 31 71 eb cf 84 57 3b 0c ad aa 70 02 63 24 a9 |.1q...W;...p.c$.| +00000070 7c a1 9a 6d b7 e0 4c d5 67 4c ce 53 9d b6 31 de ||..m..L.gL.S..1.| +00000080 69 b9 f5 ca a8 e3 ea d6 f5 a3 f3 14 03 03 00 01 |i...............| +00000090 01 16 03 03 00 24 66 ae 13 67 70 20 f5 f5 76 03 |.....$f..gp ..v.| +000000a0 11 6e 32 a6 73 a2 70 42 ab 4f 16 93 d2 fa a1 ac |.n2.s.pB.O......| +000000b0 4e b2 08 4a a9 b5 20 aa 80 b6 |N..J.. ...| >>> Flow 4 (server to client) -00000000 16 03 03 00 72 04 00 00 6e 00 00 00 00 00 68 00 |....r...n.....h.| -00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 65 |...............e| -00000020 ea 4b d1 ef ba 2d db 0c ba 9a d4 20 76 57 c8 ec |.K...-..... vW..| -00000030 dc 2d 77 fb fb 3b 93 5f 53 e0 14 4f 90 fb d6 55 |.-w..;._S..O...U| -00000040 57 8c 8d 0d 25 ea 5d 0d f2 91 e5 12 22 12 ec 7b |W...%.]....."..{| -00000050 5f b6 6e fd 07 59 23 24 fc b1 97 ca ea 56 a5 c2 |_.n..Y#$.....V..| -00000060 a0 e4 9e 99 64 f2 64 d0 75 7a 46 63 e3 dc 21 ed |....d.d.uzFc..!.| -00000070 78 56 e9 e1 ab 66 80 14 03 03 00 01 01 16 03 03 |xV...f..........| -00000080 00 24 fc 14 68 07 17 1f df b7 84 cb fd c1 e0 e4 |.$..h...........| -00000090 f2 1a ea 34 b5 00 7f 70 be c8 1c 0a d6 55 e3 57 |...4...p.....U.W| -000000a0 50 4e 6d 7d 8a 5d 17 03 03 00 21 24 27 50 40 c1 |PNm}.]....!$'P@.| -000000b0 c5 bd c7 9f 95 d9 ba 2e 7b 0e db ea a7 31 81 05 |........{....1..| -000000c0 75 43 b1 63 cf b8 55 92 ef 76 98 a9 15 03 03 00 |uC.c..U..v......| -000000d0 16 d7 ea 3c 79 e7 a6 2f 61 39 ec 4e 95 86 48 5e |....| +00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 94 |................| +00000030 6f 2c b5 83 61 bd 50 da 49 7f 8b 8f 58 57 00 a1 |o,..a.P.I...XW..| +00000040 11 0d 4a 9d 8a 39 dd 85 23 c0 eb 9d 1a 45 93 92 |..J..9..#....E..| +00000050 e7 af 15 a3 a4 48 da f9 a4 d8 8e cb 6c 3d 44 77 |.....H......l=Dw| +00000060 f9 c4 83 89 85 33 94 c1 c6 20 9a 73 44 83 89 5e |.....3... .sD..^| +00000070 59 ee 05 c6 7e 8d e9 7d 7b f8 84 46 b6 7d 43 ec |Y...~..}{..F.}C.| +00000080 f1 af 1f 0f 35 b4 1c 14 03 03 00 01 01 16 03 03 |....5...........| +00000090 00 24 8c 0d bd bc 34 93 ed ad 80 21 6d 08 e4 0e |.$....4....!m...| +000000a0 67 4f 99 8d df 2a 2d 4f 13 39 82 be a1 d2 1f 75 |gO...*-O.9.....u| +000000b0 73 c8 b2 ce 41 0c 17 03 03 00 21 d8 c2 50 d6 11 |s...A.....!..P..| +000000c0 bc 86 58 68 0e 60 4a 47 a5 d0 12 7e a3 b5 be 64 |..Xh.`JG...~...d| +000000d0 e6 b1 bc 62 70 85 d4 7c cd fe 67 cf 15 03 03 00 |...bp..|..g.....| +000000e0 16 e4 1c d5 f4 f7 d0 f5 b2 b3 2b 3d b0 7d c0 23 |..........+=.}.#| +000000f0 e2 5c a5 c7 a4 23 fa |.\...#.| diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-3DES b/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-3DES index 5995b3314c4..74576264d85 100644 --- a/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-3DES +++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-3DES @@ -1,83 +1,77 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 5c 01 00 00 58 03 03 52 cc 57 59 68 |....\...X..R.WYh| -00000010 11 72 a6 ec 6b 0a 47 1d 10 06 ec 75 af 07 38 a0 |.r..k.G....u..8.| -00000020 30 9e 91 12 e1 9b 19 46 0d d4 45 00 00 04 00 0a |0......F..E.....| -00000030 00 ff 01 00 00 2b 00 0d 00 22 00 20 06 01 06 02 |.....+...". ....| +00000000 16 03 01 00 5a 01 00 00 56 03 03 ac 1d 0b 6e f3 |....Z...V.....n.| +00000010 25 04 00 97 a0 79 39 c5 ef 95 8b e3 c1 87 0d 1c |%....y9.........| +00000020 0b c3 39 3e ff 23 0e 3c 28 8f 75 00 00 04 00 0a |..9>.#.<(.u.....| +00000030 00 ff 01 00 00 29 00 0d 00 20 00 1e 06 01 06 02 |.....)... ......| 00000040 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 |................| -00000050 03 02 03 03 02 01 02 02 02 03 01 01 00 0f 00 01 |................| -00000060 01 |.| +00000050 03 02 03 03 02 01 02 02 02 03 00 0f 00 01 01 |...............| >>> Flow 2 (server to client) 00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 0a 00 00 |................| -00000030 05 ff 01 00 01 00 16 03 03 02 be 0b 00 02 ba 00 |................| -00000040 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......| -00000050 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..| -00000060 09 2a 86 48 86 f7 0d 01 01 05 05 00 30 45 31 0b |.*.H........0E1.| -00000070 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 |0...U....AU1.0..| -00000080 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 |.U....Some-State| -00000090 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 |1!0...U....Inter| -000000a0 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 |net Widgits Pty | -000000b0 4c 74 64 30 1e 17 0d 31 30 30 34 32 34 30 39 30 |Ltd0...100424090| -000000c0 39 33 38 5a 17 0d 31 31 30 34 32 34 30 39 30 39 |938Z..1104240909| -000000d0 33 38 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 |38Z0E1.0...U....| -000000e0 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som| -000000f0 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..| -00000100 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi| -00000110 74 73 20 50 74 79 20 4c 74 64 30 81 9f 30 0d 06 |ts Pty Ltd0..0..| -00000120 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 |.*.H............| -00000130 30 81 89 02 81 81 00 bb 79 d6 f5 17 b5 e5 bf 46 |0.......y......F| -00000140 10 d0 dc 69 be e6 2b 07 43 5a d0 03 2d 8a 7a 43 |...i..+.CZ..-.zC| -00000150 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 8c b5 b4 82 |...R..eL,x.#....| -00000160 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 fe 12 5c 7a |....;~b.,.3...\z| -00000170 56 fc f5 06 bf fa 58 7b 26 3f b5 cd 04 d3 d0 c9 |V.....X{&?......| -00000180 21 96 4a c7 f4 54 9f 5a bf ef 42 71 00 fe 18 99 |!.J..T.Z..Bq....| -00000190 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e db 51 c9 7c |..~.}}..9....Q.|| -000001a0 e3 c0 4c 3b 32 66 01 cf af b1 1d b8 71 9a 1d db |..L;2f......q...| -000001b0 db 89 6b ae da 2d 79 02 03 01 00 01 a3 81 a7 30 |..k..-y........0| -000001c0 81 a4 30 1d 06 03 55 1d 0e 04 16 04 14 b1 ad e2 |..0...U.........| -000001d0 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 88 |.Z..(.i.#i..&...| -000001e0 39 30 75 06 03 55 1d 23 04 6e 30 6c 80 14 b1 ad |90u..U.#.n0l....| -000001f0 e2 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 |..Z..(.i.#i..&..| -00000200 88 39 a1 49 a4 47 30 45 31 0b 30 09 06 03 55 04 |.9.I.G0E1.0...U.| -00000210 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a |...AU1.0...U....| -00000220 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 |Some-State1!0...| -00000230 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 |U....Internet Wi| -00000240 64 67 69 74 73 20 50 74 79 20 4c 74 64 82 09 00 |dgits Pty Ltd...| -00000250 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 55 1d 13 04 |........0...U...| -00000260 05 30 03 01 01 ff 30 0d 06 09 2a 86 48 86 f7 0d |.0....0...*.H...| -00000270 01 01 05 05 00 03 81 81 00 08 6c 45 24 c7 6b b1 |..........lE$.k.| -00000280 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a 64 75 b5 5a |Y..R.......zdu.Z| -00000290 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f 38 b3 6e 60 |.f..+...f..O8.n`| -000002a0 d3 92 fd f7 41 08 b5 25 13 b1 18 7a 24 fb 30 1d |....A..%...z$.0.| -000002b0 ba ed 98 b9 17 ec e7 d7 31 59 db 95 d3 1d 78 ea |........1Y....x.| -000002c0 50 56 5c d5 82 5a 2d 5a 5f 33 c4 b6 d8 c9 75 90 |PV\..Z-Z_3....u.| -000002d0 96 8c 0f 52 98 b5 cd 98 1f 89 20 5f f2 a0 1c a3 |...R...... _....| -000002e0 1b 96 94 dd a9 fd 57 e9 70 e8 26 6d 71 99 9b 26 |......W.p.&mq..&| -000002f0 6e 38 50 29 6c 90 a7 bd d9 16 03 03 00 04 0e 00 |n8P)l...........| -00000300 00 00 |..| +00000030 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.| +00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......| +00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..| +00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.| +00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google | +00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..| +00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150| +000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501| +000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..| +000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES| +000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G| +000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....| +000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........| +00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..| +00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.| +00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......| +00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....| +00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........| +00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K| +00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}| +00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....| +00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..| +00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%| +000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........| +000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...| +000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....| +000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.| +000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=| +000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.| +00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp| +00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H| +00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..| +00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....| +00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..| +00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w| +00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k| +00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..| +00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@| +00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...| +000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....| +000002b0 04 0e 00 00 00 |.....| >>> Flow 3 (client to server) -00000000 16 03 03 00 86 10 00 00 82 00 80 7a c0 73 ec cb |...........z.s..| -00000010 cf c2 a8 86 c0 7e 03 63 57 a1 ce 42 37 6d 78 54 |.....~.cW..B7mxT| -00000020 29 f5 3e cc 57 c7 0d d9 69 e1 52 5c 3b 6b c4 c7 |).>.W...i.R\;k..| -00000030 20 6d 59 ee c0 07 81 74 74 9f 62 41 64 f0 4d c8 | mY....tt.bAd.M.| -00000040 9b aa 1a b9 da 56 07 f5 6c 1c 59 8c d3 f9 08 d9 |.....V..l.Y.....| -00000050 08 f4 16 93 5d 9a e5 6f fb 9f ba 3d 3c d6 81 ad |....]..o...=<...| -00000060 02 12 a7 28 b6 81 6a 77 c3 e9 d7 c7 54 d6 77 83 |...(..jw....T.w.| -00000070 77 de 71 fb b3 f3 2d c4 a5 b1 e5 de aa 0e 21 bd |w.q...-.......!.| -00000080 91 a2 dc 7f f7 6f 90 82 54 b1 e7 14 03 03 00 01 |.....o..T.......| -00000090 01 16 03 03 00 30 8f ee bf fb c8 5c 54 f5 29 23 |.....0.....\T.)#| -000000a0 d4 55 f6 98 a1 6e d5 43 e7 81 b2 36 f2 98 d8 1b |.U...n.C...6....| -000000b0 0d 76 cb 14 ba 32 d7 36 30 e6 ab 42 80 95 f6 8a |.v...2.60..B....| -000000c0 60 64 a0 6b 90 81 |`d.k..| +00000000 16 03 03 00 86 10 00 00 82 00 80 15 75 c5 63 e0 |............u.c.| +00000010 c3 a5 89 dd b3 bf 03 1d bd 62 86 2e 10 98 79 cb |.........b....y.| +00000020 40 3d 9b 36 7e 55 65 d7 80 0a c5 24 ff ad 98 d5 |@=.6~Ue....$....| +00000030 d4 d9 4e 1b ed 50 0a fa 8a 3e f3 01 c4 e3 47 f7 |..N..P...>....G.| +00000040 bd 81 fc 33 0b 61 6b b5 3f 38 9b 24 cd 7d 46 66 |...3.ak.?8.$.}Ff| +00000050 18 87 ea 67 04 b7 ad 23 ac 64 4e 21 cd 29 9f 60 |...g...#.dN!.).`| +00000060 0e c1 ca 3d 25 d6 d5 2b e2 60 dc b5 57 be c0 b8 |...=%..+.`..W...| +00000070 b6 35 25 96 5b 36 55 53 86 b7 90 ef 6c bf 45 2a |.5%.[6US....l.E*| +00000080 3d a0 af 08 f0 8a 9c d0 d8 6b 88 14 03 03 00 01 |=........k......| +00000090 01 16 03 03 00 30 c5 0f b8 12 c6 5a 42 6a d8 3f |.....0.....ZBj.?| +000000a0 f5 49 e4 9a 5d b7 93 90 e7 09 1f 68 40 9d 33 a9 |.I..]......h@.3.| +000000b0 21 fa 9c 12 c7 7c d4 bf 91 c2 f8 ac 27 b9 8b b6 |!....|......'...| +000000c0 34 6e f3 c0 fb 83 |4n....| >>> Flow 4 (server to client) 00000000 14 03 03 00 01 01 16 03 03 00 30 00 00 00 00 00 |..........0.....| -00000010 00 00 00 2c 21 52 34 63 ac e3 a3 66 45 00 41 0c |...,!R4c...fE.A.| -00000020 93 5d 6a 74 5a 25 dc 69 1d 76 73 0c f4 42 6a 18 |.]jtZ%.i.vs..Bj.| -00000030 5b 62 23 e7 fe 41 cf d4 9b 86 35 17 03 03 00 30 |[b#..A....5....0| -00000040 00 00 00 00 00 00 00 00 7d 5d ce 43 85 5c 6b 89 |........}].C.\k.| -00000050 c9 a5 0e 22 69 8e b9 4a 77 4c c0 4e cc 79 d9 7e |..."i..JwL.N.y.~| -00000060 a3 c8 d3 db 5c 53 f8 92 4d c4 5a 88 72 58 05 11 |....\S..M.Z.rX..| -00000070 15 03 03 00 20 00 00 00 00 00 00 00 00 1d 63 8b |.... .........c.| -00000080 a7 74 fb 76 1d 47 31 93 1f ec 8c e2 18 8e 21 dd |.t.v.G1.......!.| -00000090 87 97 9f 1c ca |.....| +00000010 00 00 00 c1 a2 65 c1 36 63 85 cd ca 5a eb 50 ab |.....e.6c...Z.P.| +00000020 bb ec 43 30 37 8f 71 b9 b7 2d 1b bb a2 88 fa d5 |..C07.q..-......| +00000030 b4 a5 c5 4b 19 71 53 46 7d bb d0 17 03 03 00 30 |...K.qSF}......0| +00000040 00 00 00 00 00 00 00 00 6a a1 3d c6 35 a0 58 c4 |........j.=.5.X.| +00000050 ef 12 f2 59 1e 02 42 33 42 5f fe 87 a2 1a ce b7 |...Y..B3B_......| +00000060 0d d2 36 7c 7f 1a 4c 79 1f 38 34 58 b3 05 fb 96 |..6|..Ly.84X....| +00000070 15 03 03 00 20 00 00 00 00 00 00 00 00 a1 89 42 |.... ..........B| +00000080 bc 58 1f 2f 9b c4 d7 e2 d1 ce 1c c9 e0 a5 47 be |.X./..........G.| +00000090 63 0c a4 bf 26 |c...&| diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-AES b/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-AES index a152a96a849..4ca860d2c26 100644 --- a/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-AES +++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-AES @@ -1,87 +1,81 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 5c 01 00 00 58 03 03 52 cc 57 59 d0 |....\...X..R.WY.| -00000010 38 05 36 7e e3 1e 93 2a 5a bf dc c2 f8 0a 03 6f |8.6~...*Z......o| -00000020 1a fc 21 74 e5 8b 2a c3 9e 2c 26 00 00 04 00 2f |..!t..*..,&..../| -00000030 00 ff 01 00 00 2b 00 0d 00 22 00 20 06 01 06 02 |.....+...". ....| +00000000 16 03 01 00 5a 01 00 00 56 03 03 be 9a 2f 46 66 |....Z...V..../Ff| +00000010 a3 b3 10 62 63 b6 32 cb de 1e eb 76 13 50 60 d0 |...bc.2....v.P`.| +00000020 ee 40 a9 cd 50 ae d8 86 10 37 8b 00 00 04 00 2f |.@..P....7...../| +00000030 00 ff 01 00 00 29 00 0d 00 20 00 1e 06 01 06 02 |.....)... ......| 00000040 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 |................| -00000050 03 02 03 03 02 01 02 02 02 03 01 01 00 0f 00 01 |................| -00000060 01 |.| +00000050 03 02 03 03 02 01 02 02 02 03 00 0f 00 01 01 |...............| >>> Flow 2 (server to client) 00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2f 00 00 |............./..| -00000030 05 ff 01 00 01 00 16 03 03 02 be 0b 00 02 ba 00 |................| -00000040 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......| -00000050 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..| -00000060 09 2a 86 48 86 f7 0d 01 01 05 05 00 30 45 31 0b |.*.H........0E1.| -00000070 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 |0...U....AU1.0..| -00000080 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 |.U....Some-State| -00000090 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 |1!0...U....Inter| -000000a0 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 |net Widgits Pty | -000000b0 4c 74 64 30 1e 17 0d 31 30 30 34 32 34 30 39 30 |Ltd0...100424090| -000000c0 39 33 38 5a 17 0d 31 31 30 34 32 34 30 39 30 39 |938Z..1104240909| -000000d0 33 38 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 |38Z0E1.0...U....| -000000e0 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som| -000000f0 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..| -00000100 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi| -00000110 74 73 20 50 74 79 20 4c 74 64 30 81 9f 30 0d 06 |ts Pty Ltd0..0..| -00000120 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 |.*.H............| -00000130 30 81 89 02 81 81 00 bb 79 d6 f5 17 b5 e5 bf 46 |0.......y......F| -00000140 10 d0 dc 69 be e6 2b 07 43 5a d0 03 2d 8a 7a 43 |...i..+.CZ..-.zC| -00000150 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 8c b5 b4 82 |...R..eL,x.#....| -00000160 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 fe 12 5c 7a |....;~b.,.3...\z| -00000170 56 fc f5 06 bf fa 58 7b 26 3f b5 cd 04 d3 d0 c9 |V.....X{&?......| -00000180 21 96 4a c7 f4 54 9f 5a bf ef 42 71 00 fe 18 99 |!.J..T.Z..Bq....| -00000190 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e db 51 c9 7c |..~.}}..9....Q.|| -000001a0 e3 c0 4c 3b 32 66 01 cf af b1 1d b8 71 9a 1d db |..L;2f......q...| -000001b0 db 89 6b ae da 2d 79 02 03 01 00 01 a3 81 a7 30 |..k..-y........0| -000001c0 81 a4 30 1d 06 03 55 1d 0e 04 16 04 14 b1 ad e2 |..0...U.........| -000001d0 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 88 |.Z..(.i.#i..&...| -000001e0 39 30 75 06 03 55 1d 23 04 6e 30 6c 80 14 b1 ad |90u..U.#.n0l....| -000001f0 e2 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 |..Z..(.i.#i..&..| -00000200 88 39 a1 49 a4 47 30 45 31 0b 30 09 06 03 55 04 |.9.I.G0E1.0...U.| -00000210 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a |...AU1.0...U....| -00000220 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 |Some-State1!0...| -00000230 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 |U....Internet Wi| -00000240 64 67 69 74 73 20 50 74 79 20 4c 74 64 82 09 00 |dgits Pty Ltd...| -00000250 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 55 1d 13 04 |........0...U...| -00000260 05 30 03 01 01 ff 30 0d 06 09 2a 86 48 86 f7 0d |.0....0...*.H...| -00000270 01 01 05 05 00 03 81 81 00 08 6c 45 24 c7 6b b1 |..........lE$.k.| -00000280 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a 64 75 b5 5a |Y..R.......zdu.Z| -00000290 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f 38 b3 6e 60 |.f..+...f..O8.n`| -000002a0 d3 92 fd f7 41 08 b5 25 13 b1 18 7a 24 fb 30 1d |....A..%...z$.0.| -000002b0 ba ed 98 b9 17 ec e7 d7 31 59 db 95 d3 1d 78 ea |........1Y....x.| -000002c0 50 56 5c d5 82 5a 2d 5a 5f 33 c4 b6 d8 c9 75 90 |PV\..Z-Z_3....u.| -000002d0 96 8c 0f 52 98 b5 cd 98 1f 89 20 5f f2 a0 1c a3 |...R...... _....| -000002e0 1b 96 94 dd a9 fd 57 e9 70 e8 26 6d 71 99 9b 26 |......W.p.&mq..&| -000002f0 6e 38 50 29 6c 90 a7 bd d9 16 03 03 00 04 0e 00 |n8P)l...........| -00000300 00 00 |..| +00000030 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.| +00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......| +00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..| +00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.| +00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google | +00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..| +00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150| +000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501| +000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..| +000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES| +000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G| +000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....| +000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........| +00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..| +00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.| +00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......| +00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....| +00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........| +00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K| +00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}| +00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....| +00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..| +00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%| +000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........| +000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...| +000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....| +000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.| +000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=| +000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.| +00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp| +00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H| +00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..| +00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....| +00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..| +00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w| +00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k| +00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..| +00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@| +00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...| +000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....| +000002b0 04 0e 00 00 00 |.....| >>> Flow 3 (client to server) -00000000 16 03 03 00 86 10 00 00 82 00 80 4b b4 28 bc 78 |...........K.(.x| -00000010 41 34 f3 49 e8 74 07 74 42 ae 2e 55 9e 9a ce e5 |A4.I.t.tB..U....| -00000020 4a 1b e7 55 c7 64 c4 9c b3 dd 20 d6 f8 8e 67 b3 |J..U.d.... ...g.| -00000030 7a 5c 3b 34 e4 1a f6 bd 65 fc 21 cd 9a de 64 77 |z\;4....e.!...dw| -00000040 09 a5 92 e5 a4 f5 18 7b 23 5b 8b c1 95 23 97 6f |.......{#[...#.o| -00000050 76 55 04 34 22 7d 43 71 db cd eb f8 36 36 44 4b |vU.4"}Cq....66DK| -00000060 ae e3 cc ec 64 88 7b e1 ea d6 ab 49 35 94 a5 04 |....d.{....I5...| -00000070 1e 83 c5 cf 21 bb ca 33 5f d4 bf 1d d3 4d 07 59 |....!..3_....M.Y| -00000080 b4 39 b2 4b 7b 05 43 70 0d ba 7a 14 03 03 00 01 |.9.K{.Cp..z.....| -00000090 01 16 03 03 00 40 74 4b 7d b2 53 49 ea 86 90 c3 |.....@tK}.SI....| -000000a0 64 6b 64 31 1a 2a 3f 1a 37 1e 56 b8 dd 12 6d 56 |dkd1.*?.7.V...mV| -000000b0 2a 61 92 5b 39 e7 e1 be 71 70 4b 9b b3 f0 71 e7 |*a.[9...qpK...q.| -000000c0 47 2e 2e 17 c3 0a 66 9f 69 74 30 2d f0 a0 7f 84 |G.....f.it0-....| -000000d0 25 db c1 81 ee cf |%.....| +00000000 16 03 03 00 86 10 00 00 82 00 80 61 b4 31 93 2b |...........a.1.+| +00000010 d5 e8 06 74 b1 f6 d6 5f a3 92 78 b6 cf bf 7f ea |...t..._..x.....| +00000020 a2 07 1e 90 94 68 5b 19 ae d4 e3 11 78 96 58 fd |.....h[.....x.X.| +00000030 96 18 f2 09 58 dc 39 a1 d9 9e 83 f0 24 45 6e 6b |....X.9.....$Enk| +00000040 e6 5e e7 cb 94 42 00 10 64 d5 d2 bc 80 23 bd fe |.^...B..d....#..| +00000050 5c 3e 3a 80 ff 38 b8 dc ff 25 ba b0 0a cc ef 94 |\>:..8...%......| +00000060 a1 31 bd 04 93 91 86 6e 8b fd a1 9d 01 ee 91 a6 |.1.....n........| +00000070 44 8b 21 55 52 67 3e b1 e4 6e bd 1f 07 85 e1 97 |D.!URg>..n......| +00000080 7f 55 70 00 5f f4 4b e6 50 45 f7 14 03 03 00 01 |.Up._.K.PE......| +00000090 01 16 03 03 00 40 71 ff ab 6d 79 3c da dc 5b 34 |.....@q..my<..[4| +000000a0 48 39 48 08 e3 29 cb 53 21 fd 67 93 0b f8 81 47 |H9H..).S!.g....G| +000000b0 40 7f 23 50 5f 94 db 2b 7b 7e 9f 0b bf 38 59 d9 |@.#P_..+{~...8Y.| +000000c0 6b 57 8f 1e 83 eb 93 2c 62 12 31 c6 f5 21 f2 22 |kW.....,b.1..!."| +000000d0 7a 82 e9 e6 ec 38 |z....8| >>> Flow 4 (server to client) 00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |..........@.....| -00000010 00 00 00 00 00 00 00 00 00 00 00 f3 4d 5a fc 21 |............MZ.!| -00000020 30 b5 a1 86 9d e2 ea 38 ac 54 57 fa 5a 54 97 b8 |0......8.TW.ZT..| -00000030 bb 4d 64 09 ef ce a1 75 0c 50 8d ff 5c c2 e9 47 |.Md....u.P..\..G| -00000040 95 93 53 c0 bd dc c5 9c e0 59 17 17 03 03 00 40 |..S......Y.....@| +00000010 00 00 00 00 00 00 00 00 00 00 00 45 87 33 41 c1 |...........E.3A.| +00000020 b8 e7 4c 11 1c 1b 7b 55 51 85 06 01 c1 b6 87 6b |..L...{UQ......k| +00000030 01 b3 56 c4 5a 37 ea b6 3a c4 b0 da 1b 5c 15 d4 |..V.Z7..:....\..| +00000040 03 5a 57 e9 9a 56 16 a5 fa 77 1c 17 03 03 00 40 |.ZW..V...w.....@| 00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| -00000060 69 c5 48 6e 45 cf 98 1b 2c 23 40 d1 ab a3 c2 e2 |i.HnE...,#@.....| -00000070 10 7b b1 c8 21 3c f0 eb 96 bd 4f 78 b2 4a 7b 18 |.{..!<....Ox.J{.| -00000080 4c b1 a6 67 bf 06 40 01 d0 8d 91 be 17 d8 0c 71 |L..g..@........q| +00000060 6f 2e 7c ba 3d 85 4c 7b 1f 13 a5 d6 97 e6 67 f4 |o.|.=.L{......g.| +00000070 24 d5 a8 d4 26 41 64 0a fd b3 2e a0 a2 7a 2b 54 |$...&Ad......z+T| +00000080 a4 1d 6e fe 4c c4 73 e3 76 d0 3a 60 52 df b0 53 |..n.L.s.v.:`R..S| 00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........| -000000a0 00 00 00 00 00 20 84 80 3d 70 fe ae ee d7 2f e9 |..... ..=p..../.| -000000b0 bf 65 30 bf 0b dd 98 ea bb ba 12 14 98 53 7f d5 |.e0..........S..| -000000c0 56 ce 06 3c d0 |V..<.| +000000a0 00 00 00 00 00 8b 0a 6d 14 3b 84 bc 7d c6 8d 9d |.......m.;..}...| +000000b0 d5 27 32 84 4b 14 75 42 0f aa 5e 88 ba fa a2 c7 |.'2.K.uB..^.....| +000000c0 16 93 8a c4 fd |.....| diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM b/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM index 0ddfe022f22..7a26ebd82a7 100644 --- a/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM +++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM @@ -1,93 +1,87 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 9c 01 00 00 98 03 03 53 04 f1 30 73 |...........S..0s| -00000010 a1 ea 8c d2 90 1c c6 d6 0d 3c af 58 21 65 90 25 |.........<.X!e.%| -00000020 5e fa f4 27 22 65 c9 68 90 b9 04 00 00 04 c0 2f |^..'"e.h......./| -00000030 00 ff 01 00 00 6b 00 0b 00 04 03 00 01 02 00 0a |.....k..........| +00000000 16 03 01 00 9a 01 00 00 96 03 03 16 dc f8 f5 3a |...............:| +00000010 13 32 e6 1f bd f6 3c 66 b7 4c 67 17 ee b2 2a ba |.2....>> Flow 2 (server to client) 00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 c0 2f 00 00 |............./..| -00000030 05 ff 01 00 01 00 16 03 03 02 be 0b 00 02 ba 00 |................| -00000040 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......| -00000050 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..| -00000060 09 2a 86 48 86 f7 0d 01 01 05 05 00 30 45 31 0b |.*.H........0E1.| -00000070 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 |0...U....AU1.0..| -00000080 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 |.U....Some-State| -00000090 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 |1!0...U....Inter| -000000a0 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 |net Widgits Pty | -000000b0 4c 74 64 30 1e 17 0d 31 30 30 34 32 34 30 39 30 |Ltd0...100424090| -000000c0 39 33 38 5a 17 0d 31 31 30 34 32 34 30 39 30 39 |938Z..1104240909| -000000d0 33 38 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 |38Z0E1.0...U....| -000000e0 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som| -000000f0 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..| -00000100 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi| -00000110 74 73 20 50 74 79 20 4c 74 64 30 81 9f 30 0d 06 |ts Pty Ltd0..0..| -00000120 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 |.*.H............| -00000130 30 81 89 02 81 81 00 bb 79 d6 f5 17 b5 e5 bf 46 |0.......y......F| -00000140 10 d0 dc 69 be e6 2b 07 43 5a d0 03 2d 8a 7a 43 |...i..+.CZ..-.zC| -00000150 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 8c b5 b4 82 |...R..eL,x.#....| -00000160 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 fe 12 5c 7a |....;~b.,.3...\z| -00000170 56 fc f5 06 bf fa 58 7b 26 3f b5 cd 04 d3 d0 c9 |V.....X{&?......| -00000180 21 96 4a c7 f4 54 9f 5a bf ef 42 71 00 fe 18 99 |!.J..T.Z..Bq....| -00000190 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e db 51 c9 7c |..~.}}..9....Q.|| -000001a0 e3 c0 4c 3b 32 66 01 cf af b1 1d b8 71 9a 1d db |..L;2f......q...| -000001b0 db 89 6b ae da 2d 79 02 03 01 00 01 a3 81 a7 30 |..k..-y........0| -000001c0 81 a4 30 1d 06 03 55 1d 0e 04 16 04 14 b1 ad e2 |..0...U.........| -000001d0 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 88 |.Z..(.i.#i..&...| -000001e0 39 30 75 06 03 55 1d 23 04 6e 30 6c 80 14 b1 ad |90u..U.#.n0l....| -000001f0 e2 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 |..Z..(.i.#i..&..| -00000200 88 39 a1 49 a4 47 30 45 31 0b 30 09 06 03 55 04 |.9.I.G0E1.0...U.| -00000210 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a |...AU1.0...U....| -00000220 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 |Some-State1!0...| -00000230 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 |U....Internet Wi| -00000240 64 67 69 74 73 20 50 74 79 20 4c 74 64 82 09 00 |dgits Pty Ltd...| -00000250 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 55 1d 13 04 |........0...U...| -00000260 05 30 03 01 01 ff 30 0d 06 09 2a 86 48 86 f7 0d |.0....0...*.H...| -00000270 01 01 05 05 00 03 81 81 00 08 6c 45 24 c7 6b b1 |..........lE$.k.| -00000280 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a 64 75 b5 5a |Y..R.......zdu.Z| -00000290 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f 38 b3 6e 60 |.f..+...f..O8.n`| -000002a0 d3 92 fd f7 41 08 b5 25 13 b1 18 7a 24 fb 30 1d |....A..%...z$.0.| -000002b0 ba ed 98 b9 17 ec e7 d7 31 59 db 95 d3 1d 78 ea |........1Y....x.| -000002c0 50 56 5c d5 82 5a 2d 5a 5f 33 c4 b6 d8 c9 75 90 |PV\..Z-Z_3....u.| -000002d0 96 8c 0f 52 98 b5 cd 98 1f 89 20 5f f2 a0 1c a3 |...R...... _....| -000002e0 1b 96 94 dd a9 fd 57 e9 70 e8 26 6d 71 99 9b 26 |......W.p.&mq..&| -000002f0 6e 38 50 29 6c 90 a7 bd d9 16 03 03 00 cd 0c 00 |n8P)l...........| -00000300 00 c9 03 00 17 41 04 1e 18 37 ef 0d 19 51 88 35 |.....A...7...Q.5| -00000310 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd a7 24 20 3e |uq..T[....g..$ >| -00000320 b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e f1 07 9f 6c |.V...(^.+-O....l| -00000330 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 a6 b5 68 1a |K[.V.2B.X..I..h.| -00000340 41 03 56 6b dc 5a 89 04 01 00 80 a2 54 61 84 29 |A.Vk.Z......Ta.)| -00000350 3e 97 4b 97 9a 9f 5c c0 49 6d 86 d2 79 8e 95 a1 |>.K...\.Im..y...| -00000360 0a 5a 36 73 34 bb 05 73 35 47 e1 2b 5d f3 ef 36 |.Z6s4..s5G.+]..6| -00000370 a8 32 e2 7e ef aa 3f 1f b3 64 60 d4 06 2e 98 e3 |.2.~..?..d`.....| -00000380 11 e2 60 3c d6 20 17 63 b2 6f a0 cd 21 01 2b 4e |..`<. .c.o..!.+N| -00000390 b2 a8 55 04 39 37 5c 6c 71 66 4d a3 eb 1b 83 67 |..U.97\lqfM....g| -000003a0 6b 15 a0 56 9a f1 a2 79 92 29 ce 58 3c 10 4d 65 |k..V...y.).X<.Me| -000003b0 1f 22 e3 ea d8 74 aa 01 7e ca f3 89 23 41 4d bd |."...t..~...#AM.| -000003c0 df 77 4e 59 54 97 74 ad 07 ea c0 16 03 03 00 04 |.wNYT.t.........| -000003d0 0e 00 00 00 |....| +00000030 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.| +00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......| +00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..| +00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.| +00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google | +00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..| +00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150| +000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501| +000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..| +000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES| +000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G| +000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....| +000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........| +00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..| +00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.| +00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......| +00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....| +00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........| +00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K| +00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}| +00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....| +00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..| +00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%| +000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........| +000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...| +000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....| +000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.| +000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=| +000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.| +00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp| +00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H| +00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..| +00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....| +00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..| +00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w| +00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k| +00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..| +00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@| +00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...| +000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....| +000002b0 cd 0c 00 00 c9 03 00 17 41 04 1e 18 37 ef 0d 19 |........A...7...| +000002c0 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd a7 |Q.5uq..T[....g..| +000002d0 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e f1 |$ >.V...(^.+-O..| +000002e0 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 a6 |..lK[.V.2B.X..I.| +000002f0 b5 68 1a 41 03 56 6b dc 5a 89 05 01 00 80 40 b3 |.h.A.Vk.Z.....@.| +00000300 66 ee 53 3c 80 f4 da d1 de e6 fe 50 c8 89 60 d5 |f.S<.......P..`.| +00000310 e4 80 73 39 91 79 6c cf 89 bb a5 da e4 c7 e5 0d |..s9.yl.........| +00000320 13 a6 76 24 65 1a a2 b8 cb 95 c2 c6 9d 66 74 57 |..v$e........ftW| +00000330 9e 90 4f 48 77 88 3a b4 f3 fa 88 ab 61 22 d3 40 |..OHw.:.....a".@| +00000340 08 c4 0a 69 19 ed c3 ea d8 15 79 12 d5 ac 8d af |...i......y.....| +00000350 41 7d 87 4b a9 ff f8 cb 24 55 88 38 34 11 a5 bd |A}.K....$U.84...| +00000360 c1 d6 e5 86 d5 64 b5 f2 df c8 03 f2 a2 6b ff f4 |.....d.......k..| +00000370 a8 38 e0 18 04 d4 cd bd e0 cc 63 fc 3f 8b 16 03 |.8........c.?...| +00000380 03 00 04 0e 00 00 00 |.......| >>> Flow 3 (client to server) -00000000 16 03 03 00 46 10 00 00 42 41 04 45 65 ce f7 b9 |....F...BA.Ee...| -00000010 52 e3 fb 13 db 91 f2 65 43 84 57 f5 1a 19 a0 e6 |R......eC.W.....| -00000020 89 2d bb 2c 83 6b 62 f6 6f 1f 26 ae 59 67 bd dc |.-.,.kb.o.&.Yg..| -00000030 c4 9e 0b dc 7d 6e f8 6b 95 8c 61 47 3d cd d1 df |....}n.k..aG=...| -00000040 82 45 30 81 c3 a3 49 5d 85 59 70 14 03 03 00 01 |.E0...I].Yp.....| -00000050 01 16 03 03 00 28 3f aa 85 33 f9 c6 95 a0 56 ff |.....(?..3....V.| -00000060 1c f1 5a ba 6e 41 50 0c ab 92 e1 e2 8e 89 1c f1 |..Z.nAP.........| -00000070 fa 54 1b f1 f5 00 01 12 6d c4 96 78 b6 87 |.T......m..x..| +00000000 16 03 03 00 46 10 00 00 42 41 04 de de ff 8c df |....F...BA......| +00000010 d8 4c 72 af 29 3c 4d e0 ed 0f 34 cc fd 2d 52 63 |.Lr.)>> Flow 4 (server to client) 00000000 14 03 03 00 01 01 16 03 03 00 28 00 00 00 00 00 |..........(.....| -00000010 00 00 00 94 5c be 46 05 d6 d0 b0 3a 56 dc 2c 10 |....\.F....:V.,.| -00000020 0f 6f 5d 33 33 7f a5 4e 74 84 bf 63 87 c4 f4 49 |.o]33..Nt..c...I| -00000030 bc 6b ab 17 03 03 00 25 00 00 00 00 00 00 00 01 |.k.....%........| -00000040 7e 4f f9 ae ae fe 6b a0 4a f8 0f 0b b4 b6 65 b6 |~O....k.J.....e.| -00000050 be 24 5f 94 6d d1 db 54 11 07 b9 ce 01 15 03 03 |.$_.m..T........| -00000060 00 1a 00 00 00 00 00 00 00 02 a8 1c d6 62 ac fd |.............b..| -00000070 77 ba 23 92 5d 34 f1 17 c7 e1 1c 99 |w.#.]4......| +00000010 00 00 00 92 90 01 f0 70 fa 57 2e 40 d3 4c ef 6a |.......p.W.@.L.j| +00000020 03 0c 56 65 f7 c0 3b d0 8a db 48 c9 ae 58 3e 7c |..Ve..;...H..X>|| +00000030 d1 48 67 17 03 03 00 25 00 00 00 00 00 00 00 01 |.Hg....%........| +00000040 9e 35 a0 13 73 da 3f 26 ff 1d 90 08 e9 cc 40 7e |.5..s.?&......@~| +00000050 82 f3 5e 6e b4 8e 5a 39 7f a4 09 60 b2 15 03 03 |..^n..Z9...`....| +00000060 00 1a 00 00 00 00 00 00 00 02 04 95 9b 2d 17 1c |.............-..| +00000070 6a bc 26 f7 6c 8e f1 c0 0e 82 4a 44 |j.&.l.....JD| diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-AES256-GCM-SHA384 b/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-AES256-GCM-SHA384 new file mode 100644 index 00000000000..d59645c52db --- /dev/null +++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-AES256-GCM-SHA384 @@ -0,0 +1,87 @@ +>>> Flow 1 (client to server) +00000000 16 03 01 00 9a 01 00 00 96 03 03 5d 6b 2a ff 74 |...........]k*.t| +00000010 88 f1 68 8d 1b eb c3 84 34 b5 19 0a 7d f1 9a 0f |..h.....4...}...| +00000020 4d c3 0a d7 98 b8 72 e0 73 e4 38 00 00 04 c0 30 |M.....r.s.8....0| +00000030 00 ff 01 00 00 69 00 0b 00 04 03 00 01 02 00 0a |.....i..........| +00000040 00 34 00 32 00 0e 00 0d 00 19 00 0b 00 0c 00 18 |.4.2............| +00000050 00 09 00 0a 00 16 00 17 00 08 00 06 00 07 00 14 |................| +00000060 00 15 00 04 00 05 00 12 00 13 00 01 00 02 00 03 |................| +00000070 00 0f 00 10 00 11 00 0d 00 20 00 1e 06 01 06 02 |......... ......| +00000080 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 |................| +00000090 03 02 03 03 02 01 02 02 02 03 00 0f 00 01 01 |...............| +>>> Flow 2 (server to client) +00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......| +00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +00000020 00 00 00 00 00 00 00 00 00 00 00 00 c0 30 00 00 |.............0..| +00000030 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.| +00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......| +00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..| +00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.| +00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google | +00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..| +00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150| +000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501| +000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..| +000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES| +000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G| +000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....| +000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........| +00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..| +00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.| +00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......| +00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....| +00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........| +00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K| +00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}| +00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....| +00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..| +00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%| +000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........| +000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...| +000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....| +000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.| +000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=| +000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.| +00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp| +00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H| +00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..| +00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....| +00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..| +00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w| +00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k| +00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..| +00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@| +00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...| +000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....| +000002b0 cd 0c 00 00 c9 03 00 17 41 04 1e 18 37 ef 0d 19 |........A...7...| +000002c0 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd a7 |Q.5uq..T[....g..| +000002d0 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e f1 |$ >.V...(^.+-O..| +000002e0 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 a6 |..lK[.V.2B.X..I.| +000002f0 b5 68 1a 41 03 56 6b dc 5a 89 05 01 00 80 22 6b |.h.A.Vk.Z....."k| +00000300 87 4b f8 ba f2 09 91 ee ce 81 67 d4 fd d8 b5 07 |.K........g.....| +00000310 fe c3 88 96 ca e3 3a f0 87 cc ae 44 94 8e 8f 70 |......:....D...p| +00000320 79 cd de a2 26 4e 17 45 d7 ea 0f 95 a6 c9 7b 17 |y...&N.E......{.| +00000330 68 7c f5 e8 6c d5 87 6d 5a 7e 53 af 95 0c 42 91 |h|..l..mZ~S...B.| +00000340 c0 07 18 75 fd 74 1c ad ef df f8 41 b1 ad fc 36 |...u.t.....A...6| +00000350 19 31 cf c8 3f 36 55 dd 54 ac 44 a9 3a d1 ae 23 |.1..?6U.T.D.:..#| +00000360 0a 18 bf b7 6f c7 bc a6 70 50 5e 50 dd da ff 5b |....o...pP^P...[| +00000370 67 7d 0a f5 70 a0 8c 88 d9 38 d4 bf a9 c3 16 03 |g}..p....8......| +00000380 03 00 04 0e 00 00 00 |.......| +>>> Flow 3 (client to server) +00000000 16 03 03 00 46 10 00 00 42 41 04 d0 f7 11 ae 9f |....F...BA......| +00000010 ec 2e ac 8e 97 6c 58 0e 57 32 8e ac fa 3e af 36 |.....lX.W2...>.6| +00000020 22 e1 41 2b d3 d1 9c c2 1d 51 c0 e4 20 b3 4c 85 |".A+.....Q.. .L.| +00000030 b8 bd f2 d1 c6 2f 7d 83 c7 43 d9 31 36 1a 83 ca |...../}..C.16...| +00000040 c6 89 f8 ba 8c d1 7e 99 04 6e 92 14 03 03 00 01 |......~..n......| +00000050 01 16 03 03 00 28 32 67 c1 6e 5e 1e 4b 51 1b 70 |.....(2g.n^.KQ.p| +00000060 54 b9 1d 69 79 38 bd fa 7c 6b 58 71 af 72 08 2d |T..iy8..|kXq.r.-| +00000070 55 df 24 be 5b 41 0a ef 0e 90 cf d9 62 81 |U.$.[A......b.| +>>> Flow 4 (server to client) +00000000 14 03 03 00 01 01 16 03 03 00 28 00 00 00 00 00 |..........(.....| +00000010 00 00 00 87 2a 3e 09 54 54 c3 58 c0 5b 7b 91 00 |....*>.TT.X.[{..| +00000020 c4 07 98 9e de 1f f8 04 bb d7 42 04 55 7d 18 a4 |..........B.U}..| +00000030 41 7c a6 17 03 03 00 25 00 00 00 00 00 00 00 01 |A|.....%........| +00000040 ab 23 05 51 b4 60 a2 77 01 58 be a6 9f 89 2b b5 |.#.Q.`.w.X....+.| +00000050 77 6b 19 23 67 f7 89 f1 ef d6 1b f5 e7 15 03 03 |wk.#g...........| +00000060 00 1a 00 00 00 00 00 00 00 02 8a bf f0 fb 9f 56 |...............V| +00000070 36 f1 92 49 a9 e5 40 87 f9 87 9e 4d |6..I..@....M| diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-RC4 b/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-RC4 index b703a8f766c..13163d68f68 100644 --- a/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-RC4 +++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-RSA-RC4 @@ -1,79 +1,73 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 5c 01 00 00 58 03 03 52 cc 57 59 c9 |....\...X..R.WY.| -00000010 c3 13 fc 18 8a ee c2 0e 88 ff fb 4a 16 f2 eb eb |...........J....| -00000020 d4 f8 b3 5b cd bb 25 0e 0b cb 48 00 00 04 00 05 |...[..%...H.....| -00000030 00 ff 01 00 00 2b 00 0d 00 22 00 20 06 01 06 02 |.....+...". ....| +00000000 16 03 01 00 5a 01 00 00 56 03 03 8a fe f5 09 70 |....Z...V......p| +00000010 8e 6b e3 2b 12 ff d1 b2 ae 15 bf 47 0e ca 5c b5 |.k.+.......G..\.| +00000020 bb 0e ad af e5 a6 7e 36 c5 a4 c3 00 00 04 00 05 |......~6........| +00000030 00 ff 01 00 00 29 00 0d 00 20 00 1e 06 01 06 02 |.....)... ......| 00000040 06 03 05 01 05 02 05 03 04 01 04 02 04 03 03 01 |................| -00000050 03 02 03 03 02 01 02 02 02 03 01 01 00 0f 00 01 |................| -00000060 01 |.| +00000050 03 02 03 03 02 01 02 02 02 03 00 0f 00 01 01 |...............| >>> Flow 2 (server to client) 00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................| -00000030 05 ff 01 00 01 00 16 03 03 02 be 0b 00 02 ba 00 |................| -00000040 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......| -00000050 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..| -00000060 09 2a 86 48 86 f7 0d 01 01 05 05 00 30 45 31 0b |.*.H........0E1.| -00000070 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 |0...U....AU1.0..| -00000080 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 |.U....Some-State| -00000090 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 |1!0...U....Inter| -000000a0 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 |net Widgits Pty | -000000b0 4c 74 64 30 1e 17 0d 31 30 30 34 32 34 30 39 30 |Ltd0...100424090| -000000c0 39 33 38 5a 17 0d 31 31 30 34 32 34 30 39 30 39 |938Z..1104240909| -000000d0 33 38 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 |38Z0E1.0...U....| -000000e0 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som| -000000f0 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..| -00000100 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi| -00000110 74 73 20 50 74 79 20 4c 74 64 30 81 9f 30 0d 06 |ts Pty Ltd0..0..| -00000120 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 |.*.H............| -00000130 30 81 89 02 81 81 00 bb 79 d6 f5 17 b5 e5 bf 46 |0.......y......F| -00000140 10 d0 dc 69 be e6 2b 07 43 5a d0 03 2d 8a 7a 43 |...i..+.CZ..-.zC| -00000150 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 8c b5 b4 82 |...R..eL,x.#....| -00000160 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 fe 12 5c 7a |....;~b.,.3...\z| -00000170 56 fc f5 06 bf fa 58 7b 26 3f b5 cd 04 d3 d0 c9 |V.....X{&?......| -00000180 21 96 4a c7 f4 54 9f 5a bf ef 42 71 00 fe 18 99 |!.J..T.Z..Bq....| -00000190 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e db 51 c9 7c |..~.}}..9....Q.|| -000001a0 e3 c0 4c 3b 32 66 01 cf af b1 1d b8 71 9a 1d db |..L;2f......q...| -000001b0 db 89 6b ae da 2d 79 02 03 01 00 01 a3 81 a7 30 |..k..-y........0| -000001c0 81 a4 30 1d 06 03 55 1d 0e 04 16 04 14 b1 ad e2 |..0...U.........| -000001d0 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 88 |.Z..(.i.#i..&...| -000001e0 39 30 75 06 03 55 1d 23 04 6e 30 6c 80 14 b1 ad |90u..U.#.n0l....| -000001f0 e2 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 |..Z..(.i.#i..&..| -00000200 88 39 a1 49 a4 47 30 45 31 0b 30 09 06 03 55 04 |.9.I.G0E1.0...U.| -00000210 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a |...AU1.0...U....| -00000220 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 |Some-State1!0...| -00000230 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 |U....Internet Wi| -00000240 64 67 69 74 73 20 50 74 79 20 4c 74 64 82 09 00 |dgits Pty Ltd...| -00000250 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 55 1d 13 04 |........0...U...| -00000260 05 30 03 01 01 ff 30 0d 06 09 2a 86 48 86 f7 0d |.0....0...*.H...| -00000270 01 01 05 05 00 03 81 81 00 08 6c 45 24 c7 6b b1 |..........lE$.k.| -00000280 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a 64 75 b5 5a |Y..R.......zdu.Z| -00000290 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f 38 b3 6e 60 |.f..+...f..O8.n`| -000002a0 d3 92 fd f7 41 08 b5 25 13 b1 18 7a 24 fb 30 1d |....A..%...z$.0.| -000002b0 ba ed 98 b9 17 ec e7 d7 31 59 db 95 d3 1d 78 ea |........1Y....x.| -000002c0 50 56 5c d5 82 5a 2d 5a 5f 33 c4 b6 d8 c9 75 90 |PV\..Z-Z_3....u.| -000002d0 96 8c 0f 52 98 b5 cd 98 1f 89 20 5f f2 a0 1c a3 |...R...... _....| -000002e0 1b 96 94 dd a9 fd 57 e9 70 e8 26 6d 71 99 9b 26 |......W.p.&mq..&| -000002f0 6e 38 50 29 6c 90 a7 bd d9 16 03 03 00 04 0e 00 |n8P)l...........| -00000300 00 00 |..| +00000030 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.| +00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......| +00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..| +00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.| +00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google | +00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..| +00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150| +000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501| +000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..| +000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES| +000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G| +000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....| +000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........| +00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..| +00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.| +00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......| +00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....| +00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........| +00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K| +00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}| +00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....| +00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..| +00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%| +000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........| +000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...| +000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....| +000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.| +000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=| +000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.| +00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp| +00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H| +00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..| +00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....| +00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..| +00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w| +00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k| +00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..| +00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@| +00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...| +000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....| +000002b0 04 0e 00 00 00 |.....| >>> Flow 3 (client to server) -00000000 16 03 03 00 86 10 00 00 82 00 80 35 b3 60 ba 14 |...........5.`..| -00000010 5f 19 24 a0 24 de 4e 85 a9 64 78 3a 51 24 64 70 |_.$.$.N..dx:Q$dp| -00000020 88 55 6d c3 11 b8 d3 9f bc 7a 33 f8 3c 48 93 2f |.Um......z3..|.| -00000070 44 82 f4 24 03 22 40 00 64 27 53 15 41 8c 01 e9 |D..$."@.d'S.A...| -00000080 39 32 fa 8e 2d f9 b4 89 34 15 d6 14 03 03 00 01 |92..-...4.......| -00000090 01 16 03 03 00 24 f5 61 8b 24 bf b4 82 3a cf 49 |.....$.a.$...:.I| -000000a0 99 a0 b1 1b a7 a7 a3 92 7c 84 85 e0 64 a3 3d bd |........|...d.=.| -000000b0 38 98 7d 97 a8 b9 2a 35 a9 09 |8.}...*5..| +00000000 16 03 03 00 86 10 00 00 82 00 80 1c f7 2c 18 38 |.............,.8| +00000010 d9 41 b5 ab b7 35 2b 75 2d 66 ba c8 70 c2 19 1c |.A...5+u-f..p...| +00000020 f2 6d d9 a9 a8 40 8e b5 2c 75 99 06 a5 25 be 0d |.m...@..,u...%..| +00000030 b4 b0 9b aa fc 6b 12 a5 b3 e7 02 60 aa 25 e9 7f |.....k.....`.%..| +00000040 6b f5 c4 7a 1d 16 a5 d1 76 cc d5 a1 18 68 91 c3 |k..z....v....h..| +00000050 57 b8 10 f2 b8 81 f3 1b 74 ef 6c 37 3e 81 41 09 |W.......t.l7>.A.| +00000060 2a c5 15 e6 cc bb 74 4c 01 7a b9 82 5c e2 7f b7 |*.....tL.z..\...| +00000070 ac 2d 76 30 18 30 c2 19 8c 5f f2 80 41 89 bb 47 |.-v0.0..._..A..G| +00000080 28 3d 61 cc 3c 06 a8 76 93 57 71 14 03 03 00 01 |(=a.<..v.Wq.....| +00000090 01 16 03 03 00 24 46 34 1f cc eb 53 c7 d2 04 28 |.....$F4...S...(| +000000a0 b6 3d 3f 39 06 70 56 b7 db eb 53 9c 66 c3 45 9f |.=?9.pV...S.f.E.| +000000b0 69 ca 58 8f e7 ba a7 e6 5a 97 |i.X.....Z.| >>> Flow 4 (server to client) -00000000 14 03 03 00 01 01 16 03 03 00 24 c9 0b 84 e6 39 |..........$....9| -00000010 f2 e0 f3 ac 9f 0f 17 92 5f 6d de 94 18 c4 60 d9 |........_m....`.| -00000020 66 c3 0d 1a ae c2 8f 46 8f 7f f0 58 0e 4a 9b 17 |f......F...X.J..| -00000030 03 03 00 21 8b 73 a1 6a 7e d9 7e 4f 1d cc b2 7d |...!.s.j~.~O...}| -00000040 3c 83 3f 52 f8 08 77 01 4c 65 11 6d 50 25 9a cc |<.?R..w.Le.mP%..| -00000050 e3 54 27 72 59 15 03 03 00 16 3d c8 ab 14 51 fa |.T'rY.....=...Q.| -00000060 97 f1 ef 5f b4 4f 44 58 d4 93 3b ae e5 61 1f a3 |..._.ODX..;..a..| +00000000 14 03 03 00 01 01 16 03 03 00 24 78 c3 02 89 60 |..........$x...`| +00000010 e7 72 9f 51 87 14 ca 2e 0d 79 98 eb 1e 39 62 f9 |.r.Q.....y...9b.| +00000020 fc a5 c9 2c f8 0c 04 16 60 70 90 b7 31 f8 30 17 |...,....`p..1.0.| +00000030 03 03 00 21 6a b7 24 73 a7 0d 17 04 d7 54 a8 ea |...!j.$s.....T..| +00000040 28 4e f2 0a ef 87 d5 a9 b8 84 81 46 8e 97 d1 ae |(N.........F....| +00000050 3c cc b1 6b 72 15 03 03 00 16 1a bb 2f df ae 3e |<..kr......./..>| +00000060 a7 89 69 3e 35 f2 f6 cd 35 60 29 3a 6f be 32 0d |..i>5...5`):o.2.| diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-Resume b/libgo/go/crypto/tls/testdata/Server-TLSv12-Resume index c495d4adc60..8cacd218408 100644 --- a/libgo/go/crypto/tls/testdata/Server-TLSv12-Resume +++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-Resume @@ -1,36 +1,37 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 e8 01 00 00 e4 03 03 52 cc 57 59 c3 |...........R.WY.| -00000010 8b df 97 05 d8 5f 16 22 b4 b1 e7 cb 7d 2f 9b 58 |....._."....}/.X| -00000020 a3 f4 d7 2c a4 c1 9d 49 ed 4b ba 20 90 da 90 3e |...,...I.K. ...>| -00000030 36 19 7a db 56 43 26 f7 dc 42 57 33 22 ed 9d a4 |6.z.VC&..BW3"...| -00000040 9d 53 da f8 9d 4e 60 66 71 a0 2e 2e 00 04 00 05 |.S...N`fq.......| -00000050 00 ff 01 00 00 97 00 23 00 68 00 00 00 00 00 00 |.......#.h......| -00000060 00 00 00 00 00 00 00 00 00 00 65 ea 4b d1 ef ba |..........e.K...| -00000070 06 38 1e e1 88 82 3a cd 03 ac 3b 39 0a e0 19 fd |.8....:...;9....| -00000080 af 6c 57 30 df 31 6e f7 92 38 4b 5d 77 90 39 ff |.lW0.1n..8K]w.9.| -00000090 32 51 f5 ed 12 d7 b0 7c 4d 6c c5 76 e4 72 48 3e |2Q.....|Ml.v.rH>| -000000a0 59 23 fe 0d 15 df f4 ba ea b9 67 16 23 8f 7d 15 |Y#........g.#.}.| -000000b0 b6 11 f1 ab d7 d4 cd a3 21 82 92 2a 12 cf 95 f3 |........!..*....| -000000c0 60 b2 00 0d 00 22 00 20 06 01 06 02 06 03 05 01 |`....". ........| -000000d0 05 02 05 03 04 01 04 02 04 03 03 01 03 02 03 03 |................| -000000e0 02 01 02 02 02 03 01 01 00 0f 00 01 01 |.............| +00000000 16 03 01 00 f6 01 00 00 f2 03 03 53 1e 13 2e bd |...........S....| +00000010 ad 66 fd 77 1a ad 5f 4d cb bd 2e ca b5 c2 45 1d |.f.w.._M......E.| +00000020 7c 83 9d 62 3e 39 9c ce 78 99 e7 20 b4 06 b0 ec ||..b>9..x.. ....| +00000030 cf b7 52 6e 38 10 31 37 b2 e6 58 0f fa e3 b0 cb |..Rn8.17..X.....| +00000040 20 a4 d2 4b f3 7d 92 e6 7e 13 37 08 00 04 00 05 | ..K.}..~.7.....| +00000050 00 ff 01 00 00 a5 00 23 00 78 50 46 ad c1 db a8 |.......#.xPF....| +00000060 38 86 7b 2b bb fd d0 c3 42 3e 00 00 00 00 00 00 |8.{+....B>......| +00000070 00 00 00 00 00 00 00 00 00 00 94 6f 2c b5 83 61 |...........o,..a| +00000080 c4 74 90 94 e5 6c fd 70 64 57 3a 25 78 bf 9f a0 |.t...l.pdW:%x...| +00000090 7c 51 bc 2a 69 1e b3 fd 71 34 b7 9a ef cb 49 37 ||Q.*i...q4....I7| +000000a0 f8 5d 5e 7c cf 6d fc 13 c1 52 79 8e ed c3 84 01 |.]^|.m...Ry.....| +000000b0 33 94 10 65 34 64 5e b4 9c 07 46 5b 9e d7 5e 55 |3..e4d^...F[..^U| +000000c0 df fd c0 e9 d2 e8 d3 c6 42 18 ef a5 6c be e8 d2 |........B...l...| +000000d0 49 c6 00 0d 00 20 00 1e 06 01 06 02 06 03 05 01 |I.... ..........| +000000e0 05 02 05 03 04 01 04 02 04 03 03 01 03 02 03 03 |................| +000000f0 02 01 02 02 02 03 00 0f 00 01 01 |...........| >>> Flow 2 (server to client) 00000000 16 03 03 00 51 02 00 00 4d 03 03 00 00 00 00 00 |....Q...M.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| -00000020 00 00 00 00 00 00 00 00 00 00 00 20 90 da 90 3e |........... ...>| -00000030 36 19 7a db 56 43 26 f7 dc 42 57 33 22 ed 9d a4 |6.z.VC&..BW3"...| -00000040 9d 53 da f8 9d 4e 60 66 71 a0 2e 2e 00 05 00 00 |.S...N`fq.......| +00000020 00 00 00 00 00 00 00 00 00 00 00 20 b4 06 b0 ec |........... ....| +00000030 cf b7 52 6e 38 10 31 37 b2 e6 58 0f fa e3 b0 cb |..Rn8.17..X.....| +00000040 20 a4 d2 4b f3 7d 92 e6 7e 13 37 08 00 05 00 00 | ..K.}..~.7.....| 00000050 05 ff 01 00 01 00 14 03 03 00 01 01 16 03 03 00 |................| -00000060 24 11 12 ff 28 10 14 4c e5 0e ad a7 fa f3 92 fb |$...(..L........| -00000070 13 7d ae f2 b2 4a 6b a1 9e 67 cf a8 f7 8c 6f a0 |.}...Jk..g....o.| -00000080 6c 30 0e 18 55 |l0..U| +00000060 24 24 31 13 8c 45 4f 8a fc 71 50 94 b0 6f 02 5e |$$1..EO..qP..o.^| +00000070 da d3 a3 13 8b c8 53 fb 54 8d ef 90 f7 55 b1 be |......S.T....U..| +00000080 37 30 05 e5 5d |70..]| >>> Flow 3 (client to server) -00000000 14 03 03 00 01 01 16 03 03 00 24 0d 46 41 8b 24 |..........$.FA.$| -00000010 36 01 a9 fd 8b ec fc e6 b1 83 96 df 0d 3e 53 54 |6............>ST| -00000020 58 b8 43 f2 a6 25 5e 1a ae 19 9e d2 28 44 92 |X.C..%^.....(D.| +00000000 14 03 03 00 01 01 16 03 03 00 24 ed dd e4 a5 09 |..........$.....| +00000010 0d 7c cb e4 90 9c a1 1c 21 f4 13 bd 45 8f f4 d8 |.|......!...E...| +00000020 7e e2 89 7a 0d f4 75 99 66 8c 05 a3 1a e2 2b |~..z..u.f.....+| >>> Flow 4 (server to client) -00000000 17 03 03 00 21 c4 fb f6 53 bb 3e 04 cc 0b a0 03 |....!...S.>.....| -00000010 fa 49 96 da b5 8d b2 f2 e5 d8 f3 5c 27 57 4f 9c |.I.........\'WO.| -00000020 30 00 34 fc 52 92 15 03 03 00 16 a3 02 7a 50 d2 |0.4.R........zP.| -00000030 c6 b3 fc 69 8f e4 94 ae ab 22 ad 05 1d 15 69 b9 |...i....."....i.| -00000040 a5 |.| +00000000 17 03 03 00 21 69 fa 9e 98 fb 7a 95 b1 8e e5 74 |....!i....z....t| +00000010 03 02 d7 3d 69 c4 b8 c9 5b 49 e3 30 32 e3 c5 6a |...=i...[I.02..j| +00000020 fa 20 98 bd 01 ed 15 03 03 00 16 c9 b1 20 1f 30 |. ........... .0| +00000030 c1 2f 15 75 cd 82 45 de 1a 81 cd dc 10 05 1c 45 |./.u..E........E| +00000040 dc |.| diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-ResumeDisabled b/libgo/go/crypto/tls/testdata/Server-TLSv12-ResumeDisabled index db833f65559..912c1787a1e 100644 --- a/libgo/go/crypto/tls/testdata/Server-TLSv12-ResumeDisabled +++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-ResumeDisabled @@ -1,87 +1,83 @@ >>> Flow 1 (client to server) -00000000 16 03 01 00 e8 01 00 00 e4 03 03 54 23 54 02 a5 |...........T#T..| -00000010 10 11 0f 6d e5 2d 2f e8 bb 52 b1 38 3f 65 01 43 |...m.-/..R.8?e.C| -00000020 36 cc 48 f6 09 22 a1 85 20 28 3c 20 35 8b fe 7a |6.H..".. (< 5..z| -00000030 41 3b 59 3a 5d b9 b3 21 f0 62 e9 0d 7b af f5 5d |A;Y:]..!.b..{..]| -00000040 fa 65 1a 40 c8 ca cd 74 8c ef d2 fb 00 04 00 05 |.e.@...t........| -00000050 00 ff 01 00 00 97 00 23 00 68 00 00 00 00 00 00 |.......#.h......| -00000060 00 00 00 00 00 00 00 00 00 00 65 ea 4b d1 ef ba |..........e.K...| -00000070 2d db 0c ba 9a d4 20 76 57 c8 ec dc 2d 77 fb fb |-..... vW...-w..| -00000080 3b 93 5f 53 e0 14 4f 90 fb d6 55 57 8c 8d 0d 25 |;._S..O...UW...%| -00000090 ea 5d 0d f2 91 e5 12 22 12 ec 7b 5f b6 6e fd 07 |.]....."..{_.n..| -000000a0 59 23 24 fc b1 97 ca ea 56 a5 c2 a0 e4 9e 99 64 |Y#$.....V......d| -000000b0 f2 64 d0 75 7a 46 63 e3 dc 21 ed 78 56 e9 e1 ab |.d.uzFc..!.xV...| -000000c0 66 80 00 0d 00 22 00 20 06 01 06 02 06 03 05 01 |f....". ........| -000000d0 05 02 05 03 04 01 04 02 04 03 03 01 03 02 03 03 |................| -000000e0 02 01 02 02 02 03 01 01 00 0f 00 01 01 |.............| +00000000 16 03 01 00 f6 01 00 00 f2 03 03 aa 0c c2 75 42 |..............uB| +00000010 62 2a 1d 14 a0 cc a1 e4 a7 19 77 50 80 2b f8 05 |b*........wP.+..| +00000020 0b fa 60 3a a7 a7 84 d3 e1 68 26 20 68 97 0c ae |..`:.....h& h...| +00000030 7b 1d bc 13 14 a8 f6 c1 e1 96 1f 54 18 2c cb 99 |{..........T.,..| +00000040 17 7d be 45 6a 39 53 c6 50 c7 8c 75 00 04 00 05 |.}.Ej9S.P..u....| +00000050 00 ff 01 00 00 a5 00 23 00 78 50 46 ad c1 db a8 |.......#.xPF....| +00000060 38 86 7b 2b bb fd d0 c3 42 3e 00 00 00 00 00 00 |8.{+....B>......| +00000070 00 00 00 00 00 00 00 00 00 00 94 6f 2c b5 83 61 |...........o,..a| +00000080 bd 50 da 49 7f 8b 8f 58 57 00 a1 11 0d 4a 9d 8a |.P.I...XW....J..| +00000090 39 dd 85 23 c0 eb 9d 1a 45 93 92 e7 af 15 a3 a4 |9..#....E.......| +000000a0 48 da f9 a4 d8 8e cb 6c 3d 44 77 f9 c4 83 89 85 |H......l=Dw.....| +000000b0 33 94 c1 c6 20 9a 73 44 83 89 5e 59 ee 05 c6 7e |3... .sD..^Y...~| +000000c0 8d e9 7d 7b f8 84 46 b6 7d 43 ec f1 af 1f 0f 35 |..}{..F.}C.....5| +000000d0 b4 1c 00 0d 00 20 00 1e 06 01 06 02 06 03 05 01 |..... ..........| +000000e0 05 02 05 03 04 01 04 02 04 03 03 01 03 02 03 03 |................| +000000f0 02 01 02 02 02 03 00 0f 00 01 01 |...........| >>> Flow 2 (server to client) 00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| 00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 05 00 00 |................| -00000030 05 ff 01 00 01 00 16 03 03 02 be 0b 00 02 ba 00 |................| -00000040 02 b7 00 02 b4 30 82 02 b0 30 82 02 19 a0 03 02 |.....0...0......| -00000050 01 02 02 09 00 85 b0 bb a4 8a 7f b8 ca 30 0d 06 |.............0..| -00000060 09 2a 86 48 86 f7 0d 01 01 05 05 00 30 45 31 0b |.*.H........0E1.| -00000070 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 |0...U....AU1.0..| -00000080 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 |.U....Some-State| -00000090 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 |1!0...U....Inter| -000000a0 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 |net Widgits Pty | -000000b0 4c 74 64 30 1e 17 0d 31 30 30 34 32 34 30 39 30 |Ltd0...100424090| -000000c0 39 33 38 5a 17 0d 31 31 30 34 32 34 30 39 30 39 |938Z..1104240909| -000000d0 33 38 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 |38Z0E1.0...U....| -000000e0 41 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d |AU1.0...U....Som| -000000f0 65 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a |e-State1!0...U..| -00000100 13 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 |..Internet Widgi| -00000110 74 73 20 50 74 79 20 4c 74 64 30 81 9f 30 0d 06 |ts Pty Ltd0..0..| -00000120 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 |.*.H............| -00000130 30 81 89 02 81 81 00 bb 79 d6 f5 17 b5 e5 bf 46 |0.......y......F| -00000140 10 d0 dc 69 be e6 2b 07 43 5a d0 03 2d 8a 7a 43 |...i..+.CZ..-.zC| -00000150 85 b7 14 52 e7 a5 65 4c 2c 78 b8 23 8c b5 b4 82 |...R..eL,x.#....| -00000160 e5 de 1f 95 3b 7e 62 a5 2c a5 33 d6 fe 12 5c 7a |....;~b.,.3...\z| -00000170 56 fc f5 06 bf fa 58 7b 26 3f b5 cd 04 d3 d0 c9 |V.....X{&?......| -00000180 21 96 4a c7 f4 54 9f 5a bf ef 42 71 00 fe 18 99 |!.J..T.Z..Bq....| -00000190 07 7f 7e 88 7d 7d f1 04 39 c4 a2 2e db 51 c9 7c |..~.}}..9....Q.|| -000001a0 e3 c0 4c 3b 32 66 01 cf af b1 1d b8 71 9a 1d db |..L;2f......q...| -000001b0 db 89 6b ae da 2d 79 02 03 01 00 01 a3 81 a7 30 |..k..-y........0| -000001c0 81 a4 30 1d 06 03 55 1d 0e 04 16 04 14 b1 ad e2 |..0...U.........| -000001d0 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 88 |.Z..(.i.#i..&...| -000001e0 39 30 75 06 03 55 1d 23 04 6e 30 6c 80 14 b1 ad |90u..U.#.n0l....| -000001f0 e2 85 5a cf cb 28 db 69 ce 23 69 de d3 26 8e 18 |..Z..(.i.#i..&..| -00000200 88 39 a1 49 a4 47 30 45 31 0b 30 09 06 03 55 04 |.9.I.G0E1.0...U.| -00000210 06 13 02 41 55 31 13 30 11 06 03 55 04 08 13 0a |...AU1.0...U....| -00000220 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 1f 06 03 |Some-State1!0...| -00000230 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 20 57 69 |U....Internet Wi| -00000240 64 67 69 74 73 20 50 74 79 20 4c 74 64 82 09 00 |dgits Pty Ltd...| -00000250 85 b0 bb a4 8a 7f b8 ca 30 0c 06 03 55 1d 13 04 |........0...U...| -00000260 05 30 03 01 01 ff 30 0d 06 09 2a 86 48 86 f7 0d |.0....0...*.H...| -00000270 01 01 05 05 00 03 81 81 00 08 6c 45 24 c7 6b b1 |..........lE$.k.| -00000280 59 ab 0c 52 cc f2 b0 14 d7 87 9d 7a 64 75 b5 5a |Y..R.......zdu.Z| -00000290 95 66 e4 c5 2b 8e ae 12 66 1f eb 4f 38 b3 6e 60 |.f..+...f..O8.n`| -000002a0 d3 92 fd f7 41 08 b5 25 13 b1 18 7a 24 fb 30 1d |....A..%...z$.0.| -000002b0 ba ed 98 b9 17 ec e7 d7 31 59 db 95 d3 1d 78 ea |........1Y....x.| -000002c0 50 56 5c d5 82 5a 2d 5a 5f 33 c4 b6 d8 c9 75 90 |PV\..Z-Z_3....u.| -000002d0 96 8c 0f 52 98 b5 cd 98 1f 89 20 5f f2 a0 1c a3 |...R...... _....| -000002e0 1b 96 94 dd a9 fd 57 e9 70 e8 26 6d 71 99 9b 26 |......W.p.&mq..&| -000002f0 6e 38 50 29 6c 90 a7 bd d9 16 03 03 00 04 0e 00 |n8P)l...........| -00000300 00 00 |..| +00000030 05 ff 01 00 01 00 16 03 03 02 71 0b 00 02 6d 00 |..........q...m.| +00000040 02 6a 00 02 67 30 82 02 63 30 82 01 cc a0 03 02 |.j..g0..c0......| +00000050 01 02 02 09 00 a2 73 00 0c 81 00 cb f3 30 0d 06 |......s......0..| +00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 2b 31 17 |.*.H........0+1.| +00000070 30 15 06 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 |0...U....Google | +00000080 54 45 53 54 49 4e 47 31 10 30 0e 06 03 55 04 03 |TESTING1.0...U..| +00000090 13 07 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 35 30 |..Go Root0...150| +000000a0 31 30 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 |101000000Z..2501| +000000b0 30 31 30 30 30 30 30 30 5a 30 26 31 17 30 15 06 |01000000Z0&1.0..| +000000c0 03 55 04 0a 13 0e 47 6f 6f 67 6c 65 20 54 45 53 |.U....Google TES| +000000d0 54 49 4e 47 31 0b 30 09 06 03 55 04 03 13 02 47 |TING1.0...U....G| +000000e0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....| +000000f0 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 af 87 |.......0........| +00000100 88 f6 20 1b 95 65 6c 14 ab 44 05 af 3b 45 14 e3 |.. ..el..D..;E..| +00000110 b7 6d fd 00 63 4d 95 7f fe 6a 62 35 86 c0 4a f9 |.m..cM...jb5..J.| +00000120 18 7c f6 aa 25 5e 7a 64 31 66 00 ba f4 8e 92 af |.|..%^zd1f......| +00000130 c7 6b d8 76 d4 f3 5f 41 cb 6e 56 15 97 1b 97 c1 |.k.v.._A.nV.....| +00000140 3c 12 39 21 66 3d 2b 16 d1 bc db 1c c0 a7 da b7 |<.9!f=+.........| +00000150 ca ad ba da cb d5 21 50 ec de 8d ab d1 6b 81 4b |......!P.....k.K| +00000160 89 02 f3 c4 be c1 6c 89 b1 44 84 bd 21 d1 04 7d |......l..D..!..}| +00000170 9d 16 4d f9 82 15 f6 ef fa d6 09 47 f2 fb 02 03 |..M........G....| +00000180 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..| +00000190 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%| +000001a0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........| +000001b0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...| +000001c0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....| +000001d0 10 12 50 8d 89 6f 1b d1 dc 54 4d 6e cb 69 5e 06 |..P..o...TMn.i^.| +000001e0 f4 30 1b 06 03 55 1d 23 04 14 30 12 80 10 bf 3d |.0...U.#..0....=| +000001f0 b6 a9 66 f2 b8 40 cf ea b4 03 78 48 1a 41 30 19 |..f..@....xH.A0.| +00000200 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp| +00000210 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H| +00000220 86 f7 0d 01 01 0b 05 00 03 81 81 00 92 7c af 91 |.............|..| +00000230 55 12 18 96 59 31 a6 48 40 d5 2d d5 ee bb 02 a0 |U...Y1.H@.-.....| +00000240 f5 c2 1e 7c 9b b3 30 7d 3c dc 76 da 4f 3d c0 fa |...|..0}<.v.O=..| +00000250 ae 2d 33 24 6b 03 7b 1b 67 59 11 21 b5 11 bc 77 |.-3$k.{.gY.!...w| +00000260 b9 d9 e0 6e a8 2d 2e 35 fa 64 5f 22 3e 63 10 6b |...n.-.5.d_">c.k| +00000270 be ff 14 86 6d 0d f0 15 31 a8 14 38 1e 3b 84 87 |....m...1..8.;..| +00000280 2c cb 98 ed 51 76 b9 b1 4f dd db 9b 84 04 86 40 |,...Qv..O......@| +00000290 fa 51 dd ba b4 8d eb e3 46 de 46 b9 4f 86 c7 f9 |.Q......F.F.O...| +000002a0 a4 c2 41 34 ac cc f6 ea b0 ab 39 18 16 03 03 00 |..A4......9.....| +000002b0 04 0e 00 00 00 |.....| >>> Flow 3 (client to server) -00000000 16 03 03 00 86 10 00 00 82 00 80 ae 02 dd 1f 1a |................| -00000010 86 83 f5 2f 82 46 4b 29 58 aa a1 b3 56 8b 4e 40 |.../.FK)X...V.N@| -00000020 ef 23 65 67 ad 48 e5 e1 fd ae dd bf 68 fd bd a6 |.#eg.H......h...| -00000030 13 a0 7e 05 ab f7 20 e1 6a 4e d1 37 93 08 1d c9 |..~... .jN.7....| -00000040 37 e0 b5 34 28 bf 20 45 45 da 0f 7e 51 a7 c6 ae |7..4(. EE..~Q...| -00000050 61 6c 07 1b 73 ef da 6e 25 c4 ed be e3 3f da ae |al..s..n%....?..| -00000060 cd 3c 17 9c 2e ee fb 47 9d b3 a1 b2 c3 5d e0 83 |.<.....G.....]..| -00000070 74 20 37 2d 72 d6 d0 4d 58 0e 26 1c 50 22 95 08 |t 7-r..MX.&.P"..| -00000080 7d e0 5f 86 99 9e 2c 2e a7 a0 7f 14 03 03 00 01 |}._...,.........| -00000090 01 16 03 03 00 24 a2 ab 41 25 a5 cf 04 18 1d 98 |.....$..A%......| -000000a0 88 6c 59 21 86 33 54 f4 35 b4 21 6e a5 29 d5 6e |.lY!.3T.5.!n.).n| -000000b0 3d 08 72 b0 af 46 b5 8f 6b 86 |=.r..F..k.| +00000000 16 03 03 00 86 10 00 00 82 00 80 ac 10 32 61 b0 |.............2a.| +00000010 03 e3 1e 2f 89 91 5f d6 4c e0 82 a7 82 41 67 d3 |.../.._.L....Ag.| +00000020 5f b3 68 2d c0 d1 6f 03 7b 79 94 cc bb 35 6c 8a |_.h-..o.{y...5l.| +00000030 bf 1c 83 ff 88 91 5c 04 64 cc a0 df 0b 08 8c 0f |......\.d.......| +00000040 72 13 17 9f 27 14 8d 9a af 17 70 41 44 9f 89 8c |r...'.....pAD...| +00000050 fa e4 66 33 4d bd 2f 93 2a 1e 85 a1 af 9e 27 12 |..f3M./.*.....'.| +00000060 59 a4 13 67 56 85 c2 86 47 f8 c5 49 8f a4 c2 6e |Y..gV...G..I...n| +00000070 04 78 0f 11 2b fb 7e 34 b8 eb 25 93 71 ab 9f f5 |.x..+.~4..%.q...| +00000080 93 df 2b c3 1e 9e 6a 9e e3 57 aa 14 03 03 00 01 |..+...j..W......| +00000090 01 16 03 03 00 24 e0 13 15 10 4c db f3 b6 de d2 |.....$....L.....| +000000a0 68 02 f5 ea 1f 8e 58 70 4a 5a 78 d9 66 c5 74 77 |h.....XpJZx.f.tw| +000000b0 a0 3a ec d8 b7 42 e3 a5 d4 62 |.:...B...b| >>> Flow 4 (server to client) -00000000 14 03 03 00 01 01 16 03 03 00 24 59 20 4d c2 17 |..........$Y M..| -00000010 8b 3c 9b 33 d9 f9 ef fb 80 18 1f 67 a7 58 12 89 |.<.3.......g.X..| -00000020 4e 73 0f 2d 7b e6 c4 a6 79 73 01 da 22 e8 54 17 |Ns.-{...ys..".T.| -00000030 03 03 00 21 36 ca 64 0f 4a 12 a5 50 3d 97 bb 39 |...!6.d.J..P=..9| -00000040 02 fc ed d1 82 6a 9a 2e 21 79 f6 e1 b3 cc 32 db |.....j..!y....2.| -00000050 0f 5d b3 fb a5 15 03 03 00 16 51 f4 be 57 7a df |.]........Q..Wz.| -00000060 f1 f2 bd b5 51 5e 45 80 be 0b 9a 0c d1 19 3c 79 |....Q^E.......>> Flow 1 (client to server) -00000000 16 03 01 00 70 01 00 00 6c 03 03 52 cc 57 59 2d |....p...l..R.WY-| -00000010 77 aa 75 35 fa ff 2a a2 bf 91 5e e3 7f 38 7d 7a |w.u5..*...^..8}z| -00000020 e3 93 d3 e8 8b 09 bb 06 c8 6d 91 00 00 04 00 2f |.........m...../| -00000030 00 ff 01 00 00 3f 00 00 00 10 00 0e 00 00 0b 73 |.....?.........s| -00000040 6e 69 74 65 73 74 2e 63 6f 6d 00 0d 00 22 00 20 |nitest.com...". | +00000000 16 03 01 00 6e 01 00 00 6a 03 03 be 99 22 5c d2 |....n...j...."\.| +00000010 02 c7 a6 be f3 33 7a d4 76 1f cf 1e 39 0b 25 7c |.....3z.v...9.%|| +00000020 32 70 e4 8c 49 a6 87 b9 c1 2f 6d 00 00 04 00 2f |2p..I..../m..../| +00000030 00 ff 01 00 00 3d 00 00 00 10 00 0e 00 00 0b 73 |.....=.........s| +00000040 6e 69 74 65 73 74 2e 63 6f 6d 00 0d 00 20 00 1e |nitest.com... ..| 00000050 06 01 06 02 06 03 05 01 05 02 05 03 04 01 04 02 |................| -00000060 04 03 03 01 03 02 03 03 02 01 02 02 02 03 01 01 |................| -00000070 00 0f 00 01 01 |.....| +00000060 04 03 03 01 03 02 03 03 02 01 02 02 02 03 00 0f |................| +00000070 00 01 01 |...| >>> Flow 2 (server to client) 00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......| 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| @@ -46,31 +46,19 @@ 00000230 2c 65 25 d6 52 b6 e3 18 45 bd cc 16 03 03 00 04 |,e%.R...E.......| 00000240 0e 00 00 00 |....| >>> Flow 3 (client to server) -00000000 16 03 03 00 86 10 00 00 82 00 80 0d f2 bf 75 a9 |..............u.| -00000010 aa db f3 25 55 d4 20 59 63 54 d1 70 82 f9 61 c5 |...%U. YcT.p..a.| -00000020 b7 ae 3f 75 71 75 9d c5 01 a1 ed b1 07 66 9f 3f |..?uqu.......f.?| -00000030 cf c6 e6 ad 44 03 fd 18 6f 53 24 ce 76 01 bd fe |....D...oS$.v...| -00000040 e2 51 f7 df 8a 23 3a 21 c4 00 15 ff d0 e0 ff c8 |.Q...#:!........| -00000050 8b 89 33 c6 8e e0 ce 97 ef b4 c6 f9 b0 ea 38 89 |..3...........8.| -00000060 79 98 34 9e f7 bc c6 fd d2 5d 56 84 5c d2 9a ce |y.4......]V.\...| -00000070 ae de 09 bc 24 25 fc 09 0c bc 0e 91 0d 6b 36 ae |....$%.......k6.| -00000080 ce 6b cd 14 ec b6 3c fa d6 df fc 14 03 03 00 01 |.k....<.........| -00000090 01 16 03 03 00 40 ad 21 13 2b 33 7a 4a 0d fb 0f |.....@.!.+3zJ...| -000000a0 eb d2 b6 85 29 1f 59 79 ba 86 53 5c 68 b4 c7 e3 |....).Yy..S\h...| -000000b0 8a 6c 5c 18 04 4d e4 76 19 30 ba 92 b4 79 8c 64 |.l\..M.v.0...y.d| -000000c0 00 a0 2e 13 96 45 9f e7 a9 e4 23 9e 9f 89 23 26 |.....E....#...#&| -000000d0 36 20 82 fc 75 fe |6 ..u.| +00000000 16 03 03 00 86 10 00 00 82 00 80 6b 03 31 ca a0 |...........k.1..| +00000010 62 a2 53 11 ce 13 d9 f6 e7 d4 ec 2e c3 0a 38 56 |b.S...........8V| +00000020 23 22 67 23 c8 8d 16 b4 3c 0b 26 9f 1c 2d 65 13 |#"g#....<.&..-e.| +00000030 c3 cb 65 69 b0 47 ff 87 e8 02 56 c4 77 8a 40 29 |..ei.G....V.w.@)| +00000040 82 62 8b 06 61 0a 1c b3 c7 29 b6 aa c9 96 37 18 |.b..a....)....7.| +00000050 d0 60 66 63 9b 62 4b 30 cc 03 9c 37 05 c6 32 98 |.`fc.bK0...7..2.| +00000060 cb a0 e2 e4 38 60 d4 93 99 9a fc 03 66 fb b6 ef |....8`......f...| +00000070 8a 1e bb ca 13 c5 d9 7a 7c 3b 50 dc d0 ad 00 b5 |.......z|;P.....| +00000080 2c dc 1a ef c4 5c af d3 4e cd e6 14 03 03 00 01 |,....\..N.......| +00000090 01 16 03 03 00 40 42 31 83 8a 2c 86 22 c5 df e5 |.....@B1..,."...| +000000a0 f2 0b f8 0c 2f 1e 82 f4 69 fe 1d bd 4c db f1 80 |..../...i...L...| +000000b0 68 30 b7 e3 60 76 b3 f1 52 ae d6 e7 b3 cb 4a e0 |h0..`v..R.....J.| +000000c0 27 0a c1 1a 72 ed 71 ab 0a fc 10 d9 5e 4d fd 10 |'...r.q.....^M..| +000000d0 04 92 39 78 be 23 |..9x.#| >>> Flow 4 (server to client) -00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |..........@.....| -00000010 00 00 00 00 00 00 00 00 00 00 00 b7 87 61 10 03 |.............a..| -00000020 b8 a4 42 d4 8b 49 bc 40 80 70 92 c8 25 b0 c6 7f |..B..I.@.p..%...| -00000030 b3 87 76 50 5a 59 b3 3c d8 3e 23 24 aa 1a f3 36 |..vPZY.<.>#$...6| -00000040 c9 2c 87 c1 22 d2 94 f8 2c fd ef 17 03 03 00 40 |.,.."...,......@| -00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| -00000060 e5 7f bd 3e ff 9f d4 1b 91 02 f8 69 6f 70 9d 51 |...>.......iop.Q| -00000070 a5 ec ef 5b 10 3f 4e 3f 44 e5 9a 39 68 7c 3a b9 |...[.?N?D..9h|:.| -00000080 69 38 31 ec 9c 45 bf 19 d1 5c 5e 2e 06 00 ca 19 |i81..E...\^.....| -00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........| -000000a0 00 00 00 00 00 63 5e 79 2c f2 05 dc 2b d7 5b ac |.....c^y,...+.[.| -000000b0 9d fc 75 94 03 16 ca 1f b2 75 58 2d f1 2f f1 1e |..u......uX-./..| -000000c0 d2 f6 84 8f 2e |.....| +00000000 15 03 03 00 02 02 14 |.......| diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-SNI-GetCertificate b/libgo/go/crypto/tls/testdata/Server-TLSv12-SNI-GetCertificate new file mode 100644 index 00000000000..40d3714a86d --- /dev/null +++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-SNI-GetCertificate @@ -0,0 +1,64 @@ +>>> Flow 1 (client to server) +00000000 16 03 01 00 6e 01 00 00 6a 03 03 23 de 75 da 8e |....n...j..#.u..| +00000010 0a 4b 7b e4 cb 34 14 83 be d1 6a 95 25 86 f8 91 |.K{..4....j.%...| +00000020 d8 bb ac 82 9e 19 d6 9f 52 26 f6 00 00 04 00 2f |........R&...../| +00000030 00 ff 01 00 00 3d 00 00 00 10 00 0e 00 00 0b 73 |.....=.........s| +00000040 6e 69 74 65 73 74 2e 63 6f 6d 00 0d 00 20 00 1e |nitest.com... ..| +00000050 06 01 06 02 06 03 05 01 05 02 05 03 04 01 04 02 |................| +00000060 04 03 03 01 03 02 03 03 02 01 02 02 02 03 00 0f |................| +00000070 00 01 01 |...| +>>> Flow 2 (server to client) +00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......| +00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2f 00 00 |............./..| +00000030 05 ff 01 00 01 00 16 03 03 02 00 0b 00 01 fc 00 |................| +00000040 01 f9 00 01 f6 30 82 01 f2 30 82 01 5d a0 03 02 |.....0...0..]...| +00000050 01 02 02 01 00 30 0b 06 09 2a 86 48 86 f7 0d 01 |.....0...*.H....| +00000060 01 05 30 28 31 10 30 0e 06 03 55 04 0a 13 07 41 |..0(1.0...U....A| +00000070 63 6d 65 20 43 6f 31 14 30 12 06 03 55 04 03 13 |cme Co1.0...U...| +00000080 0b 73 6e 69 74 65 73 74 2e 63 6f 6d 30 1e 17 0d |.snitest.com0...| +00000090 31 32 30 34 31 31 31 37 34 30 33 35 5a 17 0d 31 |120411174035Z..1| +000000a0 33 30 34 31 31 31 37 34 35 33 35 5a 30 28 31 10 |30411174535Z0(1.| +000000b0 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 6f |0...U....Acme Co| +000000c0 31 14 30 12 06 03 55 04 03 13 0b 73 6e 69 74 65 |1.0...U....snite| +000000d0 73 74 2e 63 6f 6d 30 81 9d 30 0b 06 09 2a 86 48 |st.com0..0...*.H| +000000e0 86 f7 0d 01 01 01 03 81 8d 00 30 81 89 02 81 81 |..........0.....| +000000f0 00 bb 79 d6 f5 17 b5 e5 bf 46 10 d0 dc 69 be e6 |..y......F...i..| +00000100 2b 07 43 5a d0 03 2d 8a 7a 43 85 b7 14 52 e7 a5 |+.CZ..-.zC...R..| +00000110 65 4c 2c 78 b8 23 8c b5 b4 82 e5 de 1f 95 3b 7e |eL,x.#........;~| +00000120 62 a5 2c a5 33 d6 fe 12 5c 7a 56 fc f5 06 bf fa |b.,.3...\zV.....| +00000130 58 7b 26 3f b5 cd 04 d3 d0 c9 21 96 4a c7 f4 54 |X{&?......!.J..T| +00000140 9f 5a bf ef 42 71 00 fe 18 99 07 7f 7e 88 7d 7d |.Z..Bq......~.}}| +00000150 f1 04 39 c4 a2 2e db 51 c9 7c e3 c0 4c 3b 32 66 |..9....Q.|..L;2f| +00000160 01 cf af b1 1d b8 71 9a 1d db db 89 6b ae da 2d |......q.....k..-| +00000170 79 02 03 01 00 01 a3 32 30 30 30 0e 06 03 55 1d |y......2000...U.| +00000180 0f 01 01 ff 04 04 03 02 00 a0 30 0d 06 03 55 1d |..........0...U.| +00000190 0e 04 06 04 04 01 02 03 04 30 0f 06 03 55 1d 23 |.........0...U.#| +000001a0 04 08 30 06 80 04 01 02 03 04 30 0b 06 09 2a 86 |..0.......0...*.| +000001b0 48 86 f7 0d 01 01 05 03 81 81 00 89 c6 45 5f 1c |H............E_.| +000001c0 1f 5e f8 eb 1a b1 74 ee 24 39 05 9f 5c 42 59 bb |.^....t.$9..\BY.| +000001d0 1a 8d 86 cd b1 d0 56 f5 6a 71 7d a4 0e 95 ab 90 |......V.jq}.....| +000001e0 f5 9e 8d ea f6 27 c1 57 99 50 94 db 08 02 26 6e |.....'.W.P....&n| +000001f0 b3 4f c6 84 2d ea 8a 4b 68 d9 c1 38 91 03 ab 84 |.O..-..Kh..8....| +00000200 fb 9e 1f 85 d9 b5 d2 3f f2 31 2c 86 70 fb b5 40 |.......?.1,.p..@| +00000210 14 82 45 a4 eb af e2 64 d9 0c 8a 4c f4 f8 5b 0f |..E....d...L..[.| +00000220 ac 12 ac 2f c4 a3 15 4b ad 52 46 28 68 af 96 c6 |.../...K.RF(h...| +00000230 2c 65 25 d6 52 b6 e3 18 45 bd cc 16 03 03 00 04 |,e%.R...E.......| +00000240 0e 00 00 00 |....| +>>> Flow 3 (client to server) +00000000 16 03 03 00 86 10 00 00 82 00 80 a2 99 61 c5 90 |.............a..| +00000010 47 1a e7 47 56 51 59 e4 6e ab 82 01 18 78 ee 95 |G..GVQY.n....x..| +00000020 b8 e2 c7 c7 f9 64 98 dd 84 8d 96 d9 2d 08 62 1e |.....d......-.b.| +00000030 4f 29 83 b6 93 68 77 7a 14 1b f0 b3 1a 67 7b 7a |O)...hwz.....g{z| +00000040 f9 54 f3 7e 6d eb b6 7a c9 37 70 6a 83 68 f2 15 |.T.~m..z.7pj.h..| +00000050 81 07 30 6e b8 fa 19 0e 46 dc d6 9a 4a 8e 8d f1 |..0n....F...J...| +00000060 05 78 60 75 d4 00 d9 1e 11 5f 16 f7 bc 9f e8 8a |.x`u....._......| +00000070 c4 3e bd d9 1a b8 67 50 00 be 5f 43 ee 07 ad be |.>....gP.._C....| +00000080 f5 85 67 fc 8f c6 87 47 6d 6e b2 14 03 03 00 01 |..g....Gmn......| +00000090 01 16 03 03 00 40 91 7d 7b 05 99 48 05 70 a9 67 |.....@.}{..H.p.g| +000000a0 e9 7a 0a c3 6b bf b0 ad 68 65 17 fb 18 bf 8d bd |.z..k...he......| +000000b0 e1 4b 12 bf ea 82 9d a6 1e 3a c8 77 65 32 bd 5e |.K.......:.we2.^| +000000c0 c4 46 da e7 e1 ac 09 fe 4a ac bc 57 6a 17 7d dc |.F......J..Wj.}.| +000000d0 fe 9c d0 d0 6e fc |....n.| +>>> Flow 4 (server to client) +00000000 15 03 03 00 02 02 14 |.......| diff --git a/libgo/go/crypto/tls/testdata/Server-TLSv12-SNI-GetCertificateNotFound b/libgo/go/crypto/tls/testdata/Server-TLSv12-SNI-GetCertificateNotFound new file mode 100644 index 00000000000..904f69ecacb --- /dev/null +++ b/libgo/go/crypto/tls/testdata/Server-TLSv12-SNI-GetCertificateNotFound @@ -0,0 +1,64 @@ +>>> Flow 1 (client to server) +00000000 16 03 01 00 6e 01 00 00 6a 03 03 27 db e3 e8 f4 |....n...j..'....| +00000010 48 1d 45 d5 20 64 97 b2 20 a6 67 94 7a 1e 87 12 |H.E. d.. .g.z...| +00000020 25 b1 53 94 27 78 ed ae 58 2f 1b 00 00 04 00 2f |%.S.'x..X/...../| +00000030 00 ff 01 00 00 3d 00 00 00 10 00 0e 00 00 0b 73 |.....=.........s| +00000040 6e 69 74 65 73 74 2e 63 6f 6d 00 0d 00 20 00 1e |nitest.com... ..| +00000050 06 01 06 02 06 03 05 01 05 02 05 03 04 01 04 02 |................| +00000060 04 03 03 01 03 02 03 03 02 01 02 02 02 03 00 0f |................| +00000070 00 01 01 |...| +>>> Flow 2 (server to client) +00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......| +00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 2f 00 00 |............./..| +00000030 05 ff 01 00 01 00 16 03 03 02 00 0b 00 01 fc 00 |................| +00000040 01 f9 00 01 f6 30 82 01 f2 30 82 01 5d a0 03 02 |.....0...0..]...| +00000050 01 02 02 01 00 30 0b 06 09 2a 86 48 86 f7 0d 01 |.....0...*.H....| +00000060 01 05 30 28 31 10 30 0e 06 03 55 04 0a 13 07 41 |..0(1.0...U....A| +00000070 63 6d 65 20 43 6f 31 14 30 12 06 03 55 04 03 13 |cme Co1.0...U...| +00000080 0b 73 6e 69 74 65 73 74 2e 63 6f 6d 30 1e 17 0d |.snitest.com0...| +00000090 31 32 30 34 31 31 31 37 34 30 33 35 5a 17 0d 31 |120411174035Z..1| +000000a0 33 30 34 31 31 31 37 34 35 33 35 5a 30 28 31 10 |30411174535Z0(1.| +000000b0 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 6f |0...U....Acme Co| +000000c0 31 14 30 12 06 03 55 04 03 13 0b 73 6e 69 74 65 |1.0...U....snite| +000000d0 73 74 2e 63 6f 6d 30 81 9d 30 0b 06 09 2a 86 48 |st.com0..0...*.H| +000000e0 86 f7 0d 01 01 01 03 81 8d 00 30 81 89 02 81 81 |..........0.....| +000000f0 00 bb 79 d6 f5 17 b5 e5 bf 46 10 d0 dc 69 be e6 |..y......F...i..| +00000100 2b 07 43 5a d0 03 2d 8a 7a 43 85 b7 14 52 e7 a5 |+.CZ..-.zC...R..| +00000110 65 4c 2c 78 b8 23 8c b5 b4 82 e5 de 1f 95 3b 7e |eL,x.#........;~| +00000120 62 a5 2c a5 33 d6 fe 12 5c 7a 56 fc f5 06 bf fa |b.,.3...\zV.....| +00000130 58 7b 26 3f b5 cd 04 d3 d0 c9 21 96 4a c7 f4 54 |X{&?......!.J..T| +00000140 9f 5a bf ef 42 71 00 fe 18 99 07 7f 7e 88 7d 7d |.Z..Bq......~.}}| +00000150 f1 04 39 c4 a2 2e db 51 c9 7c e3 c0 4c 3b 32 66 |..9....Q.|..L;2f| +00000160 01 cf af b1 1d b8 71 9a 1d db db 89 6b ae da 2d |......q.....k..-| +00000170 79 02 03 01 00 01 a3 32 30 30 30 0e 06 03 55 1d |y......2000...U.| +00000180 0f 01 01 ff 04 04 03 02 00 a0 30 0d 06 03 55 1d |..........0...U.| +00000190 0e 04 06 04 04 01 02 03 04 30 0f 06 03 55 1d 23 |.........0...U.#| +000001a0 04 08 30 06 80 04 01 02 03 04 30 0b 06 09 2a 86 |..0.......0...*.| +000001b0 48 86 f7 0d 01 01 05 03 81 81 00 89 c6 45 5f 1c |H............E_.| +000001c0 1f 5e f8 eb 1a b1 74 ee 24 39 05 9f 5c 42 59 bb |.^....t.$9..\BY.| +000001d0 1a 8d 86 cd b1 d0 56 f5 6a 71 7d a4 0e 95 ab 90 |......V.jq}.....| +000001e0 f5 9e 8d ea f6 27 c1 57 99 50 94 db 08 02 26 6e |.....'.W.P....&n| +000001f0 b3 4f c6 84 2d ea 8a 4b 68 d9 c1 38 91 03 ab 84 |.O..-..Kh..8....| +00000200 fb 9e 1f 85 d9 b5 d2 3f f2 31 2c 86 70 fb b5 40 |.......?.1,.p..@| +00000210 14 82 45 a4 eb af e2 64 d9 0c 8a 4c f4 f8 5b 0f |..E....d...L..[.| +00000220 ac 12 ac 2f c4 a3 15 4b ad 52 46 28 68 af 96 c6 |.../...K.RF(h...| +00000230 2c 65 25 d6 52 b6 e3 18 45 bd cc 16 03 03 00 04 |,e%.R...E.......| +00000240 0e 00 00 00 |....| +>>> Flow 3 (client to server) +00000000 16 03 03 00 86 10 00 00 82 00 80 72 23 e9 89 70 |...........r#..p| +00000010 97 02 08 58 0d 28 96 5b 19 73 dd 4f 6e 4c 11 dd |...X.(.[.s.OnL..| +00000020 cb 56 14 f4 8f c8 e5 84 03 f5 7e f0 a4 08 44 8c |.V........~...D.| +00000030 22 74 01 5c e4 9d e0 38 53 90 66 e3 df bb 09 a8 |"t.\...8S.f.....| +00000040 11 97 0a 44 01 d2 70 85 14 a1 9a 2f 02 34 40 6d |...D..p..../.4@m| +00000050 66 80 72 9a 97 98 5c 91 0e dc 42 ac c2 90 2f 30 |f.r...\...B.../0| +00000060 ca 39 25 94 da 6e b6 5f 94 a9 94 66 7f 32 6a bb |.9%..n._...f.2j.| +00000070 5d 43 20 c3 74 f7 52 29 1f d5 62 6b a4 a1 8c 25 |]C .t.R)..bk...%| +00000080 46 69 22 a5 68 54 f4 68 30 e2 52 14 03 03 00 01 |Fi".hT.h0.R.....| +00000090 01 16 03 03 00 40 51 d2 78 64 e3 59 ee b7 5f 95 |.....@Q.xd.Y.._.| +000000a0 4c 49 7f 0d 49 3f 55 71 8c 3b 24 e3 81 22 4a d1 |LI..I?Uq.;$.."J.| +000000b0 ab 84 4e df 02 9d 56 ea 2a 14 71 e1 dc 1d 5c 1d |..N...V.*.q...\.| +000000c0 54 ce cb 58 f6 4d e7 73 44 0d 99 95 a5 2d 7c 2f |T..X.M.sD....-|/| +000000d0 15 f5 8f fd 97 40 |.....@| +>>> Flow 4 (server to client) +00000000 15 03 03 00 02 02 14 |.......| diff --git a/libgo/go/crypto/tls/ticket.go b/libgo/go/crypto/tls/ticket.go index 0923027c701..7be50ce68c9 100644 --- a/libgo/go/crypto/tls/ticket.go +++ b/libgo/go/crypto/tls/ticket.go @@ -22,6 +22,9 @@ type sessionState struct { cipherSuite uint16 masterSecret []byte certificates [][]byte + // usedOldKey is true if the ticket from which this session came from + // was encrypted with an older key and thus should be refreshed. + usedOldKey bool } func (s *sessionState) equal(i interface{}) bool { @@ -132,20 +135,23 @@ func (s *sessionState) unmarshal(data []byte) bool { func (c *Conn) encryptTicket(state *sessionState) ([]byte, error) { serialized := state.marshal() - encrypted := make([]byte, aes.BlockSize+len(serialized)+sha256.Size) - iv := encrypted[:aes.BlockSize] + encrypted := make([]byte, ticketKeyNameLen+aes.BlockSize+len(serialized)+sha256.Size) + keyName := encrypted[:ticketKeyNameLen] + iv := encrypted[ticketKeyNameLen : ticketKeyNameLen+aes.BlockSize] macBytes := encrypted[len(encrypted)-sha256.Size:] if _, err := io.ReadFull(c.config.rand(), iv); err != nil { return nil, err } - block, err := aes.NewCipher(c.config.SessionTicketKey[:16]) + key := c.config.ticketKeys()[0] + copy(keyName, key.keyName[:]) + block, err := aes.NewCipher(key.aesKey[:]) if err != nil { return nil, errors.New("tls: failed to create cipher while encrypting ticket: " + err.Error()) } - cipher.NewCTR(block, iv).XORKeyStream(encrypted[aes.BlockSize:], serialized) + cipher.NewCTR(block, iv).XORKeyStream(encrypted[ticketKeyNameLen+aes.BlockSize:], serialized) - mac := hmac.New(sha256.New, c.config.SessionTicketKey[16:32]) + mac := hmac.New(sha256.New, key.hmacKey[:]) mac.Write(encrypted[:len(encrypted)-sha256.Size]) mac.Sum(macBytes[:0]) @@ -154,14 +160,29 @@ func (c *Conn) encryptTicket(state *sessionState) ([]byte, error) { func (c *Conn) decryptTicket(encrypted []byte) (*sessionState, bool) { if c.config.SessionTicketsDisabled || - len(encrypted) < aes.BlockSize+sha256.Size { + len(encrypted) < ticketKeyNameLen+aes.BlockSize+sha256.Size { return nil, false } - iv := encrypted[:aes.BlockSize] + keyName := encrypted[:ticketKeyNameLen] + iv := encrypted[ticketKeyNameLen : ticketKeyNameLen+aes.BlockSize] macBytes := encrypted[len(encrypted)-sha256.Size:] - mac := hmac.New(sha256.New, c.config.SessionTicketKey[16:32]) + keys := c.config.ticketKeys() + keyIndex := -1 + for i, candidateKey := range keys { + if bytes.Equal(keyName, candidateKey.keyName[:]) { + keyIndex = i + break + } + } + + if keyIndex == -1 { + return nil, false + } + key := &keys[keyIndex] + + mac := hmac.New(sha256.New, key.hmacKey[:]) mac.Write(encrypted[:len(encrypted)-sha256.Size]) expected := mac.Sum(nil) @@ -169,15 +190,15 @@ func (c *Conn) decryptTicket(encrypted []byte) (*sessionState, bool) { return nil, false } - block, err := aes.NewCipher(c.config.SessionTicketKey[:16]) + block, err := aes.NewCipher(key.aesKey[:]) if err != nil { return nil, false } - ciphertext := encrypted[aes.BlockSize : len(encrypted)-sha256.Size] + ciphertext := encrypted[ticketKeyNameLen+aes.BlockSize : len(encrypted)-sha256.Size] plaintext := ciphertext cipher.NewCTR(block, iv).XORKeyStream(plaintext, ciphertext) - state := new(sessionState) + state := &sessionState{usedOldKey: keyIndex > 0} ok := state.unmarshal(plaintext) return state, ok } diff --git a/libgo/go/crypto/tls/tls.go b/libgo/go/crypto/tls/tls.go index d50e1202924..0b1c3778ad4 100644 --- a/libgo/go/crypto/tls/tls.go +++ b/libgo/go/crypto/tls/tls.go @@ -167,22 +167,24 @@ func Dial(network, addr string, config *Config) (*Conn, error) { // LoadX509KeyPair reads and parses a public/private key pair from a pair of // files. The files must contain PEM encoded data. -func LoadX509KeyPair(certFile, keyFile string) (cert Certificate, err error) { +func LoadX509KeyPair(certFile, keyFile string) (Certificate, error) { certPEMBlock, err := ioutil.ReadFile(certFile) if err != nil { - return + return Certificate{}, err } keyPEMBlock, err := ioutil.ReadFile(keyFile) if err != nil { - return + return Certificate{}, err } return X509KeyPair(certPEMBlock, keyPEMBlock) } // X509KeyPair parses a public/private key pair from a pair of // PEM encoded data. -func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (cert Certificate, err error) { +func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (Certificate, error) { + var cert Certificate var certDERBlock *pem.Block + fail := func(err error) (Certificate, error) { return Certificate{}, err } for { certDERBlock, certPEMBlock = pem.Decode(certPEMBlock) if certDERBlock == nil { @@ -194,62 +196,56 @@ func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (cert Certificate, err error) } if len(cert.Certificate) == 0 { - err = errors.New("crypto/tls: failed to parse certificate PEM data") - return + return fail(errors.New("crypto/tls: failed to parse certificate PEM data")) } var keyDERBlock *pem.Block for { keyDERBlock, keyPEMBlock = pem.Decode(keyPEMBlock) if keyDERBlock == nil { - err = errors.New("crypto/tls: failed to parse key PEM data") - return + return fail(errors.New("crypto/tls: failed to parse key PEM data")) } if keyDERBlock.Type == "PRIVATE KEY" || strings.HasSuffix(keyDERBlock.Type, " PRIVATE KEY") { break } } + var err error cert.PrivateKey, err = parsePrivateKey(keyDERBlock.Bytes) if err != nil { - return + return fail(err) } // We don't need to parse the public key for TLS, but we so do anyway // to check that it looks sane and matches the private key. x509Cert, err := x509.ParseCertificate(cert.Certificate[0]) if err != nil { - return + return fail(err) } switch pub := x509Cert.PublicKey.(type) { case *rsa.PublicKey: priv, ok := cert.PrivateKey.(*rsa.PrivateKey) if !ok { - err = errors.New("crypto/tls: private key type does not match public key type") - return + return fail(errors.New("crypto/tls: private key type does not match public key type")) } if pub.N.Cmp(priv.N) != 0 { - err = errors.New("crypto/tls: private key does not match public key") - return + return fail(errors.New("crypto/tls: private key does not match public key")) } case *ecdsa.PublicKey: priv, ok := cert.PrivateKey.(*ecdsa.PrivateKey) if !ok { - err = errors.New("crypto/tls: private key type does not match public key type") - return + return fail(errors.New("crypto/tls: private key type does not match public key type")) } if pub.X.Cmp(priv.X) != 0 || pub.Y.Cmp(priv.Y) != 0 { - err = errors.New("crypto/tls: private key does not match public key") - return + return fail(errors.New("crypto/tls: private key does not match public key")) } default: - err = errors.New("crypto/tls: unknown public key algorithm") - return + return fail(errors.New("crypto/tls: unknown public key algorithm")) } - return + return cert, nil } // Attempt to parse the given private key DER block. OpenSSL 0.9.8 generates diff --git a/libgo/go/crypto/tls/tls_test.go b/libgo/go/crypto/tls/tls_test.go index e82579eee9f..c45c10378d7 100644 --- a/libgo/go/crypto/tls/tls_test.go +++ b/libgo/go/crypto/tls/tls_test.go @@ -7,6 +7,7 @@ package tls import ( "bytes" "fmt" + "internal/testenv" "io" "net" "strings" @@ -40,7 +41,7 @@ D2lWusoe2/nEqfDVVWGWlyJ7yOmqaVm/iNUN9B2N2g== ` // keyPEM is the same as rsaKeyPEM, but declares itself as just -// "PRIVATE KEY", not "RSA PRIVATE KEY". http://golang.org/issue/4477 +// "PRIVATE KEY", not "RSA PRIVATE KEY". https://golang.org/issue/4477 var keyPEM = `-----BEGIN PRIVATE KEY----- MIIBOwIBAAJBANLJhPHhITqQbPklG3ibCVxwGMRfp/v4XqhfdQHdcVfHap6NQ5Wo k/4xIA+ui35/MmNartNuC+BdZ1tMuVCPFZcCAwEAAQJAEJ2N+zsR0Xn8/Q6twa4G @@ -280,3 +281,54 @@ func TestTLSUniqueMatches(t *testing.T) { t.Error("client and server channel bindings differ when session resumption is used") } } + +func TestVerifyHostname(t *testing.T) { + testenv.MustHaveExternalNetwork(t) + + c, err := Dial("tcp", "www.google.com:https", nil) + if err != nil { + t.Fatal(err) + } + if err := c.VerifyHostname("www.google.com"); err != nil { + t.Fatalf("verify www.google.com: %v", err) + } + if err := c.VerifyHostname("www.yahoo.com"); err == nil { + t.Fatalf("verify www.yahoo.com succeeded") + } + + c, err = Dial("tcp", "www.google.com:https", &Config{InsecureSkipVerify: true}) + if err != nil { + t.Fatal(err) + } + if err := c.VerifyHostname("www.google.com"); err == nil { + t.Fatalf("verify www.google.com succeeded with InsecureSkipVerify=true") + } + if err := c.VerifyHostname("www.yahoo.com"); err == nil { + t.Fatalf("verify www.google.com succeeded with InsecureSkipVerify=true") + } +} + +func TestVerifyHostnameResumed(t *testing.T) { + testenv.MustHaveExternalNetwork(t) + + config := &Config{ + ClientSessionCache: NewLRUClientSessionCache(32), + } + for i := 0; i < 2; i++ { + c, err := Dial("tcp", "www.google.com:https", config) + if err != nil { + t.Fatalf("Dial #%d: %v", i, err) + } + cs := c.ConnectionState() + if i > 0 && !cs.DidResume { + t.Fatalf("Subsequent connection unexpectedly didn't resume") + } + if cs.VerifiedChains == nil { + t.Fatalf("Dial #%d: cs.VerifiedChains == nil", i) + } + if err := c.VerifyHostname("www.google.com"); err != nil { + t.Fatalf("verify www.google.com #%d: %v", i, err) + } + c.Close() + } +} diff --git a/libgo/go/crypto/x509/cert_pool.go b/libgo/go/crypto/x509/cert_pool.go index babe94d41c5..2362e84688d 100644 --- a/libgo/go/crypto/x509/cert_pool.go +++ b/libgo/go/crypto/x509/cert_pool.go @@ -77,7 +77,7 @@ func (s *CertPool) AddCert(cert *Certificate) { } // AppendCertsFromPEM attempts to parse a series of PEM encoded certificates. -// It appends any certificates found to s and returns true if any certificates +// It appends any certificates found to s and reports whether any certificates // were successfully parsed. // // On many Linux systems, /etc/ssl/cert.pem will contain the system wide set diff --git a/libgo/go/crypto/x509/pem_decrypt.go b/libgo/go/crypto/x509/pem_decrypt.go index 194c81bf688..49ceadb4366 100644 --- a/libgo/go/crypto/x509/pem_decrypt.go +++ b/libgo/go/crypto/x509/pem_decrypt.go @@ -108,7 +108,10 @@ var IncorrectPasswordError = errors.New("x509: decryption password incorrect") // encrypt it and returns a slice of decrypted DER encoded bytes. It inspects // the DEK-Info header to determine the algorithm used for decryption. If no // DEK-Info header is present, an error is returned. If an incorrect password -// is detected an IncorrectPasswordError is returned. +// is detected an IncorrectPasswordError is returned. Because of deficiencies +// in the encrypted-PEM format, it's not always possible to detect an incorrect +// password. In these cases no error will be returned but the decrypted DER +// bytes will be random noise. func DecryptPEMBlock(b *pem.Block, password []byte) ([]byte, error) { dek, ok := b.Headers["DEK-Info"] if !ok { @@ -141,6 +144,10 @@ func DecryptPEMBlock(b *pem.Block, password []byte) ([]byte, error) { return nil, err } + if len(b.Bytes)%block.BlockSize() != 0 { + return nil, errors.New("x509: encrypted PEM data is not a multiple of the block size") + } + data := make([]byte, len(b.Bytes)) dec := cipher.NewCBCDecrypter(block, iv) dec.CryptBlocks(data, b.Bytes) diff --git a/libgo/go/crypto/x509/pem_decrypt_test.go b/libgo/go/crypto/x509/pem_decrypt_test.go index 13e4700bdda..685d5ee1569 100644 --- a/libgo/go/crypto/x509/pem_decrypt_test.go +++ b/libgo/go/crypto/x509/pem_decrypt_test.go @@ -9,6 +9,7 @@ import ( "crypto/rand" "encoding/base64" "encoding/pem" + "strings" "testing" ) @@ -221,3 +222,26 @@ AgkA8SEfu/2i3g0CCQDGNlXbBHX7kQIIK3Ww5o0cYbECCQDCimPb0dYGsQIIeQ7A jryIst8=`, }, } + +const incompleteBlockPEM = ` +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-128-CBC,74611ABC2571AF11B1BF9B69E62C89E7 + +6L8yXK2MTQUWBk4ZD6OvCiYp+mXyR1594TQ1K38MxGvDw5pwcDME2Lek8RrR5fd40P2XsL2Z4KKt +ai+OP1BZUetfK6AW4MiqB2FDyIdOAJ8XeWuZy21Wtsh8wPD6yYOFM/w7WZL8weX3Y0TSeG/T +-----END RSA PRIVATE KEY-----` + +func TestIncompleteBlock(t *testing.T) { + // incompleteBlockPEM contains ciphertext that is not a multiple of the + // block size. This previously panicked. See #11215. + block, _ := pem.Decode([]byte(incompleteBlockPEM)) + _, err := DecryptPEMBlock(block, []byte("foo")) + if err == nil { + t.Fatal("Bad PEM data decrypted successfully") + } + const expectedSubstr = "block size" + if e := err.Error(); !strings.Contains(e, expectedSubstr) { + t.Fatalf("Expected error containing %q but got: %q", expectedSubstr, e) + } +} diff --git a/libgo/go/crypto/x509/pkix/pkix.go b/libgo/go/crypto/x509/pkix/pkix.go index 8768b785908..5add4e5d3e0 100644 --- a/libgo/go/crypto/x509/pkix/pkix.go +++ b/libgo/go/crypto/x509/pkix/pkix.go @@ -46,14 +46,17 @@ type Extension struct { } // Name represents an X.509 distinguished name. This only includes the common -// elements of a DN. Additional elements in the name are ignored. +// elements of a DN. When parsing, all elements are stored in Names and +// non-standard elements can be extracted from there. When marshaling, elements +// in ExtraNames are appended and override other values with the same OID. type Name struct { Country, Organization, OrganizationalUnit []string Locality, Province []string StreetAddress, PostalCode []string SerialNumber, CommonName string - Names []AttributeTypeAndValue + Names []AttributeTypeAndValue + ExtraNames []AttributeTypeAndValue } func (n *Name) FillFromRDNSequence(rdns *RDNSequence) { @@ -110,8 +113,8 @@ var ( // and returns the new value. The relativeDistinguishedNameSET contains an // attributeTypeAndValue for each of the given values. See RFC 5280, A.1, and // search for AttributeTypeAndValue. -func appendRDNs(in RDNSequence, values []string, oid asn1.ObjectIdentifier) RDNSequence { - if len(values) == 0 { +func (n Name) appendRDNs(in RDNSequence, values []string, oid asn1.ObjectIdentifier) RDNSequence { + if len(values) == 0 || oidInAttributeTypeAndValue(oid, n.ExtraNames) { return in } @@ -125,23 +128,37 @@ func appendRDNs(in RDNSequence, values []string, oid asn1.ObjectIdentifier) RDNS } func (n Name) ToRDNSequence() (ret RDNSequence) { - ret = appendRDNs(ret, n.Country, oidCountry) - ret = appendRDNs(ret, n.Organization, oidOrganization) - ret = appendRDNs(ret, n.OrganizationalUnit, oidOrganizationalUnit) - ret = appendRDNs(ret, n.Locality, oidLocality) - ret = appendRDNs(ret, n.Province, oidProvince) - ret = appendRDNs(ret, n.StreetAddress, oidStreetAddress) - ret = appendRDNs(ret, n.PostalCode, oidPostalCode) + ret = n.appendRDNs(ret, n.Country, oidCountry) + ret = n.appendRDNs(ret, n.Organization, oidOrganization) + ret = n.appendRDNs(ret, n.OrganizationalUnit, oidOrganizationalUnit) + ret = n.appendRDNs(ret, n.Locality, oidLocality) + ret = n.appendRDNs(ret, n.Province, oidProvince) + ret = n.appendRDNs(ret, n.StreetAddress, oidStreetAddress) + ret = n.appendRDNs(ret, n.PostalCode, oidPostalCode) if len(n.CommonName) > 0 { - ret = appendRDNs(ret, []string{n.CommonName}, oidCommonName) + ret = n.appendRDNs(ret, []string{n.CommonName}, oidCommonName) } if len(n.SerialNumber) > 0 { - ret = appendRDNs(ret, []string{n.SerialNumber}, oidSerialNumber) + ret = n.appendRDNs(ret, []string{n.SerialNumber}, oidSerialNumber) + } + for _, atv := range n.ExtraNames { + ret = append(ret, []AttributeTypeAndValue{atv}) } return ret } +// oidInAttributeTypeAndValue returns whether a type with the given OID exists +// in atv. +func oidInAttributeTypeAndValue(oid asn1.ObjectIdentifier, atv []AttributeTypeAndValue) bool { + for _, a := range atv { + if a.Type.Equal(oid) { + return true + } + } + return false +} + // CertificateList represents the ASN.1 structure of the same name. See RFC // 5280, section 5.1. Use Certificate.CheckCRLSignature to verify the // signature. @@ -160,7 +177,7 @@ func (certList *CertificateList) HasExpired(now time.Time) bool { // 5280, section 5.1. type TBSCertificateList struct { Raw asn1.RawContent - Version int `asn1:"optional,default:2"` + Version int `asn1:"optional,default:1"` Signature AlgorithmIdentifier Issuer RDNSequence ThisUpdate time.Time diff --git a/libgo/go/crypto/x509/root_bsd.go b/libgo/go/crypto/x509/root_bsd.go new file mode 100644 index 00000000000..93172837368 --- /dev/null +++ b/libgo/go/crypto/x509/root_bsd.go @@ -0,0 +1,14 @@ +// Copyright 2015 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 dragonfly freebsd netbsd openbsd + +package x509 + +// Possible certificate files; stop after finding one. +var certFiles = []string{ + "/usr/local/share/certs/ca-root-nss.crt", // FreeBSD/DragonFly + "/etc/ssl/cert.pem", // OpenBSD + "/etc/openssl/certs/ca-certificates.crt", // NetBSD +} diff --git a/libgo/go/crypto/x509/root_cgo_darwin.go b/libgo/go/crypto/x509/root_cgo_darwin.go index bdcc2c1708a..bf4a5cdfeee 100644 --- a/libgo/go/crypto/x509/root_cgo_darwin.go +++ b/libgo/go/crypto/x509/root_cgo_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. -// +build cgo +// +build cgo,!arm,!arm64,!ios package x509 diff --git a/libgo/go/crypto/x509/root_darwin.go b/libgo/go/crypto/x509/root_darwin.go index 2a61d36eaea..78de56c2215 100644 --- a/libgo/go/crypto/x509/root_darwin.go +++ b/libgo/go/crypto/x509/root_darwin.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +//go:generate go run root_darwin_arm_gen.go -output root_darwin_armx.go + package x509 import "os/exec" diff --git a/libgo/go/crypto/x509/root_darwin_arm_gen.go b/libgo/go/crypto/x509/root_darwin_arm_gen.go new file mode 100644 index 00000000000..5817158c33b --- /dev/null +++ b/libgo/go/crypto/x509/root_darwin_arm_gen.go @@ -0,0 +1,191 @@ +// Copyright 2015 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 + +// Generates root_darwin_armx.go. +// +// As of iOS 8, there is no API for querying the system trusted X.509 root +// certificates. We could use SecTrustEvaluate to verify that a trust chain +// exists for a certificate, but the x509 API requires returning the entire +// chain. +// +// Apple publishes the list of trusted root certificates for iOS on +// support.apple.com. So we parse the list and extract the certificates from +// an OS X machine and embed them into the x509 package. +package main + +import ( + "bytes" + "crypto/x509" + "encoding/pem" + "flag" + "fmt" + "go/format" + "io/ioutil" + "log" + "math/big" + "net/http" + "os/exec" + "strings" +) + +var output = flag.String("output", "root_darwin_armx.go", "file name to write") + +func main() { + certs, err := selectCerts() + if err != nil { + log.Fatal(err) + } + + buf := new(bytes.Buffer) + + fmt.Fprintf(buf, "// Created by root_darwin_arm_gen --output %s; DO NOT EDIT\n", *output) + fmt.Fprintf(buf, "%s", header) + + fmt.Fprintf(buf, "const systemRootsPEM = `\n") + for _, cert := range certs { + b := &pem.Block{ + Type: "CERTIFICATE", + Bytes: cert.Raw, + } + if err := pem.Encode(buf, b); err != nil { + log.Fatal(err) + } + } + fmt.Fprintf(buf, "`") + + source, err := format.Source(buf.Bytes()) + if err != nil { + log.Fatal("source format error:", err) + } + if err := ioutil.WriteFile(*output, source, 0644); err != nil { + log.Fatal(err) + } +} + +func selectCerts() ([]*x509.Certificate, error) { + ids, err := fetchCertIDs() + if err != nil { + return nil, err + } + + scerts, err := sysCerts() + if err != nil { + return nil, err + } + + var certs []*x509.Certificate + for _, id := range ids { + sn, ok := big.NewInt(0).SetString(id.serialNumber, 0) // 0x prefix selects hex + if !ok { + return nil, fmt.Errorf("invalid serial number: %q", id.serialNumber) + } + ski, ok := big.NewInt(0).SetString(id.subjectKeyID, 0) + if !ok { + return nil, fmt.Errorf("invalid Subject Key ID: %q", id.subjectKeyID) + } + + for _, cert := range scerts { + if sn.Cmp(cert.SerialNumber) != 0 { + continue + } + cski := big.NewInt(0).SetBytes(cert.SubjectKeyId) + if ski.Cmp(cski) != 0 { + continue + } + certs = append(certs, cert) + break + } + } + return certs, nil +} + +func sysCerts() (certs []*x509.Certificate, err error) { + cmd := exec.Command("/usr/bin/security", "find-certificate", "-a", "-p", "/System/Library/Keychains/SystemRootCertificates.keychain") + data, err := cmd.Output() + if err != nil { + return nil, err + } + for len(data) > 0 { + var block *pem.Block + block, data = pem.Decode(data) + if block == nil { + break + } + if block.Type != "CERTIFICATE" || len(block.Headers) != 0 { + continue + } + + cert, err := x509.ParseCertificate(block.Bytes) + if err != nil { + continue + } + certs = append(certs, cert) + } + return certs, nil +} + +type certID struct { + serialNumber string + subjectKeyID string +} + +// fetchCertIDs fetches IDs of iOS X509 certificates from apple.com. +func fetchCertIDs() ([]certID, error) { + resp, err := http.Get("https://support.apple.com/en-us/HT204132") + if err != nil { + return nil, err + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + text := string(body) + text = text[strings.Index(text, "
")] + + lines := strings.Split(text, "\n") + var ids []certID + var id certID + for i, ln := range lines { + if i == len(lines)-1 { + break + } + const sn = "Serial Number:" + if ln == sn { + id.serialNumber = "0x" + strings.Replace(strings.TrimSpace(lines[i+1]), ":", "", -1) + continue + } + if strings.HasPrefix(ln, sn) { + // extract hex value from parentheses. + id.serialNumber = ln[strings.Index(ln, "(")+1 : len(ln)-1] + continue + } + if strings.TrimSpace(ln) == "X509v3 Subject Key Identifier:" { + id.subjectKeyID = "0x" + strings.Replace(strings.TrimSpace(lines[i+1]), ":", "", -1) + ids = append(ids, id) + id = certID{} + } + } + return ids, nil +} + +const header = ` +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build cgo +// +build darwin +// +build arm arm64 + +package x509 + +func initSystemRoots() { + systemRoots = NewCertPool() + systemRoots.AppendCertsFromPEM([]byte(systemRootsPEM)) +} +` diff --git a/libgo/go/crypto/x509/root_darwin_armx.go b/libgo/go/crypto/x509/root_darwin_armx.go new file mode 100644 index 00000000000..37675b48a39 --- /dev/null +++ b/libgo/go/crypto/x509/root_darwin_armx.go @@ -0,0 +1,4907 @@ +// Created by root_darwin_arm_gen --output root_darwin_armx.go; DO NOT EDIT + +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build cgo +// +build darwin +// +build arm arm64 ios + +package x509 + +func initSystemRoots() { + systemRoots = NewCertPool() + systemRoots.AppendCertsFromPEM([]byte(systemRootsPEM)) +} + +const systemRootsPEM = ` +-----BEGIN CERTIFICATE----- +MIIF8DCCA9igAwIBAgIPBuhGJy8fCo/RhFzjafbVMA0GCSqGSIb3DQEBBQUAMDgx +CzAJBgNVBAYTAkVTMRQwEgYDVQQKDAtJWkVOUEUgUy5BLjETMBEGA1UEAwwKSXpl +bnBlLmNvbTAeFw0wNzEyMTMxMzA4MjdaFw0zNzEyMTMwODI3MjVaMDgxCzAJBgNV +BAYTAkVTMRQwEgYDVQQKDAtJWkVOUEUgUy5BLjETMBEGA1UEAwwKSXplbnBlLmNv +bTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMnTesoPHqynhugWZWqx +whtFMnGV2f4QW8yv56V5AY+Jw8ryVXH3d753lPNypCxE2J6SmxQ6oeckkAoKVo7F +2CaU4dlI4S0+2gpy3aOZFdqBoof0e24md4lYrdbrDLJBenNubdt6eEHpCIgSfocu +ZhFjbFT7PJ1ywLwu/8K33Q124zrX97RovqL144FuwUZvXY3gTcZUVYkaMzEKsVe5 +o4qYw+w7NMWVQWl+dcI8IMVhulFHoCCQk6GQS/NOfIVFVJrRBSZBsLVNHTO+xAPI +JXzBcNs79AktVCdIrC/hxKw+yMuSTFM5NyPs0wH54AlETU1kwOENWocivK0bo/4m +tRXzp/yEGensoYi0RGmEg/OJ0XQGqcwL1sLeJ4VQJsoXuMl6h1YsGgEebL4TrRCs +tST1OJGh1kva8bvS3ke18byB9llrzxlT6Y0Vy0rLqW9E5RtBz+GGp8rQap+8TI0G +M1qiheWQNaBiXBZO8OOi+gMatCxxs1gs3nsL2xoP694hHwZ3BgOwye+Z/MC5TwuG +KP7Suerj2qXDR2kS4Nvw9hmL7Xtw1wLW7YcYKCwEJEx35EiKGsY7mtQPyvp10gFA +Wo15v4vPS8+qFsGV5K1Mij4XkdSxYuWC5YAEpAN+jb/af6IPl08M0w3719Hlcn4c +yHf/W5oPt64FRuXxqBbsR6QXAgMBAAGjgfYwgfMwgbAGA1UdEQSBqDCBpYEPaW5m +b0BpemVucGUuY29tpIGRMIGOMUcwRQYDVQQKDD5JWkVOUEUgUy5BLiAtIENJRiBB +MDEzMzcyNjAtUk1lcmMuVml0b3JpYS1HYXN0ZWl6IFQxMDU1IEY2MiBTODFDMEEG +A1UECQw6QXZkYSBkZWwgTWVkaXRlcnJhbmVvIEV0b3JiaWRlYSAxNCAtIDAxMDEw +IFZpdG9yaWEtR2FzdGVpejAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQUHRxlDqjyJXu0kc/ksbHmvVV0bAUwDQYJKoZIhvcNAQEFBQAD +ggIBAMeBRm8hGE+gBe/n1bqXUKJg7aWSFBpSm/nxiEqg3Hh10dUflU7F57dp5iL0 ++CmoKom+z892j+Mxc50m0xwbRxYpB2iEitL7sRskPtKYGCwkjq/2e+pEFhsqxPqg +l+nqbFik73WrAGLRne0TNtsiC7bw0fRue0aHwp28vb5CO7dz0JoqPLRbEhYArxk5 +ja2DUBzIgU+9Ag89njWW7u/kwgN8KRwCfr00J16vU9adF79XbOnQgxCvv11N75B7 +XSus7Op9ACYXzAJcY9cZGKfsK8eKPlgOiofmg59OsjQerFQJTx0CCzl+gQgVuaBp +E8gyK+OtbBPWg50jLbJtooiGfqgNASYJQNntKE6MkyQP2/EeTXp6WuKlWPHcj1+Z +ggwuz7LdmMySlD/5CbOlliVbN/UShUHiGUzGigjB3Bh6Dx4/glmimj4/+eAJn/3B +kUtdyXvWton83x18hqrNA/ILUpLxYm9/h+qrdslsUMIZgq+qHfUgKGgu1fxkN0/P +pUTEvnK0jHS0bKf68r10OEMr3q/53NjgnZ/cPcqlY0S/kqJPTIAcuxrDmkoEVU3K +7iYLHL8CxWTTnn7S05EcS6L1HOUXHA0MUqORH5zwIe0ClG+poEnK6EOMxPQ02nwi +o8ZmPrgbBYhdurz3vOXcFD2nhqi2WVIhA16L4wTtSyoeo09Q +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML +RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp +bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5 +IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0yOTA3 +MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3 +LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp +YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG +A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq +K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe +sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX +MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT +XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/ +HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH +4QIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJKoZIhvcNAQEFBQADggEBADub +j1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPyT/4xmf3IDExo +U8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf +zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5b +u/8j72gZyxKTJ1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+ +bYQLCIt+jerXmCHG8+c8eS9enNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/Er +fF6adulZkMV8gzURZVE= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFwTCCA6mgAwIBAgIITrIAZwwDXU8wDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UE +BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEjMCEGA1UEAxMaU3dpc3NTaWdu +IFBsYXRpbnVtIENBIC0gRzIwHhcNMDYxMDI1MDgzNjAwWhcNMzYxMDI1MDgzNjAw +WjBJMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMSMwIQYDVQQD +ExpTd2lzc1NpZ24gUGxhdGludW0gQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQAD +ggIPADCCAgoCggIBAMrfogLi2vj8Bxax3mCq3pZcZB/HL37PZ/pEQtZ2Y5Wu669y +IIpFR4ZieIbWIDkm9K6j/SPnpZy1IiEZtzeTIsBQnIJ71NUERFzLtMKfkr4k2Htn +IuJpX+UFeNSH2XFwMyVTtIc7KZAoNppVRDBopIOXfw0enHb/FZ1glwCNioUD7IC+ +6ixuEFGSzH7VozPY1kneWCqv9hbrS3uQMpe5up1Y8fhXSQQeol0GcN1x2/ndi5ob +jM89o03Oy3z2u5yg+gnOI2Ky6Q0f4nIoj5+saCB9bzuohTEJfwvH6GXp43gOCWcw +izSC+13gzJ2BbWLuCB4ELE6b7P6pT1/9aXjvCR+htL/68++QHkwFix7qepF6w9fl ++zC8bBsQWJj3Gl/QKTIDE0ZNYWqFTFJ0LwYfexHihJfGmfNtf9dng34TaNhxKFrY +zt3oEBSa/m0jh26OWnA81Y0JAKeqvLAxN23IhBQeW71FYyBrS3SMvds6DsHPWhaP +pZjydomyExI7C3d3rLvlPClKknLKYRorXkzig3R3+jVIeoVNjZpTxN94ypeRSCtF +KwH3HBqi7Ri6Cr2D+m+8jVeTO9TUps4e8aCxzqv9KyiaTxvXw3LbpMS/XUz13XuW +ae5ogObnmLo2t/5u7Su9IPhlGdpVCX4l3P5hYnL5fhgC72O00Puv5TtjjGePAgMB +AAGjgawwgakwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O +BBYEFFCvzAeHFUdvOMW0ZdHelarp35zMMB8GA1UdIwQYMBaAFFCvzAeHFUdvOMW0 +ZdHelarp35zMMEYGA1UdIAQ/MD0wOwYJYIV0AVkBAQEBMC4wLAYIKwYBBQUHAgEW +IGh0dHA6Ly9yZXBvc2l0b3J5LnN3aXNzc2lnbi5jb20vMA0GCSqGSIb3DQEBBQUA +A4ICAQAIhab1Fgz8RBrBY+D5VUYI/HAcQiiWjrfFwUF1TglxeeVtlspLpYhg0DB0 +uMoI3LQwnkAHFmtllXcBrqS3NQuB2nEVqXQXOHtYyvkv+8Bldo1bAbl93oI9ZLi+ +FHSjClTTLJUYFzX1UWs/j6KWYTl4a0vlpqD4U99REJNi54Av4tHgvI42Rncz7Lj7 +jposiU0xEQ8mngS7twSNC/K5/FqdOxa3L8iYq/6KUFkuozv8KV2LwUvJ4ooTHbG/ +u0IdUt1O2BReEMYxB+9xJ/cbOQncguqLs5WGXv312l0xpuAxtpTmREl0xRbl9x8D +YSjFyMsSoEJL+WuICI20MhjzdZ/EfwBPBZWcoxcCw7NTm6ogOSkrZvqdr16zktK1 +puEa+S1BaYEUtLS17Yk9zvupnTVCRLEcFHOBzyoBNZox1S2PbYTfgE1X4z/FhHXa +icYwu+uPyyIIoK6q8QNsOktNCaUOcsZWayFCTiMlFGiudgp8DAdwZPmaL/YFOSbG +DI8Zf0NebvRbFS/bYV3mZy8/CJT5YLSYMdp08YSTcU1f+2BY0fvEwW2JorsgH51x +kcsymxM9Pn2SUjWskpSi0xjCfMfqr3YFFt1nJ8J+HAciIfNAChs0B0QTwoRqjt8Z +Wr9/6x3iGjjRXK9HkmuAtTClyY3YqzGBH9/CZjfTk6mFhnll0g== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UE +BhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8w +MzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290 +IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDkyMjExMjIwMlowazELMAkGA1UEBhMC +SVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1 +ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENB +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNv +UTufClrJwkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX +4ay8IMKx4INRimlNAJZaby/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9 +KK3giq0itFZljoZUj5NDKd45RnijMCO6zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/ +gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1fYVEiVRvjRuPjPdA1Yprb +rxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2oxgkg4YQ +51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2F +be8lEfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxe +KF+w6D9Fz8+vm2/7hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4F +v6MGn8i1zeQf1xcGDXqVdFUNaBr8EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbn +fpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5jF66CyCU3nuDuP/jVo23Eek7 +jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLYiDrIn3hm7Ynz +ezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt +ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAL +e3KHwGCmSUyIWOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70 +jsNjLiNmsGe+b7bAEzlgqqI0JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDz +WochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKxK3JCaKygvU5a2hi/a5iB0P2avl4V +SM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+Xlff1ANATIGk0k9j +pwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC4yyX +X04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+Ok +fcvHlXHo2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7R +K4X9p2jIugErsWx0Hbhzlefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btU +ZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXemOR/qnuOf0GZvBeyqdn6/axag67XH/JJU +LysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9vwGYT7JZVEc+NHt4bVaT +LnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UE +BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz +dCBOZXR3b3JraW5nMB4XDTEwMDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDEL +MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp +cm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SEHi3y +YJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbua +kCNrmreIdIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRL +QESxG9fhwoXA3hA/Pe24/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp +6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gbh+0t+nvujArjqWaJGctB+d1ENmHP4ndG +yH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNVHQ4EFgQUBx/S55zawm6i +QLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ +KoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfO +tDIuUFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzu +QY0x2+c06lkh1QF612S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZ +Lgo/bNjR9eUJtGxUAArgFU2HdW23WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4u +olu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9/ZFvgrG+CJPbFEfxojfHRZ48 +x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEvTCCA6WgAwIBAgIBADANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEn +MCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQL +ExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMg +b2YgQ29tbWVyY2UgUm9vdDAeFw0wMzA5MzAxNjEzNDNaFw0zNzA5MzAxNjEzNDRa +MH8xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1lcmZpcm1hIFNBIENJRiBB +ODI3NDMyODcxIzAhBgNVBAsTGmh0dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3JnMSIw +IAYDVQQDExlDaGFtYmVycyBvZiBDb21tZXJjZSBSb290MIIBIDANBgkqhkiG9w0B +AQEFAAOCAQ0AMIIBCAKCAQEAtzZV5aVdGDDg2olUkfzIx1L4L1DZ77F1c2VHfRtb +unXF/KGIJPov7coISjlUxFF6tdpg6jg8gbLL8bvZkSM/SAFwdakFKq0fcfPJVD0d +BmpAPrMMhe5cG3nCYsS4No41XQEMIwRHNaqbYE6gZj3LJgqcQKH0XZi/caulAGgq +7YN6D6IUtdQis4CwPAxaUWktWBiP7Zme8a7ileb2R6jWDA+wWFjbw2Y3npuRVDM3 +0pQcakjJyfKl2qUMI/cjDpwyVV5xnIQFUZot/eZOKjRa3spAN2cMVCFVd9oKDMyX +roDclDZK9D7ONhMeU+SsTjoF7Nuucpw4i9A5O4kKPnf+dQIBA6OCAUQwggFAMBIG +A1UdEwEB/wQIMAYBAf8CAQwwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5j +aGFtYmVyc2lnbi5vcmcvY2hhbWJlcnNyb290LmNybDAdBgNVHQ4EFgQU45T1sU3p +26EpW1eLTXYGduHRooowDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIA +BzAnBgNVHREEIDAegRxjaGFtYmVyc3Jvb3RAY2hhbWJlcnNpZ24ub3JnMCcGA1Ud +EgQgMB6BHGNoYW1iZXJzcm9vdEBjaGFtYmVyc2lnbi5vcmcwWAYDVR0gBFEwTzBN +BgsrBgEEAYGHLgoDATA+MDwGCCsGAQUFBwIBFjBodHRwOi8vY3BzLmNoYW1iZXJz +aWduLm9yZy9jcHMvY2hhbWJlcnNyb290Lmh0bWwwDQYJKoZIhvcNAQEFBQADggEB +AAxBl8IahsAifJ/7kPMa0QOx7xP5IV8EnNrJpY0nbJaHkb5BkAFyk+cefV/2icZd +p0AJPaxJRUXcLo0waLIJuvvDL8y6C98/d3tGfToSJI6WjzwFCm/SlCgdbQzALogi +1djPHRPH8EjX1wWnz8dHnjs8NMiAT9QUu/wNUPf6s+xCX6ndbcj0dc97wXImsQEc +XCz9ek60AcUFV7nnPKoF2YjpB0ZBzu9Bga5Y34OirsrXdx/nADydb47kMgkdTXg0 +eDQ8lJsm7U9xxhl6vSAiSFr+S30Dt+dYvsYyTnQeaN2oaFuzPu5ifdmA6Ap1erfu +tGWaIZDgqtCYvDi1czyL+Nw= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb +MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow +GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj +YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL +MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE +BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM +GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua +BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe +3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4 +YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR +rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm +ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU +oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF +MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v +QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t +b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF +AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q +GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz +Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2 +G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi +l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3 +smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCB +gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G +A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV +BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw +MDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl +YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P +RE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3 +UcEbVASY06m/weaKXTuH+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI +2GqGd0S7WWaXUF601CxwRM/aN5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8 +Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp ++2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+ +DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5O +nKVIrLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW +/zAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6g +PKA6hjhodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9u +QXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOCAQEAPpiem/Yb6dc5t3iuHXIY +SdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CPOGEIqB6BCsAv +IC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/ +RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4 +zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd +BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB +ZQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDcDCCAligAwIBAgIBBTANBgkqhkiG9w0BAQUFADBbMQswCQYDVQQGEwJVUzEY +MBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxDDAKBgNVBAsT +A1BLSTEWMBQGA1UEAxMNRG9EIFJvb3QgQ0EgMjAeFw0wNDEyMTMxNTAwMTBaFw0y +OTEyMDUxNTAwMTBaMFsxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVy +bm1lbnQxDDAKBgNVBAsTA0RvRDEMMAoGA1UECxMDUEtJMRYwFAYDVQQDEw1Eb0Qg +Um9vdCBDQSAyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwCzB9o07 +rP8/PNZxvrh0IgfscEEV/KtA4weqwcPYn/7aTDq/P8jYKHtLNgHArEUlw9IOCo+F +GGQQPRoTcCpvjtfcjZOzQQ84Ic2tq8I9KgXTVxE3Dc2MUfmT48xGSSGOFLTNyxQ+ +OM1yMe6rEvJl6jQuVl3/7mN1y226kTT8nvP0LRy+UMRC31mI/2qz+qhsPctWcXEF +lrufgOWARVlnQbDrw61gpIB1BhecDvRD4JkOG/t/9bPMsoGCsf0ywbi+QaRktWA6 +WlEwjM7eQSwZR1xJEGS5dKmHQa99brrBuKG/ZTE6BGf5tbuOkooAY7ix5ow4X4P/ +UNU7ol1rshDMYwIDAQABoz8wPTAdBgNVHQ4EFgQUSXS7DF66ev4CVO97oMaVxgmA +cJYwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD +ggEBAJiRjT+JyLv1wGlzKTs1rLqzCHY9cAmS6YREIQF9FHYb7lFsHY0VNy17MWn0 +mkS4r0bMNPojywMnGdKDIXUr5+AbmSbchECV6KjSzPZYXGbvP0qXEIIdugqi3VsG +K52nZE7rLgE1pLQ/E61V5NVzqGmbEfGY8jEeb0DU+HifjpGgb3AEkGaqBivO4XqS +tX3h4NGW56E6LcyxnR8FRO2HmdNNGnA5wQQM5X7Z8a/XIA7xInolpHOZzD+kByeW +qKKV7YK5FtOeC4fCwfKI9WLfaN/HvGlR7bFc3FRUKQ8JOZqsA8HbDE2ubwp6Fknx +v5HSOJTT9pUst2zJQraNypCNhdk= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAw +PTELMAkGA1UEBhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFz +cyAyIFByaW1hcnkgQ0EwHhcNOTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9 +MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2VydHBsdXMxGzAZBgNVBAMTEkNsYXNz +IDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANxQ +ltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxvc0NXYKwzCkTsA18cgCSR5aiR +VhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLRYE2+L0ER4/YXJQyL +kcAbmXuZVg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v0lPubNCd +EgETjdyAYveVqUSISnFOYFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yas +H7WLO7dDWWuwJKZtkIvEcupdM5i3y95ee++U8Rs+yskhwcWYAqqi9lt3m/V+llU0 +HGdpwPFC40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRMECDAGAQH/AgEKMAsGA1Ud +DwQEAwIBBjAdBgNVHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJYIZIAYb4 +QgEBBAQDAgEGMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMu +Y29tL0NSTC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/ +AN9WM2K191EBkOvDP9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8 +yfFC82x/xXp8HVGIutIKPidd3i1RTtMTZGnkLuPT55sJmabglZvOGtd/vjzOUrMR +FcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+7UCmnYR0ObncHoUW2ikbhiMA +ybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW//1IMwrh3KWB +kJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7 +l7+ijrRU +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50 +cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3Qs +IEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVz +dCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwHhcNMDkwNzA3MTcy +NTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVu +dHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwt +dGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0 +aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP/vaCeb9zYQYKpSfYs1/T +RU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXzHHfV1IWN +cCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hW +wcKUs/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1 +U1+cPvQXLOZprE4yTGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0 +jaWvYkxN4FisZDQSA/i2jZRjJKRxAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAP +BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ60B7vfec7aVHUbI2fkBJmqzAN +BgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5ZiXMRrEPR9RP/ +jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ +Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v +1fN2D807iDginWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4R +nAuknZoh8/CbCzB428Hch0P+vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmH +VHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xOe4pIb4tF9g== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIID9jCCAt6gAwIBAgIQZIKe/DcedF38l/+XyLH/QTANBgkqhkiG9w0BAQsFADCB +lDELMAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8w +HQYDVQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRl +YyBDbGFzcyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +IC0gRzYwHhcNMTExMDE4MDAwMDAwWhcNMzcxMjAxMjM1OTU5WjCBlDELMAkGA1UE +BhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZT +eW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBDbGFzcyAy +IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzYwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDNzOkFyGOFyz9AYxe9GPo15gRn +V2WYKaRPyVyPDzTS+NqoE2KquB5QZ3iwFkygOakVeq7t0qLA8JA3KRgmXOgNPLZs +ST/B4NzZS7YUGQum05bh1gnjGSYc+R9lS/kaQxwAg9bQqkmi1NvmYji6UBRDbfkx ++FYW2TgCkc/rbN27OU6Z4TBnRfHU8I3D3/7yOAchfQBeVkSz5GC9kSucq1sEcg+y +KNlyqwUgQiWpWwNqIBDMMfAr2jUs0Pual07wgksr2F82owstr2MNHSV/oW5cYqGN +KD6h/Bwg+AEvulWaEbAZ0shQeWsOagXXqgQ2sqPy4V93p3ec5R7c6d9qwWVdAgMB +AAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW +BBSHjCCVyJhK0daABkqQNETfHE2/sDANBgkqhkiG9w0BAQsFAAOCAQEAgY6ypWaW +tyGltu9vI1pf24HFQqV4wWn99DzX+VxrcHIa/FqXTQCAiIiCisNxDY7FiZss7Y0L +0nJU9X3UXENX6fOupQIR9nYrgVfdfdp0MP1UR/bgFm6mtApI5ud1Bw8pGTnOefS2 +bMVfmdUfS/rfbSw8DVSAcPCIC4DPxmiiuB1w2XaM/O6lyc+tHc+ZJVdaYkXLFmu9 +Sc2lo4xpeSWuuExsi0BmSxY/zwIa3eFsawdhanYVKZl/G92IgMG/tY9zxaaWI4Sm +KIYkM2oBLldzJbZev4/mHWGoQClnHYebHX+bn5nNMdZUvmK7OaxoEkiRIKXLsd3+ +b/xa5IJVWa8xqQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCB +lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug +Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho +dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt +SGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgxOTIyWjCBlzELMAkG +A1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEe +MBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8v +d3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdh +cmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn +0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlIwrthdBKWHTxqctU8EGc6Oe0rE81m65UJ +M6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFdtqdt++BxF2uiiPsA3/4a +MXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8i4fDidNd +oI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqI +DsjfPe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9Ksy +oUhbAgMBAAGjgbkwgbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYD +VR0OBBYEFKFyXyYbKJhDlV0HN9WFlp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0 +dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LUhhcmR3YXJlLmNy +bDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEF +BQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM +//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28Gpgoiskli +CE7/yMgUsogWXecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gE +CJChicsZUN/KHAG8HQQZexB2lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t +3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kniCrVWFCVH/A7HFe7fRQ5YiuayZSS +KqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67nfhmqA== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUFADBr +MQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRl +cm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNv +bW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2WhcNMjIwNjI0MDAxNjEyWjBrMQsw +CQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5h +dGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNvbW1l +cmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvV95WHm6h +2mCxlCfLF9sHP4CFT8icttD0b0/Pmdjh28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4E +lpF7sDPwsRROEW+1QK8bRaVK7362rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdV +ZqW1LS7YgFmypw23RuwhY/81q6UCzyr0TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq +299yOIzzlr3xF7zSujtFWsan9sYXiwGd/BmoKoMWuDpI/k4+oKsGGelT84ATB+0t +vz8KPFUgOSwsAGl0lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzsGHxBvfaL +dXe6YJ2E5/4tAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD +AgEGMB0GA1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUF +AAOCAQEAX/FBfXxcCLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcR +zCSs00Rsca4BIGsDoo8Ytyk6feUWYFN4PMCvFYP3j1IzJL1kk5fui/fbGKhtcbP3 +LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pzzkWKsKZJ/0x9nXGIxHYdkFsd +7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBuYQa7FkKMcPcw +++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/hC3euiInlhBx6yLt +398znM/jra6O1I7mT1GvFpLgXPYHDw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFpDCCA4ygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEc +MBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBP +bmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyODA2 +MDAwMFoXDTM3MDkyOTE0MDgwMFowYzELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0Ft +ZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2EgT25saW5lIFJvb3Qg +Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBAMxBRR3pPU0Q9oyxQcngXssNt79Hc9PwVU3dxgz6sWYFas14tNwC +206B89enfHG8dWOgXeMHDEjsJcQDIPT/DjsS/5uN4cbVG7RtIuOx238hZK+GvFci +KtZHgVdEglZTvYYUAQv8f3SkWq7xuhG1m1hagLQ3eAkzfDJHA1zEpYNI9FdWboE2 +JxhP7JsowtS013wMPgwr38oE18aO6lhOqKSlGBxsRZijQdEt0sdtjRnxrXm3gT+9 +BoInLRBYBbV4Bbkv2wxrkJB+FFk4u5QkE+XRnRTf04JNRvCAOVIyD+OEsnpD8l7e +Xz8d3eOyG6ChKiMDbi4BFYdcpnV1x5dhvt6G3NRI270qv0pV2uh9UPu0gBe4lL8B +PeraunzgWGcXuVjgiIZGZ2ydEEdYMtA1fHkqkKJaEBEjNa0vzORKW6fIJ/KD3l67 +Xnfn6KVuY8INXWHQjNJsWiEOyiijzirplcdIz5ZvHZIlyMbGwcEMBawmxNJ10uEq +Z8A9W6Wa6897GqidFEXlD6CaZd4vKL3Ob5Rmg0gp2OpljK+T2WSfVVcmv2/LNzGZ +o2C7HK2JNDJiuEMhBnIMoVxtRsX6Kc8w3onccVvdtjc+31D1uAclJuW8tf48ArO3 ++L5DwYcRlJ4jbBeKuIonDFRH8KmzwICMoCfrHRnjB453cMor9H124HhnAgMBAAGj +YzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE1FwWg4u3OpaaEg5+31IqEj +FNeeMB8GA1UdIwQYMBaAFE1FwWg4u3OpaaEg5+31IqEjFNeeMA4GA1UdDwEB/wQE +AwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAZ2sGuV9FOypLM7PmG2tZTiLMubekJcmn +xPBUlgtk87FYT15R/LKXeydlwuXK5w0MJXti4/qftIe3RUavg6WXSIylvfEWK5t2 +LHo1YGwRgJfMqZJS5ivmae2p+DYtLHe/YUjRYwu5W1LtGLBDQiKmsXeu3mnFzccc +obGlHBD7GL4acN3Bkku+KVqdPzW+5X1R+FXgJXUjhx5c3LqdsKyzadsXg8n33gy8 +CNyRnqjQ1xU3c6U1uPx+xURABsPr+CKAXEfOAuMRn0T//ZoyzH1kUQ7rVyZ2OuMe +IjzCpjbdGe+n/BLzJsBZMYVMnNjP36TMzCmT/5RtdlwTCJfy7aULTd3oyWgOZtMA +DjMSW7yV5TKQqLPGbIOtd+6Lfn6xqavT4fG2wLHqiMDn05DpKJKUe2h7lyoKZy2F +AjgQ5ANh1NolNscIWC2hp1GvMApJ9aZphwctREZ2jirlmjvXGKL8nDgQzMY70rUX +Om/9riW99XJZZLF0KjhfGEzfz3EEWjbUvy+ZnOjZurGV5gJLIaFb1cFPj65pbVPb +AZO1XB4Y3WRayhgoPmMEEf0cjQAPuDffZ4qdZqkCapH/E8ovXYO8h5Ns3CRRFgQl +Zvqz2cK6Kb6aSDiCmfS/O0oxGfm/jiEzFMpPVF/7zvuPcX/9XhmgD0uRuMRUvAaw +RY8mkaKO/qk= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYD +VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0 +ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0G +CSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTAeFw0wOTA2MTYxMTMwMThaFw0y +OTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3Qx +FjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3pp +Z25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o +dTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvP +kd6mJviZpWNwrZuuyjNAfW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tc +cbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG0IMZfcChEhyVbUr02MelTTMuhTlAdX4U +fIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKApxn1ntxVUwOXewdI/5n7 +N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm1HxdrtbC +xkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1 ++rUCAwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G +A1UdDgQWBBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPM +Pcu1SCOhGnqmKrs0aDAbBgNVHREEFDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqG +SIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0olZMEyL/azXm4Q5DwpL7v8u8h +mLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfXI/OMn74dseGk +ddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775 +tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c +2Pm2G2JwCz02yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5t +HMN1Rq41Bab2XD0h7lbwyYIiLXpUq3DDfSJlgnCW +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIHqTCCBZGgAwIBAgIQYwaGp8U3ZaVDkKhqWMzUMjANBgkqhkiG9w0BAQUFADCB +jzELMAkGA1UEBhMCTFYxNTAzBgNVBAoTLFZBUyBMYXR2aWphcyBQYXN0cyAtIFZp +ZW4ucmVnLk5yLjQwMDAzMDUyNzkwMSMwIQYDVQQLExpTZXJ0aWZpa2FjaWphcyBw +YWthbHBvanVtaTEkMCIGA1UEAxMbVkFTIExhdHZpamFzIFBhc3RzIFNTSShSQ0Ep +MB4XDTA2MDkxMzA5MjIxMFoXDTI0MDkxMzA5Mjc1N1owgY8xCzAJBgNVBAYTAkxW +MTUwMwYDVQQKEyxWQVMgTGF0dmlqYXMgUGFzdHMgLSBWaWVuLnJlZy5Oci40MDAw +MzA1Mjc5MDEjMCEGA1UECxMaU2VydGlmaWthY2lqYXMgcGFrYWxwb2p1bWkxJDAi +BgNVBAMTG1ZBUyBMYXR2aWphcyBQYXN0cyBTU0koUkNBKTCCAiIwDQYJKoZIhvcN +AQEBBQADggIPADCCAgoCggIBAJu4+f1hVS9PpKUUtS6OuSSPrPuxVD9A/0/F5YZo +e1OT+zWCNahQLpRSoNuDPnXaFXCsCc/ugkmtNkm5tHGLtAChQgbKCApjl7YI/O60 +3Jh4GYLJ+H9kPqrJ/rGN67Bk9bzzxD46kOpOjj8bGbxqg8ORPGxV+wpSwOjhXXeF +M8VJ3+xqv79sN/6OSaIVGM6LjmseOKMwb4iBfnJWRBrEejkP9sSPltSy6wBOXN67 +5zu35iQFk2tN5pFEv+6YG8eFGxFBeyI2p74+6Ho33BjekJ2PzbLXmj/iF39bDOHv +P2Y9biTksM7DDIhslNo4JXxSOeNzFLMARWOaDEJAXgTG93JkzsluM7Pk020klTeT +fvIAXRmLH/NDc6ifRdIGqey0Qrv67gzHTz9RH9Gv0KwYf4eBIv6p3QeWbXz4TtlN +OlBp1UF+xdp02I5z5X6D4cMZgbe9v0COvi6aogyqTgIuuyrhCF0xA8msJ7Cv3NXI +FH1AnVWJIfmQzNTJYEFzq+jN2DpVOQqCmf6b9fU8HJHLwPpGVK4h/CqsXHveepdx +/WxrzUiapNuBfBg3L5B9YZS9F8lctlQWd8oJSqrpvE+UdQFaVryS0o+515feVnQB +9xZxSbH1GEaZQe5i4bMsZXVpKXJDA/ibH/o49J7sQBCOrJfVsDO+nxjcLfdBeFRK +YkTnAgMBAAGjggH9MIIB+TAOBgNVHQ8BAf8EBAMCAQYwGAYIKwYBBQUHAQMEDDAK +MAgGBgQAjkYBATAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTMw/Vm/3OsOFqW +GyGJuIFMH8teJTAQBgkrBgEEAYI3FQEEAwIBADCCAYkGA1UdIASCAYAwggF8MIIB +eAYLKwYBBAGBxFkBAQIwggFnMIIBOAYIKwYBBQUHAgIwggEqHoIBJgBTAGkAcwAg +AGkAcgAgAHMAZQByAHQAaQBmAGkAawBhAHQAcwAsACAAawBvACAAaQB6AGQAZQB2 +AGkAcwAgAFYAQQBTACAATABhAHQAdgBpAGoAYQBzACAAUABhAHMAdABzACwAIABu +AG8AZAByAG8AcwBpAG4AbwB0ACAAYQB0AGIAaQBsAHMAdABpAGIAdQAgAEUAbABl +AGsAdAByAG8AbgBpAHMAawBvACAAZABvAGsAdQBtAGUAbgB0AHUAIABsAGkAawB1 +AG0AYQBtACAAdQBuACAARQBpAHIAbwBwAGEAcwAgAFAAYQByAGwAYQBtAGUAbgB0 +AGEAIABkAGkAcgBlAGsAdABpAHYAYQBpACAAMQA5ADkAOQAvADkAMwAvAEUASzAp +BggrBgEFBQcCARYdaHR0cDovL3d3dy5lLW1lLmx2L3JlcG9zaXRvcnkwDQYJKoZI +hvcNAQEFBQADggIBAB8oSjWQIWNoCi94r6MegiaXoz8nGdJLo0J6BhNlW8EEy+t9 +fO+U8vGJ9bffUgIhadLqljTloM+XuJxVDhCFoxReLAX4tTp28/l6uN62DCdp8suU +kQsdudWOb5kvzfIZVjk6SFbwAf+Cdbay/dHU9fJjV0xNoX7MELoEae/0FPyzlx9F +7m9KKH/Rxie8x6Opa3vtghNvq94P+3HrXBEaqSzQMJ/8NjdW75XpurcTtq6fAmGt +nuxrBG82nw+Z98LJyEwouSjUIdeeVNXAzvSO5FWUe48kxjj8q3qkVnc9qEXvZJKk +0Ep+u3OL9A1Sc7g6SF5DgNOpcHdi/8coHHMeQ+YnJFtJueY2pI79xS0veqV5EnrX +IbIlbcgPosNhS+VI4le6n/KKId3bZPDaGd/OwJuAOcJ3d2MVU3KE+qSPBzeGIX1Q ++j1qN9uRDjez/c4Lynth0Jx0nH04aG3pex3W8Sq07ztgUncF5gLCX4xbvPB9t3PH +kWuyKrNjozTVq60lcUf/Gj56to2VdsPups0DCWzuRWeYz5lIdsHOinSaaFIBNCLI +7eIUC4S9bhCMsXKbvugI11fVf+q0AT1O5OLoZ+eMfunnQhHvlUbIkda+JxeAGTSY +58bfHvwhX56GPbx+8Jy9cp70R4JbcWfz+txUTKhc2FnH0AcOEzMnvPRp8Gsh +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEDzCCAvegAwIBAgIBATANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQGEwJTSzET +MBEGA1UEBxMKQnJhdGlzbGF2YTETMBEGA1UEChMKRGlzaWcgYS5zLjERMA8GA1UE +AxMIQ0EgRGlzaWcwHhcNMDYwMzIyMDEzOTM0WhcNMTYwMzIyMDEzOTM0WjBKMQsw +CQYDVQQGEwJTSzETMBEGA1UEBxMKQnJhdGlzbGF2YTETMBEGA1UEChMKRGlzaWcg +YS5zLjERMA8GA1UEAxMIQ0EgRGlzaWcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQCS9jHBfYj9mQGp2HvycXXxMcbzdWb6UShGhJd4NLxs/LxFWYgmGErE +Nx+hSkS943EE9UQX4j/8SFhvXJ56CbpRNyIjZkMhsDxkovhqFQ4/61HhVKndBpnX +mjxUizkDPw/Fzsbrg3ICqB9x8y34dQjbYkzo+s7552oftms1grrijxaSfQUMbEYD +XcDtab86wYqg6I7ZuUUohwjstMoVvoLdtUSLLa2GDGhibYVW8qwUYzrG0ZmsNHhW +S8+2rT+MitcE5eN4TPWGqvWP+j1scaMtymfraHtuM6kMgiioTGohQBUgDCZbg8Kp +FhXAJIJdKxatymP2dACw30PEEGBWZ2NFAgMBAAGjgf8wgfwwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUjbJJaJ1yCCW5wCf1UJNWSEZx+Y8wDgYDVR0PAQH/BAQD +AgEGMDYGA1UdEQQvMC2BE2Nhb3BlcmF0b3JAZGlzaWcuc2uGFmh0dHA6Ly93d3cu +ZGlzaWcuc2svY2EwZgYDVR0fBF8wXTAtoCugKYYnaHR0cDovL3d3dy5kaXNpZy5z +ay9jYS9jcmwvY2FfZGlzaWcuY3JsMCygKqAohiZodHRwOi8vY2EuZGlzaWcuc2sv +Y2EvY3JsL2NhX2Rpc2lnLmNybDAaBgNVHSAEEzARMA8GDSuBHpGT5goAAAABAQEw +DQYJKoZIhvcNAQEFBQADggEBAF00dGFMrzvY/59tWDYcPQuBDRIrRhCA/ec8J9B6 +yKm2fnQwM6M6int0wHl5QpNt/7EpFIKrIYwvF/k/Ji/1WcbvgAa3mkkp7M5+cTxq +EEHA9tOasnxakZzArFvITV734VP/Q3f8nktnbNfzg9Gg4H8l37iYC5oyOGwwoPP/ +CBUz91BKez6jPiCp3C9WgArtQVCwyfTssuMmRAAOb54GvCKWU3BlxFAKRmukLyeB +EicTXxChds6KezfqwzlhA5WYOudsiCUI/HloDYd9Yvi0X/vF2Ey9WLw/Q1vUHgFN +PGO+I++MzVpQuGhU+QqZMxEA4Z7CRneC9VkGjCFMhwnN5ag= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDXTCCAkWgAwIBAgIDAOJCMA0GCSqGSIb3DQEBBQUAMFUxCzAJBgNVBAYTAkFU +MRAwDgYDVQQKEwdBLVRydXN0MRkwFwYDVQQLExBBLVRydXN0LW5RdWFsLTAxMRkw +FwYDVQQDExBBLVRydXN0LW5RdWFsLTAxMB4XDTA0MTEzMDIzMDAwMFoXDTE0MTEz +MDIzMDAwMFowVTELMAkGA1UEBhMCQVQxEDAOBgNVBAoTB0EtVHJ1c3QxGTAXBgNV +BAsTEEEtVHJ1c3QtblF1YWwtMDExGTAXBgNVBAMTEEEtVHJ1c3QtblF1YWwtMDEw +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQD/9RyAEZ6eHmhYzNJ328f0 +jmdSUFi6EqRqOxb3jHNPTIpK82CR6z5lmSnZQNUuCPD+htbNZffd2DKVB06NOyZ1 +2zcOMCgj4GtkZoqE0zPpPT3bpoE55nkZZe/qWEX/64wz/L/4EdkvKDSKG/UsP75M +tmCVY5m2Eg73RVFRz4ccBIMpHel4lzEqSkdDtZOY5fnkrE333hx67nxq21vY8Eyf +8O4fPQ5RtN8eohQCcPQ1z6ypU1R7N9jPRpnI+yzMOiwd3+QcKhHi1miCzo0pkOaB +1CwmfsTyNl8qU0NJUL9Ta6cea7WThwTiWol2yD88cd2cy388xpbNkfrCPmZNGLoV +AgMBAAGjNjA0MA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0OBAoECE5ZzscCMocwMA4G +A1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEA69I9R1hU9Gbl9vV7W7AH +QpUJAlFAvv2It/eY8p2ouQUPVaSZikaKtAYrCD/arzfXB43Qet+dM6CpHsn8ikYR +vQKePjXv3Evf+C1bxwJAimcnZV6W+bNOTpdo8lXljxkmfN+Z5S+XzvK2ttUtP4Et +YOVaxHw2mPMNbvDeY+foJkiBn3KYjGabMaR8moZqof5ofj4iS/WyamTZti6v/fKx +n1vII+/uWkcxV5DT5+r9HLon0NYF0Vg317Wh+gWDV59VZo+dcwJDb+keYqMFYoqp +77SGkZGu41S8NGYkQY3X9rNHRkDbLfpKYDmy6NanpOE1EHW1/sNSFAs43qZZKJEQ +xg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEojCCA4qgAwIBAgIQRL4Mi1AAJLQR0zYlJWfJiTANBgkqhkiG9w0BAQUFADCB +rjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug +Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho +dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xNjA0BgNVBAMTLVVUTi1VU0VSRmlyc3Qt +Q2xpZW50IEF1dGhlbnRpY2F0aW9uIGFuZCBFbWFpbDAeFw05OTA3MDkxNzI4NTBa +Fw0xOTA3MDkxNzM2NThaMIGuMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAV +BgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5l +dHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRydXN0LmNvbTE2MDQGA1UE +AxMtVVROLVVTRVJGaXJzdC1DbGllbnQgQXV0aGVudGljYXRpb24gYW5kIEVtYWls +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsjmFpPJ9q0E7YkY3rs3B +YHW8OWX5ShpHornMSMxqmNVNNRm5pELlzkniii8efNIxB8dOtINknS4p1aJkxIW9 +hVE1eaROaJB7HHqkkqgX8pgV8pPMyaQylbsMTzC9mKALi+VuG6JG+ni8om+rWV6l +L8/K2m2qL+usobNqqrcuZzWLeeEeaYji5kbNoKXqvgvOdjp6Dpvq/NonWz1zHyLm +SGHGTPNpsaguG7bUMSAsvIKKjqQOpdeJQ/wWWq8dcdcRWdq6hw2v+vPhwvCkxWeM +1tZUOt4KpLoDd7NlyP0e03RiqhjKaJMeoYV+9Udly/hNVyh00jT/MLbu9mIwFIws +6wIDAQABo4G5MIG2MAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud +DgQWBBSJgmd9xJ0mcABLtFBIfN49rgRufTBYBgNVHR8EUTBPME2gS6BJhkdodHRw +Oi8vY3JsLnVzZXJ0cnVzdC5jb20vVVROLVVTRVJGaXJzdC1DbGllbnRBdXRoZW50 +aWNhdGlvbmFuZEVtYWlsLmNybDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUH +AwQwDQYJKoZIhvcNAQEFBQADggEBALFtYV2mGn98q0rkMPxTbyUkxsrt4jFcKw7u +7mFVbwQ+zznexRtJlOTrIEy05p5QLnLZjfWqo7NK2lYcYJeA3IKirUq9iiv/Cwm0 +xtcgBEXkzYABurorbs6q15L+5K/r9CYdFip/bDCVNy8zEqx/3cfREYxRmLLQo5HQ +rfafnoOTHh1CuEava2bwm3/q4wMC5QJRwarVNZ1yQAOJujEdxRBoUp7fooXFXAim +eOZTT7Hot9MUnpOmw2TjrH5xzbyf6QMbzPvprDHBr3wVdAKZw7JHpsIyYdfHb0gk +USeh1YdV8nuPmD0Wnu51tvjQjvLzxq4oW6fw8zYX/MMF08oDSlQ= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UE +BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVz +dCBQcmVtaXVtMB4XDTEwMDEyOTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkG +A1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1U +cnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxBLf +qV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtnBKAQ +JG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ ++jjeRFcV5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrS +s8PhaJyJ+HoAVt70VZVs+7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5 +HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmdGPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d7 +70O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5Rp9EixAqnOEhss/n/fauG +V+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NIS+LI+H+S +qHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S +5u046uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4Ia +C1nEWTJ3s7xgaVY5/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TX +OwF0lkLgAOIua+rF7nKsu7/+6qqo+Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYE +FJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ +BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByvMiPIs0laUZx2 +KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg +Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B +8OWycvpEgjNC6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQ +MKSOyARiqcTtNd56l+0OOF6SL5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc +0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK+4w1IX2COPKpVJEZNZOUbWo6xbLQ +u4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmVBtWVyuEklut89pMF +u+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFgIxpH +YoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8 +GKa1qF60g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaO +RtGdFNrHF+QFlozEJLUbzxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6e +KeC2uAloGRwYQw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJTRTEU +MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3 +b3JrMSAwHgYDVQQDExdBZGRUcnVzdCBQdWJsaWMgQ0EgUm9vdDAeFw0wMDA1MzAx +MDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtB +ZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5ldHdvcmsxIDAeBgNV +BAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+A3S72mnTRqX4jsIMEZBRpS9mVEBV +6tsfSlbunyNu9DnLoblv8n75XYcmYZ4c+OLspoH4IcUkzBEMP9smcnrHAZcHF/nX +GCwwfQ56HmIexkvA/X1id9NEHif2P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnP +dzRGULD4EfL+OHn3Bzn+UZKXC1sIXzSGAa2Il+tmzV7R/9x98oTaunet3IAIx6eH +1lWfl2royBFkuucZKT8Rs3iQhCBSWxHveNCD9tVIkNAwHM+A+WD+eeSI8t0A65RF +62WUaUC6wNW0uLp9BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0GA1UdDgQW +BBSBPjfYkrAfd59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUw +AwEB/zCBjgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDEL +MAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRU +cnVzdCBUVFAgTmV0d29yazEgMB4GA1UEAxMXQWRkVHJ1c3QgUHVibGljIENBIFJv +b3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4JNojVhaTdt02KLmuG7jD8WS6 +IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL+YPoRNWyQSW/ +iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbjPGsye/Kf8Lb93/Ao +GEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bYGozH7ZxOmuASu7VqTITh +4SINhwBk/ox9Yjllpu9CtoAlEmEBqCQTcAARJl/6NVDFSMwGR+gn2HCNX2TmoUQm +XiLsks3/QppEIW1cxeMiHV9HEufOX1362KqxMy3ZdvJOOjMMK7MtkAY= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEajCCA1KgAwIBAgIBATANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJKUDEN +MAsGA1UECgwESlBLSTEpMCcGA1UECwwgUHJlZmVjdHVyYWwgQXNzb2NpYXRpb24g +Rm9yIEpQS0kxETAPBgNVBAsMCEJyaWRnZUNBMB4XDTAzMTIyNzA1MDgxNVoXDTEz +MTIyNjE0NTk1OVowWjELMAkGA1UEBhMCSlAxDTALBgNVBAoMBEpQS0kxKTAnBgNV +BAsMIFByZWZlY3R1cmFsIEFzc29jaWF0aW9uIEZvciBKUEtJMREwDwYDVQQLDAhC +cmlkZ2VDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANTnUmg7K3m8 +52vd77kwkq156euwoWm5no8E8kmaTSc7x2RABPpqNTlMKdZ6ttsyYrqREeDkcvPL +yF7yf/I8+innasNtsytcTAy8xY8Avsbd4JkCGW9dyPjk9pzzc3yLQ64Rx2fujRn2 +agcEVdPCr/XpJygX8FD5bbhkZ0CVoiASBmlHOcC3YpFlfbT1QcpOSOb7o+VdKVEi +MMfbBuU2IlYIaSr/R1nO7RPNtkqkFWJ1/nKjKHyzZje7j70qSxb+BTGcNgTHa1YA +UrogKB+UpBftmb4ds+XlkEJ1dvwokiSbCDaWFKD+YD4B2s0bvjCbw8xuZFYGhNyR +/2D5XfN1s2MCAwEAAaOCATkwggE1MA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E +BTADAQH/MG0GA1UdHwRmMGQwYqBgoF6kXDBaMQswCQYDVQQGEwJKUDENMAsGA1UE +CgwESlBLSTEpMCcGA1UECwwgUHJlZmVjdHVyYWwgQXNzb2NpYXRpb24gRm9yIEpQ +S0kxETAPBgNVBAsMCEJyaWRnZUNBMIGDBgNVHREEfDB6pHgwdjELMAkGA1UEBhMC +SlAxJzAlBgNVBAoMHuWFrOeahOWAi+S6uuiqjeiovOOCteODvOODk+OCuTEeMBwG +A1UECwwV6YO96YGT5bqc55yM5Y2U6K2w5LyaMR4wHAYDVQQLDBXjg5bjg6rjg4Pj +grjoqo3oqLzlsYAwHQYDVR0OBBYEFNQXMiCqQNkR2OaZmQgLtf8mR8p8MA0GCSqG +SIb3DQEBBQUAA4IBAQATjJo4reTNPC5CsvAKu1RYT8PyXFVYHbKsEpGt4GR8pDCg +HEGAiAhHSNrGh9CagZMXADvlG0gmMOnXowriQQixrtpkmx0TB8tNAlZptZWkZC+R +8TnjOkHrk2nFAEC3ezbdK0R7MR4tJLDQCnhEWbg50rf0wZ/aF8uAaVeEtHXa6W0M +Xq3dSe0XAcrLbX4zZHQTaWvdpLAIjl6DZ3SCieRMyoWUL+LXaLFdTP5WBCd+No58 +IounD9X4xxze2aeRVaiV/WnQ0OSPNS7n7YXy6xQdnaOU4KRW/Lne1EDf5IfWC/ih +bVAmhZMbcrkWWcsR6aCPG+2mV3zTD6AUzuKPal8Y +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG +A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv +b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw +MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i +YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT +aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ +jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp +xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp +1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG +snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ +U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8 +9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E +BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B +AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz +yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE +38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP +AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad +DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME +HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDdTCCAl2gAwIBAgILAgAAAAAA1ni3lAUwDQYJKoZIhvcNAQEEBQAwVzELMAkG +A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv +b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw +MDBaFw0xNDAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i +YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT +aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ +jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp +xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp +1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG +snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ +U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8 +9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIABjAdBgNVHQ4EFgQU +YHtmGkUNl8qJUC99BM00qP/8/UswDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0B +AQQFAAOCAQEArqqf/LfSyx9fOSkoGJ40yWxPbxrwZKJwSk8ThptgKJ7ogUmYfQq7 +5bCdPTbbjwVR/wkxKh/diXeeDy5slQTthsu0AD+EAk2AaioteAuubyuig0SDH81Q +gkwkr733pbTIWg/050deSY43lv6aiAU62cDbKYfmGZZHpzqmjIs8d/5GY6dT2iHR +rH5Jokvmw2dZL7OKDrssvamqQnw1wdh/1acxOk5jQzmvCLBhNIzTmKlDNPYPhyk7 +ncJWWJh3w/cbrPad+D6qp1RF8PX51TFl/mtYnHGzHtdS6jIX/EBgHcl5JLL2bP2o +Zg6C3ZjL2sJETy6ge/L3ayx2EYRGinij4w== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEKzCCAxOgAwIBAgIEOsylTDANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJE +SzEVMBMGA1UEChMMVERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQg +Um9vdCBDQTAeFw0wMTA0MDUxNjMzMTdaFw0yMTA0MDUxNzAzMTdaMEMxCzAJBgNV +BAYTAkRLMRUwEwYDVQQKEwxUREMgSW50ZXJuZXQxHTAbBgNVBAsTFFREQyBJbnRl +cm5ldCBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxLhA +vJHVYx/XmaCLDEAedLdInUaMArLgJF/wGROnN4NrXceO+YQwzho7+vvOi20jxsNu +Zp+Jpd/gQlBn+h9sHvTQBda/ytZO5GhgbEaqHF1j4QeGDmUApy6mcca8uYGoOn0a +0vnRrEvLznWv3Hv6gXPU/Lq9QYjUdLP5Xjg6PEOo0pVOd20TDJ2PeAG3WiAfAzc1 +4izbSysseLlJ28TQx5yc5IogCSEWVmb/Bexb4/DPqyQkXsN/cHoSxNK1EKC2IeGN +eGlVRGn1ypYcNIUXJXfi9i8nmHj9eQY6otZaQ8H/7AQ77hPv01ha/5Lr7K7a8jcD +R0G2l8ktCkEiu7vmpwIDAQABo4IBJTCCASEwEQYJYIZIAYb4QgEBBAQDAgAHMGUG +A1UdHwReMFwwWqBYoFakVDBSMQswCQYDVQQGEwJESzEVMBMGA1UEChMMVERDIElu +dGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTENMAsGA1UEAxME +Q1JMMTArBgNVHRAEJDAigA8yMDAxMDQwNTE2MzMxN1qBDzIwMjEwNDA1MTcwMzE3 +WjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUbGQBx/2FbazI2p5QCIUItTxWqFAw +HQYDVR0OBBYEFGxkAcf9hW2syNqeUAiFCLU8VqhQMAwGA1UdEwQFMAMBAf8wHQYJ +KoZIhvZ9B0EABBAwDhsIVjUuMDo0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4IBAQBO +Q8zR3R0QGwZ/t6T609lN+yOfI1Rb5osvBCiLtSdtiaHsmGnc540mgwV5dOy0uaOX +wTUA/RXaOYE6lTGQ3pfphqiZdwzlWqCE/xIWrG64jcN7ksKsLtB9KOy282A4aW8+ +2ARVPp7MVdK6/rtHBNcK2RYKNCn1WBPVT8+PVkuzHu7TmHnaCB4Mb7j4Fifvwm89 +9qNLPg7kbWzbO0ESm70NRyN/PErQr8Cv9u8btRXE64PECV90i9kR+8JWsTz4cMo0 +jUNAE4z9mQNUecYu6oah9jrUCbz0vGbMPVjQV0kK7iXiQe4T+Zs4NNEA9X7nlB38 +aQNiuJkFBT1reBK9sG9l +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEk +MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpH +bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX +DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD +QSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprlOQcJ +FspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAw +DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61F +uOJAf/sKbvu+M8k8o4TVMAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGX +kPoUVy0D7O48027KqGx2vKLeuwIgJ6iFJzWbVsaj8kfSt24bAgAXqmemFZHe+pTs +ewv4n4Q= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJC +TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0 +aWZpY2F0aW9uIEF1dGhvcml0eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0 +aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAzMTkxODMzMzNaFw0yMTAzMTcxODMz +MzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUw +IwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQDEyVR +dW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Yp +li4kVEAkOPcahdxYTMukJ0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2D +rOpm2RgbaIr1VxqYuvXtdj182d6UajtLF8HVj71lODqV0D1VNk7feVcxKh7YWWVJ +WCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeLYzcS19Dsw3sgQUSj7cug +F+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWenAScOospU +xbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCC +Ak4wPQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVv +dmFkaXNvZmZzaG9yZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREw +ggENMIIBCQYJKwYBBAG+WAABMIH7MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNl +IG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBh +c3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFy +ZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh +Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYI +KwYBBQUHAgEWFmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3T +KbkGGew5Oanwl4Rqy+/fMIGuBgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rq +y+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1p +dGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYD +VQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6tlCL +MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSk +fnIYj9lofFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf8 +7C9TqnN7Az10buYWnuulLsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1R +cHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2xgI4JVrmcGmD+XcHXetwReNDWXcG31a0y +mQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi5upZIof4l/UO/erMkqQW +xFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi5nrQNiOK +SnQ2+Q== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx +KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd +BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl +YyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgxMDAxMTA0MDE0WhcNMzMxMDAxMjM1 +OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy +aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50 +ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUd +AqSzm1nzHoqvNK38DcLZSBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiC +FoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/FvudocP05l03Sx5iRUKrERLMjfTlH6VJi +1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx9702cu+fjOlbpSD8DT6Iavq +jnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGVWOHAD3bZ +wI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGj +QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/ +WSA2AHmgoCJrjNXyYdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhy +NsZt+U2e+iKo4YFWz827n+qrkRk4r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPAC +uvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNfvNoBYimipidx5joifsFvHZVw +IEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR3p1m0IvVVGb6 +g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN +9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlP +BSeOE6Fuwg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAw +NzEUMBIGA1UECgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJv +b3QgQ0EgdjEwHhcNMDcxMDE4MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYD +VQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwWVGVsaWFTb25lcmEgUm9vdCBDQSB2 +MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+6yfwIaPzaSZVfp3F +VRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA3GV1 +7CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+X +Z75Ljo1kB1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+ +/jXh7VB7qTCNGdMJjmhnXb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs +81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxHoLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkm +dtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3F0fUTPHSiXk+TT2YqGHe +Oh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJoWjiUIMu +sDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4 +pgd7gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fs +slESl1MpWtTwEhDcTwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQ +arMCpgKIv7NHfirZ1fpoeDVNAgMBAAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYD +VR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qWDNXr+nuqF+gTEjANBgkqhkiG +9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNmzqjMDfz1mgbl +dxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx +0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1Tj +TQpgcmLNkQfWpb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBed +Y2gea+zDTYa4EzAvXUYNR0PVG6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7 +Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpcc41teyWRyu5FrgZLAMzTsVlQ2jqI +OylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOTJsjrDNYmiLbAJM+7 +vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2qReW +t88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcn +HL/EVlP6Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVx +SK236thZiNSQvxaz2emsWWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCB +qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf +Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw +MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV +BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3MDAwMDAwWhcNMzYw +NzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5j +LjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYG +A1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl +IG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsoPD7gFnUnMekz52hWXMJEEUMDSxuaPFs +W0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ1CRfBsDMRJSUjQJib+ta +3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGcq/gcfomk +6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6 +Sk/KaAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94J +NqR32HuHUETVPm4pafs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBA +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XP +r87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUFAAOCAQEAeRHAS7ORtvzw6WfU +DW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeEuzLlQRHAd9mz +YJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX +xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2 +/qxAeeWsEG89jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/ +LHbTY5xZ3Y+m4Q6gLkH3LpVHz7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7 +jVaMaA== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDhDCCAmygAwIBAgIBCTANBgkqhkiG9w0BAQUFADAzMQswCQYDVQQGEwJDTjER +MA8GA1UEChMIVW5pVHJ1c3QxETAPBgNVBAMTCFVDQSBSb290MB4XDTA0MDEwMTAw +MDAwMFoXDTI5MTIzMTAwMDAwMFowMzELMAkGA1UEBhMCQ04xETAPBgNVBAoTCFVu +aVRydXN0MREwDwYDVQQDEwhVQ0EgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBALNdB8qGJn1r4vs4CQ7MgsJqGgCiFV/W6dQBt1YDAVmP9ThpJHbC +XivF9iu/r/tB/Q9a/KvXg3BNMJjRnrJ2u5LWu+kQKGkoNkTo8SzXWHwk1n8COvCB +a2FgP/Qz3m3l6ihST/ypHWN8C7rqrsRoRuTej8GnsrZYWm0dLNmMOreIy4XU9+gD +Xv2yTVDo1h//rgI/i0+WITyb1yXJHT/7mLFZ5PCpO6+zzYUs4mBGzG+OoOvwNMXx +QhhgrhLtRnUc5dipllq+3lrWeGeWW5N3UPJuG96WUUqm1ktDdSFmjXfsAoR2XEQQ +th1hbOSjIH23jboPkXXHjd+8AmCoKai9PUMCAwEAAaOBojCBnzALBgNVHQ8EBAMC +AQYwDAYDVR0TBAUwAwEB/zBjBgNVHSUEXDBaBggrBgEFBQcDAQYIKwYBBQUHAwIG +CCsGAQUFBwMDBggrBgEFBQcDBAYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEFBQcD +BwYIKwYBBQUHAwgGCCsGAQUFBwMJMB0GA1UdDgQWBBTbHzXza0z/QjFkm827Wh4d +SBC37jANBgkqhkiG9w0BAQUFAAOCAQEAOGy3iPGt+lg3dNHocN6cJ1nL5BXXoMNg +14iABMUwTD3UGusGXllH5rxmy+AI/Og17GJ9ysDawXiv5UZv+4mCI4/211NmVaDe +JRI7cTYWVRJ2+z34VFsxugAG+H1V5ad2g6pcSpemKijfvcZsCyOVjjN/Hl5AHxNU +LJzltQ7dFyiuawHTUin1Ih+QOfTcYmjwPIZH7LgFRbu3DJaUxmfLI3HQjnQi1kHr +A6i26r7EARK1s11AdgYg1GS4KUYGis4fk5oQ7vuqWrTcL9Ury/bXBYSYBZELhPc9 ++tb5evosFeo2gkO3t7jj83EB7UNDogVFwygFBzXjAaU4HoDU18PZ3g== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCB +ijELMAkGA1UEBhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHly +aWdodCAoYykgMjAwNTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNl +ZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQSBDQTAeFw0w +NTEyMTExNjAzNDRaFw0zNzEyMTExNjA5NTFaMIGKMQswCQYDVQQGEwJDSDEQMA4G +A1UEChMHV0lTZUtleTEbMBkGA1UECxMSQ29weXJpZ2h0IChjKSAyMDA1MSIwIAYD +VQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBX +SVNlS2V5IEdsb2JhbCBSb290IEdBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAy0+zAJs9Nt350UlqaxBJH+zYK7LG+DKBKUOVTJoZIyEVRd7jyBxR +VVuuk+g3/ytr6dTqvirdqFEr12bDYVxgAsj1znJ7O7jyTmUIms2kahnBAbtzptf2 +w93NvKSLtZlhuAGio9RN1AU9ka34tAhxZK9w8RxrfvbDd50kc3vkDIzh2TbhmYsF +mQvtRTEJysIA2/dyoJaqlYfQjse2YXMNdmaM3Bu0Y6Kff5MTMPGhJ9vZ/yxViJGg +4E8HsChWjBgbl0SOid3gF27nKu+POQoxhILYQBRJLnpB5Kf+42TMwVlxSywhp1t9 +4B3RLoGbw9ho972WG6xwsRYUC9tguSYBBQIDAQABo1EwTzALBgNVHQ8EBAMCAYYw +DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUswN+rja8sHnR3JQmthG+IbJphpQw +EAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBAEuh/wuHbrP5wUOx +SPMowB0uyQlB+pQAHKSkq0lPjz0e701vvbyk9vImMMkQyh2I+3QZH4VFvbBsUfk2 +ftv1TDI6QU9bR8/oCy22xBmddMVHxjtqD6wU2zz0c5ypBd8A3HR4+vg1YFkCExh8 +vPtNsCBtQ7tgMHpnM1zFmdH4LTlSc/uMqpclXHLZCB6rTjzjgTGfA6b7wP4piFXa +hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZi +Fj4A4xylNoEYokxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ +/L7fCg0= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDlDCCAnygAwIBAgIQWAsFbFMk27JQVxhf+eWmUDANBgkqhkiG9w0BAQUFADAn +MQswCQYDVQQGEwJCRTEYMBYGA1UEAxMPQmVsZ2l1bSBSb290IENBMB4XDTAzMDEy +NjIzMDAwMFoXDTE0MDEyNjIzMDAwMFowJzELMAkGA1UEBhMCQkUxGDAWBgNVBAMT +D0JlbGdpdW0gUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AMihcekcRkJ5eHFvna6pqKsot03HIOswkVp19eLSz8hMFJhCWK3HEcVAQGpa+XQS +J4fpnOVxTiIs0RIYqjBeoiG52bv/9nTrMQHnO35YD5EWTXaJqAFPrSJmcPpLHZXB +MFjqvNll2Jq0iOtJRlLf0lMVdssUXRlJsW9q09P9vMIt7EU/CT9YvvzU7wCMgTVy +v/cY6pZifSsofxVsY9LKyn0FrMhtB20yvmi4BUCuVJhWPmbxMOjvxKuTXgfeMo8S +dKpbNCNUwOpszv42kqgJF+qhLc9s44Qd3ocuMws8dOIhUDiVLlzg5cYx+dtA+mqh +pIqTm6chBocdJ9PEoclMsG8CAwEAAaOBuzCBuDAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zBCBgNVHSAEOzA5MDcGBWA4AQEBMC4wLAYIKwYBBQUHAgEW +IGh0dHA6Ly9yZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMB0GA1UdDgQWBBQQ8AxW +m2HqVzq2NZdtn925FI7b5jARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAU +EPAMVpth6lc6tjWXbZ/duRSO2+YwDQYJKoZIhvcNAQEFBQADggEBAMhtIlGKYfgP +lm7VILKB+MbcoxYA2s1q52sq+llIp0xJN9dzoWoBZV4yveeX09AuPHPTjHuD79ZC +wT+oqV0PN7p20kC9zC0/00RBSZz9Wyn0AiMiW3Ebv1jZKE4tRfTa57VjRUQRDSp/ +M382SbTObqkCMa5c/ciJv0J71/Fg8teH9lcuen5qE4Ad3OPQYx49cTGxYNSeCMqr +8JTHSHVUgfMbrXec6LKP24OsjzRr6L/D2fVDw2RV6xq9NoY2uiGMlxoh1OotO6y6 +7Kcdq765Sps1LxxcHVGnH1TtEpf/8m6HfUbJdNbv6z195lluBpQE5KJVhzgoaiJe +4r50ErAEQyo= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE +BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz +dCBDb21tZXJjaWFsMB4XDTEwMDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDEL +MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp +cm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6EqdbDuKP +Hx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yr +ba0F8PrVC8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPAL +MeIrJmqbTFeurCA+ukV6BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1 +yHp52UKqK39c/s4mT6NmgTWvRLpUHhwwMmWd5jyTXlBOeuM61G7MGvv50jeuJCqr +VwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNVHQ4EFgQUnZPGU4teyq8/ +nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ +KoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYG +XUPGhi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNj +vbz4YYCanrHOQnDiqX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivt +Z8SOyUOyXGsViQK8YvxO8rUzqrJv0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9g +N53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0khsUlHRUe072o0EclNmsxZt9YC +nlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRF +MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBD +bGFzcyAzIENBIDIgRVYgMjAwOTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUw +NDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNV +BAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAwOTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfSegpn +ljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM0 +3TP1YtHhzRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6Z +qQTMFexgaDbtCHu39b+T7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lR +p75mpoo6Kr3HGrHhFPC+Oh25z1uxav60sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8 +HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure3511H3a6UCAwEAAaOCASQw +ggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyvcop9Ntea +HNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFw +Oi8vZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xh +c3MlMjAzJTIwQ0ElMjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1E +RT9jZXJ0aWZpY2F0ZXJldm9jYXRpb25saXN0MEagRKBChkBodHRwOi8vd3d3LmQt +dHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xhc3NfM19jYV8yX2V2XzIwMDku +Y3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+PPoeUSbrh/Yp +3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05 +nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNF +CSuGdXzfX2lXANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7na +xpeG0ILD5EJt/rDiZE4OJudANCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqX +KVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVvw9y4AyHqnxbxLFS1 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIF2TCCA8GgAwIBAgIQHp4o6Ejy5e/DfEoeWhhntjANBgkqhkiG9w0BAQsFADBk +MQswCQYDVQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0 +YWwgQ2VydGlmaWNhdGUgU2VydmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3Qg +Q0EgMjAeFw0xMTA2MjQwODM4MTRaFw0zMTA2MjUwNzM4MTRaMGQxCzAJBgNVBAYT +AmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGlnaXRhbCBDZXJ0aWZp +Y2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAyMIICIjAN +BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAlUJOhJ1R5tMJ6HJaI2nbeHCOFvEr +jw0DzpPMLgAIe6szjPTpQOYXTKueuEcUMncy3SgM3hhLX3af+Dk7/E6J2HzFZ++r +0rk0X2s682Q2zsKwzxNoysjL67XiPS4h3+os1OD5cJZM/2pYmLcX5BtS5X4HAB1f +2uY+lQS3aYg5oUFgJWFLlTloYhyxCwWJwDaCFCE/rtuh/bxvHGCGtlOUSbkrRsVP +ACu/obvLP+DHVxxX6NZp+MEkUp2IVd3Chy50I9AU/SpHWrumnf2U5NGKpV+GY3aF +y6//SSj8gO1MedK75MDvAe5QQQg1I3ArqRa0jG6F6bYRzzHdUyYb3y1aSgJA/MTA +tukxGggo5WDDH8SQjhBiYEQN7Aq+VRhxLKX0srwVYv8c474d2h5Xszx+zYIdkeNL +6yxSNLCK/RJOlrDrcH+eOfdmQrGrrFLadkBXeyq96G4DsguAhYidDMfCd7Camlf0 +uPoTXGiTOmekl9AbmbeGMktg2M7v0Ax/lZ9vh0+Hio5fCHyqW/xavqGRn1V9TrAL +acywlKinh/LTSlDcX3KwFnUey7QYYpqwpzmqm59m2I2mbJYV4+by+PGDYmy7Velh +k6M99bFXi08jsJvllGov34zflVEpYKELKeRcVVi3qPyZ7iVNTA6z00yPhOgpD/0Q +VAKFyPnlw4vP5w8CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0hBBYw +FDASBgdghXQBUwIBBgdghXQBUwIBMBIGA1UdEwEB/wQIMAYBAf8CAQcwHQYDVR0O +BBYEFE0mICKJS9PVpAqhb97iEoHF8TwuMB8GA1UdIwQYMBaAFE0mICKJS9PVpAqh +b97iEoHF8TwuMA0GCSqGSIb3DQEBCwUAA4ICAQAyCrKkG8t9voJXiblqf/P0wS4R +fbgZPnm3qKhyN2abGu2sEzsOv2LwnN+ee6FTSA5BesogpxcbtnjsQJHzQq0Qw1zv +/2BZf82Fo4s9SBwlAjxnffUy6S8w5X2lejjQ82YqZh6NM4OKb3xuqFp1mrjX2lhI +REeoTPpMSQpKwhI3qEAMw8jh0FcNlzKVxzqfl9NX+Ave5XLzo9v/tdhZsnPdTSpx +srpJ9csc1fV5yJmz/MFMdOO0vSk3FQQoHt5FRnDsr7p4DooqzgB53MBfGWcsa0vv +aGgLQ+OswWIJ76bdZWGgr4RVSJFSHMYlkSrQwSIjYVmvRRGFHQEkNI/Ps/8XciAT +woCqISxxOQ7Qj1zB09GOInJGTB2Wrk9xseEFKZZZ9LuedT3PDTcNYtsmjGOpI99n +Bjx8Oto0QuFmtEYE3saWmA9LSHokMnWRn6z3aOkquVVlzl1h0ydw2Df+n7mvoC5W +t6NlUe07qxS/TFED6F+KBZvuim6c779o+sjaC+NCydAXFJy3SuCvkychVSa1ZC+N +8f+mQAWFBVzKBxlcCxMoTFh/wqXvRdpg065lYZ1Tg3TCrvJcwhbtkj6EPnNgiLx2 +9CzP0H1907he0ZESEOnN3col49XtmS++dYFLJPlFRpTJKSFTnCZFqhMX5OfNeOI5 +wSsSnqaeG8XmDtkx2Q== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEZjCCA06gAwIBAgIQRL4Mi1AAJLQR0zYt4LNfGzANBgkqhkiG9w0BAQUFADCB +lTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug +Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho +dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHTAbBgNVBAMTFFVUTi1VU0VSRmlyc3Qt +T2JqZWN0MB4XDTk5MDcwOTE4MzEyMFoXDTE5MDcwOTE4NDAzNlowgZUxCzAJBgNV +BAYTAlVTMQswCQYDVQQIEwJVVDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkxHjAc +BgNVBAoTFVRoZSBVU0VSVFJVU1QgTmV0d29yazEhMB8GA1UECxMYaHR0cDovL3d3 +dy51c2VydHJ1c3QuY29tMR0wGwYDVQQDExRVVE4tVVNFUkZpcnN0LU9iamVjdDCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6qgT+jo2F4qjEAVZURnicP +HxzfOpuCaDDASmEd8S8O+r5596Uj71VRloTN2+O5bj4x2AogZ8f02b+U60cEPgLO +KqJdhwQJ9jCdGIqXsqoc/EHSoTbL+z2RuufZcDX65OeQw5ujm9M89RKZd7G3CeBo +5hy485RjiGpq/gt2yb70IuRnuasaXnfBhQfdDWy/7gbHd2pBnqcP1/vulBe3/IW+ +pKvEHDHd17bR5PDv3xaPslKT16HUiaEHLr/hARJCHhrh2JU022R5KP+6LhHC5ehb +kkj7RwvCbNqtMoNB86XlQXD9ZZBt+vpRxPm9lisZBCzTbafc8H9vg2XiaquHhnUC +AwEAAaOBrzCBrDALBgNVHQ8EBAMCAcYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E +FgQU2u1kdBScFDyr3ZmpvVsoTYs8ydgwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDov +L2NybC51c2VydHJ1c3QuY29tL1VUTi1VU0VSRmlyc3QtT2JqZWN0LmNybDApBgNV +HSUEIjAgBggrBgEFBQcDAwYIKwYBBQUHAwgGCisGAQQBgjcKAwQwDQYJKoZIhvcN +AQEFBQADggEBAAgfUrE3RHjb/c652pWWmKpVZIC1WkDdIaXFwfNfLEzIR1pp6ujw +NTX00CXzyKakh0q9G7FzCL3Uw8q2NbtZhncxzaeAFK4T7/yxSPlrJSUtUbYsbUXB +mMiKVl0+7kNOPmsnjtA6S4ULX9Ptaqd1y9Fahy85dRNacrACgZ++8A+EVCBibGnU +4U3GDZlDAQ0Slox4nb9QorFEqmrPF3rPbw/U+CRVX/A0FklmPlBGyWNxODFiuGK5 +81OtbLUrohKqGU8J2l7nk8aOFAj+8DCAGKCGhU3IfdeLA/5u1fedFqySLKAj5ZyR +Uh+U3xeUc8OzwcFxBSAAeL0TUh2oPs0AH8g= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDjjCCAnagAwIBAgIIKv++n6Lw6YcwDQYJKoZIhvcNAQEFBQAwKDELMAkGA1UE +BhMCQkUxGTAXBgNVBAMTEEJlbGdpdW0gUm9vdCBDQTIwHhcNMDcxMDA0MTAwMDAw +WhcNMjExMjE1MDgwMDAwWjAoMQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1 +bSBSb290IENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMZzQh6S +/3UPi790hqc/7bIYLS2X+an7mEoj39WN4IzGMhwWLQdC1i22bi+n9fzGhYJdld61 +IgDMqFNAn68KNaJ6x+HK92AQZw6nUHMXU5WfIp8MXW+2QbyM69odRr2nlL/zGsvU ++40OHjPIltfsjFPekx40HopQcSZYtF3CiInaYNKJIT/e1wEYNm7hLHADBGXvmAYr +XR5i3FVr/mZkIV/4L+HXmymvb82fqgxG0YjFnaKVn6w/Fa7yYd/vw2uaItgscf1Y +HewApDgglVrH1Tdjuk+bqv5WRi5j2Qsj1Yr6tSPwiRuhFA0m2kHwOI8w7QUmecFL +TqG4flVSOmlGhHUCAwEAAaOBuzCBuDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ +BAUwAwEB/zBCBgNVHSAEOzA5MDcGBWA4CQEBMC4wLAYIKwYBBQUHAgEWIGh0dHA6 +Ly9yZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMB0GA1UdDgQWBBSFiuv0xbu+DlkD +lN7WgAEV4xCcOTARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUhYrr9MW7 +vg5ZA5Te1oABFeMQnDkwDQYJKoZIhvcNAQEFBQADggEBAFHYhd27V2/MoGy1oyCc +UwnzSgEMdL8rs5qauhjyC4isHLMzr87lEwEnkoRYmhC598wUkmt0FoqW6FHvv/pK +JaeJtmMrXZRY0c8RcrYeuTlBFk0pvDVTC9rejg7NqZV3JcqUWumyaa7YwBO+mPyW +nIR/VRPmPIfjvCCkpDZoa01gZhz5v6yAlGYuuUGK02XThIAC71AdXkbc98m6tTR8 +KvPG2F9fVJ3bTc0R5/0UAoNmXsimABKgX77OFP67H6dh96tK8QYUn8pJQsKpvO2F +sauBQeYNxUJpU4c5nUwfAA4+Bw11V0SoU7Q2dmSZ3G7rPUZuFF1eR1ONeE3gJ7uO +hXY= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFyjCCA7KgAwIBAgIEAJiWjDANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJO +TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFh +dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQSAtIEcyMB4XDTA4MDMyNjExMTgxN1oX +DTIwMDMyNTExMDMxMFowWjELMAkGA1UEBhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRl +ciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5lZGVybGFuZGVuIFJv +b3QgQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMVZ5291 +qj5LnLW4rJ4L5PnZyqtdj7U5EILXr1HgO+EASGrP2uEGQxGZqhQlEq0i6ABtQ8Sp +uOUfiUtnvWFI7/3S4GCI5bkYYCjDdyutsDeqN95kWSpGV+RLufg3fNU254DBtvPU +Z5uW6M7XxgpT0GtJlvOjCwV3SPcl5XCsMBQgJeN/dVrlSPhOewMHBPqCYYdu8DvE +pMfQ9XQ+pV0aCPKbJdL2rAQmPlU6Yiile7Iwr/g3wtG61jj99O9JMDeZJiFIhQGp +5Rbn3JBV3w/oOM2ZNyFPXfUib2rFEhZgF1XyZWampzCROME4HYYEhLoaJXhena/M +UGDWE4dS7WMfbWV9whUYdMrhfmQpjHLYFhN9C0lK8SgbIHRrxT3dsKpICT0ugpTN +GmXZK4iambwYfp/ufWZ8Pr2UuIHOzZgweMFvZ9C+X+Bo7d7iscksWXiSqt8rYGPy +5V6548r6f1CGPqI0GAwJaCgRHOThuVw+R7oyPxjMW4T182t0xHJ04eOLoEq9jWYv +6q012iDTiIJh8BIitrzQ1aTsr1SIJSQ8p22xcik/Plemf1WvbibG/ufMQFxRRIEK +eN5KzlW/HdXZt1bv8Hb/C3m1r737qWmRRpdogBQ2HbN/uymYNqUg+oJgYjOk7Na6 +B6duxc8UpufWkjTYgfX8HV2qXB72o007uPc5AgMBAAGjgZcwgZQwDwYDVR0TAQH/ +BAUwAwEB/zBSBgNVHSAESzBJMEcGBFUdIAAwPzA9BggrBgEFBQcCARYxaHR0cDov +L3d3dy5wa2lvdmVyaGVpZC5ubC9wb2xpY2llcy9yb290LXBvbGljeS1HMjAOBgNV +HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJFoMocVHYnitfGsNig0jQt8YojrMA0GCSqG +SIb3DQEBCwUAA4ICAQCoQUpnKpKBglBu4dfYszk78wIVCVBR7y29JHuIhjv5tLyS +CZa59sCrI2AGeYwRTlHSeYAz+51IvuxBQ4EffkdAHOV6CMqqi3WtFMTC6GY8ggen +5ieCWxjmD27ZUD6KQhgpxrRW/FYQoAUXvQwjf/ST7ZwaUb7dRUG/kSS0H4zpX897 +IZmflZ85OkYcbPnNe5yQzSipx6lVu6xiNGI1E0sUOlWDuYaNkqbG9AclVMwWVxJK +gnjIFNkXgiYtXSAfea7+1HAWFpWD2DU5/1JddRwWxRNVz0fMdWVSSt7wsKfkCpYL ++63C4iWEst3kvX5ZbJvw8NjnyvLplzh+ib7M+zkXYT9y2zqR2GUBGR2tUKRXCnxL +vJxxcypFURmFzI79R6d0lR2o0a9OF7FpJsKqeFdbxU2n5Z4FF5TKsl+gSRiNNOkm +bEgeqmiSBeGCc1qb3AdbCG19ndeNIdn8FCCqwkXfP+cAslHkwvgFuXkajDTznlvk +N1trSt8sV4pAWja63XVECDdCcAz+3F4hoKOKwJCcaNpQ5kUQR3i2TtJlycM33+FC +Y7BXN0Ute4qcvwXqZVUz9zkQxSgqIXobisQk+T8VyJoVIPVVYpbtbZNQvOSqeK3Z +ywplh6ZmwcSBo3c6WB4L7oOLnR7SUqTMHW+wmG2UMbX4cQrcufx9MmDm66+KAQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEk +MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpH +bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX +DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD +QSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6SFkc +8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8ke +hOvRnkmSh5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYI +KoZIzj0EAwMDaAAwZQIxAOVpEslu28YxuglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg +515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7yFz9SO8NdCKoCOJuxUnO +xwy8p2Fp8fc74SrL+SvzZpA3 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYD +VQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0 +IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3 +MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD +aGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0wODA4MDExMjMxNDBaFw0zODA3MzEx +MjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3Vy +cmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAG +A1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAl +BgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZI +hvcNAQEBBQADggIPADCCAgoCggIBAMDfVtPkOpt2RbQT2//BthmLN0EYlVJH6xed +KYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXfXjaOcNFccUMd2drvXNL7 +G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0ZJJ0YPP2 +zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4 +ddPB/gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyG +HoiMvvKRhI9lNNgATH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2 +Id3UwD2ln58fQ1DJu7xsepeY7s2MH/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3V +yJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfeOx2YItaswTXbo6Al/3K1dh3e +beksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSFHTynyQbehP9r +6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh +wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsog +zCtLkykPAgMBAAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQW +BBS5CcqcHtvTbDprru1U8VuTBjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDpr +ru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UEBhMCRVUxQzBBBgNVBAcTOk1hZHJp +ZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJmaXJtYS5jb20vYWRk +cmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJmaXJt +YSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiC +CQDJzdPp1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCow +KAYIKwYBBQUHAgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZI +hvcNAQEFBQADggIBAICIf3DekijZBZRG/5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZ +UohwEurdPfWbU1Rv4WCiqAm57OtZfMY18dwY6fFn5a+6ReAJ3spED8IXDneRRXoz +X1+WLGiLwUePmJs9wOzL9dWCkoQ10b42OFZyMVtHLaoXpGNR6woBrX/sdZ7LoR/x +fxKxueRkf2fWIyr0uDldmOghp+G9PUIadJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVz +a2Mg9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJjUhjxsYjV5KTXjXBjfkK9yyd +Yhz2rXzdpjEetrHHfoUm+qRqtdpjMNHvkzeyZi99Bffnt0uYlDXA2TopwZ2yUDMd +SqlapskD7+3056huirRXhOukP9DuqqqHW2Pok+JrqNS4cnhrG+055F3Lm6qH1U9O +AP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETrP3iZ8ntxPjzxmKfFGBI/5rso +M0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVqc5iJWzouE4ge +v8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z +09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIF3zCCA8egAwIBAgIOGTMAAQACKBqaBLzyVUUwDQYJKoZIhvcNAQEFBQAwejEL +MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNV +BAsTG1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQTEnMCUGA1UEAxMeVEMgVHJ1 +c3RDZW50ZXIgVW5pdmVyc2FsIENBIElJMB4XDTA2MDMyMjE1NTgzNFoXDTMwMTIz +MTIyNTk1OVowejELMAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVy +IEdtYkgxJDAiBgNVBAsTG1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQTEnMCUG +A1UEAxMeVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBIElJMIICIjANBgkqhkiG +9w0BAQEFAAOCAg8AMIICCgKCAgEAi9R3azRs5TbYalxeOO781R15Azt7g2JEgk6I +7d6D/+7MUGIFBZWZdpj2ufJf2AaRksL2LWYXH/1TA+iojWOpbuHWG4y8mLOLO9Tk +Lsp9hUkmW3m4GotAnn+7yT9jLM/RWny6KCJBElpN+Rd3/IX9wkngKhh/6aAsnPlE +/AxoOUL1JwW+jhV6YJ3wO8c85j4WvK923mq3ouGrRkXrjGV90ZfzlxElq1nroCLZ +gt2Y7X7i+qBhCkoy3iwX921E6oFHWZdXNwM53V6CItQzuPomCba8OYgvURVOm8M7 +3xOCiN1LNPIz1pDp81PcNXzAw9l8eLPNcD+NauCjgUjkKa1juPD8KGQ7mbN9/pqd +iPaZIgiRRxaJNXhdd6HPv0nh/SSUK2k2e+gc5iqQilvVOzRZQtxtz7sPQRxVzfUN +Wy4WIibvYR6X/OJTyM9bo8ep8boOhhLLE8oVx+zkNo3aXBM9ZdIOXXB03L+PemrB +Lg/Txl4PK1lszGFs/sBhTtnmT0ayWuIZFHCE+CAA7QGnl37DvRJckiMXoKUdRRcV +I5qSCLUiiI3cKyTr4LEXaNOvYb3ZhXj2jbp4yjeNY77nrB/fpUcJucglMVRGURFV +DYlcjdrSGC1z8rjVJ/VIIjfRYvd7Dcg4i6FKsPzQ8eu3hmPn4A5zf/1yUbXpfeJV +BWR4Z38CAwEAAaNjMGEwHwYDVR0jBBgwFoAUzdeQoW6jv9sw1toyJZAM5jkegGUw +DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFM3XkKFu +o7/bMNbaMiWQDOY5HoBlMA0GCSqGSIb3DQEBBQUAA4ICAQB+FojoEw42zG4qhQc4 +xlaJeuNHIWZMUAgxWlHQ/KZeFHXeTDvs8e3MfhEHSmHu6rOOOqQzxu2KQmZP8Tx7 +yaUFQZmx7Cxb7tyW0ohTS3g0uW7muw/FeqZ8Dhjfbw90TNGp8aHp2FRkzF6WeKJW +GsFzshXGVwXf2vdIJIqOf2qp+U3pPmrOYCx9LZAI9mOPFdAtnIz/8f38DBZQVhT7 +upeG7rRJA1TuG1l/MDoCgoYhrv7wFfLfToPmmcW6NfcgkIw47XXP4S73BDD7Ua2O +giRAyn0pXdXZ92Vk/KqfdLh9kl3ShCngE+qK99CrxK7vFcXCifJ7tjtJmGHzTnKR +N4xJkunI7Cqg90lufA0kxmts8jgvynAF5X/fxisrgIDV2m/LQLvYG/AkyRDIRAJ+ +LtOYqqIN8SvQ2vqOHP9U6OFKbt2o1ni1N6WsZNUUI8cOpevhCTjXwHxgpV2Yj4wC +1dxWqPNNWKkL1HxkdAEy8t8PSoqpAqKiHYR3wvHMl700GXRd4nQ+dSf3r7/ufA5t +VIimVuImrTESPB5BeW0X6hNeH/Vcn0lZo7Ivo0LD+qh+v6WfSMlgYmIK371F3uNC +tVGW/cT1Gpm4UqJEzS1hjBWPgdVdotSQPYxuQGHDWV3Y2eH2dEcieXR92sqjbzcV +NvAsGnE8EXbfXRo+VGN4a2V+Hw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIF2TCCA8GgAwIBAgIQXAuFXAvnWUHfV8w/f52oNjANBgkqhkiG9w0BAQUFADBk +MQswCQYDVQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0 +YWwgQ2VydGlmaWNhdGUgU2VydmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3Qg +Q0EgMTAeFw0wNTA4MTgxMjA2MjBaFw0yNTA4MTgyMjA2MjBaMGQxCzAJBgNVBAYT +AmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGlnaXRhbCBDZXJ0aWZp +Y2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAxMIICIjAN +BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0LmwqAzZuz8h+BvVM5OAFmUgdbI9 +m2BtRsiMMW8Xw/qabFbtPMWRV8PNq5ZJkCoZSx6jbVfd8StiKHVFXqrWW/oLJdih +FvkcxC7mlSpnzNApbjyFNDhhSbEAn9Y6cV9Nbc5fuankiX9qUvrKm/LcqfmdmUc/ +TilftKaNXXsLmREDA/7n29uj/x2lzZAeAR81sH8A25Bvxn570e56eqeqDFdvpG3F +EzuwpdntMhy0XmeLVNxzh+XTF3xmUHJd1BpYwdnP2IkCb6dJtDZd0KTeByy2dbco +kdaXvij1mB7qWybJvbCXc9qukSbraMH5ORXWZ0sKbU/Lz7DkQnGMU3nn7uHbHaBu +HYwadzVcFh4rUx80i9Fs/PJnB3r1re3WmquhsUvhzDdf/X/NTa64H5xD+SpYVUNF +vJbNcA78yeNmuk6NO4HLFWR7uZToXTNShXEuT46iBhFRyePLoW4xCGQMwtI89Tbo +19AOeCMgkckkKmUpWyL3Ic6DXqTz3kvTaI9GdVyDCW4pa8RwjPWd1yAv/0bSKzjC +L3UcPX7ape8eYIVpQtPM+GP+HkM5haa2Y0EQs3MevNP6yn0WR+Kn1dCjigoIlmJW +bjTb2QK5MHXjBNLnj8KwEUAKrNVxAmKLMb7dxiNYMUJDLXT5xp6mig/p/r+D5kNX +JLrvRjSq1xIBOO0CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0hBBYw +FDASBgdghXQBUwABBgdghXQBUwABMBIGA1UdEwEB/wQIMAYBAf8CAQcwHwYDVR0j +BBgwFoAUAyUv3m+CATpcLNwroWm1Z9SM0/0wHQYDVR0OBBYEFAMlL95vggE6XCzc +K6FptWfUjNP9MA0GCSqGSIb3DQEBBQUAA4ICAQA1EMvspgQNDQ/NwNurqPKIlwzf +ky9NfEBWMXrrpA9gzXrzvsMnjgM+pN0S734edAY8PzHyHHuRMSG08NBsl9Tpl7Ik +Vh5WwzW9iAUPWxAaZOHHgjD5Mq2eUCzneAXQMbFamIp1TpBcahQq4FJHgmDmHtqB +sfsUC1rxn9KVuj7QG9YVHaO+htXbD8BJZLsuUBlL0iT43R4HVtA4oJVwIHaM190e +3p9xxCPvgxNcoyQVTSlAPGrEqdi3pkSlDfTgnXceQHAm/NrZNuR55LU/vJtlvrsR +ls/bxig5OgjOR1tTWsWZ/l2p3e9M1MalrQLmjAcSHm8D0W+go/MpvRLHUKKwf4ip +mXeascClOS5cfGniLLDqN2qk4Vrh9VDlg++luyqI54zb/W1elxmofmZ1a3Hqv7HH +b6D0jqTsNFFbjCYDcKF31QESVwA12yPeDooomf2xEG9L/zgtYE4snOtnta1J7ksf +rK/7DZBaZmBwXarNeNQk7shBoJMBkpxqnvy5JMWzFYJ+vq6VK+uxwNrjAWALXmms +hFZhvnEX/h0TD/7Gh0Xp/jKgGg0TpJRVcaUWi7rKibCyx/yP2FS1k2Kdzs9Z+z0Y +zirLNRWCXf9UIltxUvu3yf5gmwBBZPCqKuy2QkPOiWaByIufOVQDJdMWNY6E0F/6 +MBr1mmz0DlP5OlvRHA== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCB +kzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug +Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho +dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZBgNVBAMTElVUTiAtIERBVEFDb3Jw +IFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBaMIGTMQswCQYDVQQG +EwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYD +VQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cu +dXNlcnRydXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjAN +BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6 +E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ysraP6LnD43m77VkIVni5c7yPeIbkFdicZ +D0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlowHDyUwDAXlCCpVZvNvlK +4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA9P4yPykq +lXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulW +bfXv33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQAB +o4GrMIGoMAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRT +MtGzz3/64PGgXYVOktKeRR20TzA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3Js +LnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dDLmNybDAqBgNVHSUEIzAhBggr +BgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3DQEBBQUAA4IB +AQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft +Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyj +j98C5OBxOvG0I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVH +KWss5nbZqSl9Mt3JNjy9rjXxEZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv +2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwPDPafepE39peC4N1xaf92P2BNPM/3 +mfnGV/TJVTl4uix5yaaIK/QI +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEBDCCAuygAwIBAgIIGHqpqMKWIQwwDQYJKoZIhvcNAQELBQAwYjELMAkGA1UE +BhMCVVMxEzARBgNVBAoTCkFwcGxlIEluYy4xJjAkBgNVBAsTHUFwcGxlIENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5MRYwFAYDVQQDEw1BcHBsZSBSb290IENBMB4XDTEy +MDIwMTIyMTIxNVoXDTI3MDIwMTIyMTIxNVoweTEtMCsGA1UEAwwkRGV2ZWxvcGVy +IElEIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSYwJAYDVQQLDB1BcHBsZSBDZXJ0 +aWZpY2F0aW9uIEF1dGhvcml0eTETMBEGA1UECgwKQXBwbGUgSW5jLjELMAkGA1UE +BhMCVVMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCJdk8GW5pB7qUj +KwKjX9dzP8A1sIuECj8GJH+nlT/rTw6Tr7QO0Mg+5W0Ysx/oiUe/1wkI5P9WmCkV +55SduTWjCs20wOHiYPTK7Cl4RWlpYGtfipL8niPmOsIiszFPHLrytjRZQu6wqQID +GJEEtrN4LjMfgEUNRW+7Dlpbfzrn2AjXCw4ybfuGNuRsq8QRinCEJqqfRNHxuMZ7 +lBebSPcLWBa6I8WfFTl+yl3DMl8P4FJ/QOq+rAhklVvJGpzlgMofakQcbD7EsCYf +Hex7r16gaj1HqVgSMT8gdihtHRywwk4RaSaLy9bQEYLJTg/xVnTQ2QhLZniiq6yn +4tJMh1nJAgMBAAGjgaYwgaMwHQYDVR0OBBYEFFcX7aLP3HyYoRDg/L6HLSzy4xdU +MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUK9BpR5R2Cf70a40uQKb3R01/ +CF4wLgYDVR0fBCcwJTAjoCGgH4YdaHR0cDovL2NybC5hcHBsZS5jb20vcm9vdC5j +cmwwDgYDVR0PAQH/BAQDAgGGMBAGCiqGSIb3Y2QGAgYEAgUAMA0GCSqGSIb3DQEB +CwUAA4IBAQBCOXRrodzGpI83KoyzHQpEvJUsf7xZuKxh+weQkjK51L87wVA5akR0 +ouxbH3Dlqt1LbBwjcS1f0cWTvu6binBlgp0W4xoQF4ktqM39DHhYSQwofzPuAHob +tHastrW7T9+oG53IGZdKC1ZnL8I+trPEgzrwd210xC4jUe6apQNvYPSlSKcGwrta +4h8fRkV+5Jf1JxC3ICJyb3LaxlB1xT0lj12jAOmfNoxIOY+zO+qQgC6VmmD0eM70 +DgpTPqL6T9geroSVjTK8Vk2J6XgY4KyaQrp6RhuEoonOFOiI0ViL9q5WxCwFKkWv +C9lLqQIPNKyIx2FViUTJJ3MH7oLlTvVw +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEvTCCA6WgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBhTELMAkGA1UEBhMCVVMx +IDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxs +cyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9v +dCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDcxMjEzMTcwNzU0WhcNMjIxMjE0 +MDAwNzU0WjCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdl +bGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQD +DC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkw +ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDub7S9eeKPCCGeOARBJe+r +WxxTkqxtnt3CxC5FlAM1iGd0V+PfjLindo8796jE2yljDpFoNoqXjopxaAkH5OjU +Dk/41itMpBb570OYj7OeUt9tkTmPOL13i0Nj67eT/DBMHAGTthP796EfvyXhdDcs +HqRePGj4S78NuR4uNuip5Kf4D8uCdXw1LSLWwr8L87T8bJVhHlfXBIEyg1J55oNj +z7fLY4sR4r1e6/aN7ZVyKLSsEmLpSjPmgzKuBXWVvYSV2ypcm44uDLiBK0HmOFaf +SZtsdvqKXfcBeYF8wYNABf5x/Qw/zE5gCQ5lRxAvAcAFP4/4s0HvWkJ+We/Slwxl +AgMBAAGjggE0MIIBMDAPBgNVHRMBAf8EBTADAQH/MDkGA1UdHwQyMDAwLqAsoCqG +KGh0dHA6Ly9jcmwucGtpLndlbGxzZmFyZ28uY29tL3dzcHJjYS5jcmwwDgYDVR0P +AQH/BAQDAgHGMB0GA1UdDgQWBBQmlRkQ2eihl5H/3BnZtQQ+0nMKajCBsgYDVR0j +BIGqMIGngBQmlRkQ2eihl5H/3BnZtQQ+0nMKaqGBi6SBiDCBhTELMAkGA1UEBhMC +VVMxIDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNX +ZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMg +Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHmCAQEwDQYJKoZIhvcNAQEFBQADggEB +ALkVsUSRzCPIK0134/iaeycNzXK7mQDKfGYZUMbVmO2rvwNa5U3lHshPcZeG1eMd +/ZDJPHV3V3p9+N701NX3leZ0bh08rnyd2wIDBSxxSyU+B+NemvVmFymIGjifz6pB +A4SXa5M4esowRBskRDPQ5NHcKDj0E0M1NSljqHyita04pO2t/caaH/+Xc/77szWn +k4bGdpEA5qxRFsQnMlzbc9qlk1eOPm01JghZ1edE13YgY+esE2fDbbFwRnzVlhE9 +iW9dqKHrjQrawx0zbKPqZxmamX9LPYNRKh3KL4YMon4QLSvUFpULB6ouFJJJtylv +2G0xffX8oRAHh84vWdw+WNs= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICqDCCAi2gAwIBAgIQIW4zpcvTiKRvKQe0JzzE2DAKBggqhkjOPQQDAzCBlDEL +MAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYD +VQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBD +bGFzcyAxIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0g +RzQwHhcNMTExMDA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBlDELMAkGA1UEBhMC +VVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZTeW1h +bnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBDbGFzcyAxIFB1 +YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAATXZrUb266zYO5G6ohjdTsqlG3zXxL24w+etgoUU0hS +yNw6s8tIICYSTvqJhNTfkeQpfSgB2dsYQ2mhH7XThhbcx39nI9/fMTGDAzVwsUu3 +yBe7UcvclBfb6gk7dhLeqrWjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E +BTADAQH/MB0GA1UdDgQWBBRlwI0l9Qy6l3eQP54u4Fr1ztXh5DAKBggqhkjOPQQD +AwNpADBmAjEApa7jRlP4mDbjIvouKEkN7jB+M/PsP3FezFWJeJmssv3cHFwzjim5 +axfIEWi13IMHAjEAnMhE2mnCNsNUGRCFAtqdR+9B52wmnQk9922Q0QVEL7C8g5No +8gxFSTm/mQQc0xCg +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIID3TCCAsWgAwIBAgIOHaIAAQAC7LdggHiNtgYwDQYJKoZIhvcNAQEFBQAweTEL +MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNV +BAsTG1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQTEmMCQGA1UEAxMdVEMgVHJ1 +c3RDZW50ZXIgVW5pdmVyc2FsIENBIEkwHhcNMDYwMzIyMTU1NDI4WhcNMjUxMjMx +MjI1OTU5WjB5MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIg +R21iSDEkMCIGA1UECxMbVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBMSYwJAYD +VQQDEx1UQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0EgSTCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBAKR3I5ZEr5D0MacQ9CaHnPM42Q9e3s9B6DGtxnSR +JJZ4Hgmgm5qVSkr1YnwCqMqs+1oEdjneX/H5s7/zA1hV0qq34wQi0fiU2iIIAI3T +fCZdzHd55yx4Oagmcw6iXSVphU9VDprvxrlE4Vc93x9UIuVvZaozhDrzznq+VZeu +jRIPFDPiUHDDSYcTvFHe15gSWu86gzOSBnWLknwSaHtwag+1m7Z3W0hZneTvWq3z +wZ7U10VOylY0Ibw+F1tvdwxIAUMpsN0/lm7mlaoMwCC2/T42J5zjXM9OgdwZu5GQ +fezmlwQek8wiSdeXhrYTCjxDI3d+8NzmzSQfO4ObNDqDNOMCAwEAAaNjMGEwHwYD +VR0jBBgwFoAUkqR1LKSevoFE63n8isWVpesQdXMwDwYDVR0TAQH/BAUwAwEB/zAO +BgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFJKkdSyknr6BROt5/IrFlaXrEHVzMA0G +CSqGSIb3DQEBBQUAA4IBAQAo0uCG1eb4e/CX3CJrO5UUVg8RMKWaTzqwOuAGy2X1 +7caXJ/4l8lfmXpWMPmRgFVp/Lw0BxbFg/UU1z/CyvwbZ71q+s2IhtNerNXxTPqYn +8aEt2hojnczd7Dwtnic0XQ/CNnm8yUpiLe1r2X1BQ3y2qsrtYbE3ghUJGooWMNjs +ydZHcnhLEEYUjl8Or+zHL6sQ17bxbuyGssLoDZJz3KL0Dzq/YSMQiZxIQG5wALPT +ujdEWBF6AmqI8Dc08BnprNRlc/ZpjGSUOnmFKbAWKwyCPwacx/0QK54PLLae4xW/ +2TYcuiUaUj0a7CIMHOCkoj3w6DnPgcB77V0fb8XQC9eY +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDtjCCAp6gAwIBAgIOBcAAAQACQdAGCk3OdRAwDQYJKoZIhvcNAQEFBQAwdjEL +MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNV +BAsTGVRDIFRydXN0Q2VudGVyIENsYXNzIDQgQ0ExJTAjBgNVBAMTHFRDIFRydXN0 +Q2VudGVyIENsYXNzIDQgQ0EgSUkwHhcNMDYwMzIzMTQxMDIzWhcNMjUxMjMxMjI1 +OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIgR21i +SDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgNCBDQTElMCMGA1UEAxMc +VEMgVHJ1c3RDZW50ZXIgQ2xhc3MgNCBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBALXNTJytrlG7fEjFDSmGehSt2VA9CXIgDRS2Y8b+WJ7gIV7z +jyIZ3E6RIM1viCmis8GsKnK6i1S4QF/yqvhDhsIwXMynXX/GCEnkDjkvjhjWkd0j +FnmA22xIHbzB3ygQY9GB493fL3l1oht48pQB5hBiecugfQLANIJ7x8CtHUzXapZ2 +W78mhEj9h/aECqqSB5lIPGG8ToVYx5ct/YFKocabEvVCUNFkPologiJw3fX64yhC +L04y87OjNopq1mJcrPoBbbTgci6VaLTxkwzGioLSHVPqfOA/QrcSWrjN2qUGZ8uh +d32llvCSHmcOHUJG5vnt+0dTf1cERh9GX8eu4I8CAwEAAaNCMEAwDwYDVR0TAQH/ +BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFB/quz4lGwa9pd1iBX7G +TFq/6A9DMA0GCSqGSIb3DQEBBQUAA4IBAQBYpCubTPfkpJKknGWYGWIi/HIy6QRd +xMRwLVpG3kxHiiW5ot3u6hKvSI3vK2fbO8w0mCr3CEf/Iq978fTr4jgCMxh1KBue +dmWsiANy8jhHHYz1nwqIUxAUu4DlDLNdjRfuHhkcho0UZ3iMksseIUn3f9MYv5x5 ++F0IebWqak2SNmy8eesOPXmK2PajVnBd3ttPedJ60pVchidlvqDTB4FAVd0Qy+BL +iILAkH0457+W4Ze6mqtCD9Of2J4VMxHL94J59bXAQVaS4d9VA61Iz9PyLrHHLVZM +ZHQqMc7cdalUR6SnQnIJ5+ECpkeyBM1CE+FhDOB4OiIgohxgQoaH96Xm +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEU +MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3 +b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwHhcNMDAwNTMw +MTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQswCQYDVQQGEwJTRTEUMBIGA1UEChML +QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYD +VQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUA +A4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwzexODcEyPNwTXH+9ZOEQpnXvUGW2ul +CDtbKRY654eyNAbFvAWlA3yCyykQruGIgb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6n +tGO0/7Gcrjyvd7ZWxbWroulpOj0OM3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyl +dI+Yrsj5wAYi56xz36Uu+1LcsRVlIPo1Zmne3yzxbrww2ywkEtvrNTVokMsAsJch +PXQhI2U0K7t4WaPW4XY5mqRJjox0r26kmqPZm9I4XJuiGMx1I4S+6+JNM3GOGvDC ++Mcdoq0Dlyz4zyXG9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8wHQYDVR0O +BBYEFJWxtPCUtr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8E +BTADAQH/MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBl +MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFk +ZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENB +IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxtZBsfzQ3duQH6lmM0MkhHma6X +7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0PhiVYrqW9yTkkz +43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9tTEv2dB8Xfjea4MY +eDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL/bscVjby/rK25Xa71SJl +pz/+0WatC7xrmYbvP33zGDLKe8bjq2RGlfgmadlVg3sslgf/WSxEo8bl6ancoWOA +WiFeIc9TVPC6b4nbqKqVz4vjccweGyBECMB6tkD9xOQ14R0WHNC8K47Wcdk= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDpDCCAoygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEc +MBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBP +bmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyODA2 +MDAwMFoXDTM3MTExOTIwNDMwMFowYzELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0Ft +ZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2EgT25saW5lIFJvb3Qg +Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAKgv6KRpBgNHw+kqmP8ZonCaxlCyfqXfaE0bfA+2l2h9LaaLl+lk +hsmj76CGv2BlnEtUiMJIxUo5vxTjWVXlGbR0yLQFOVwWpeKVBeASrlmLojNoWBym +1BW32J/X3HGrfpq/m44zDyL9Hy7nBzbvYjnF3cu6JRQj3gzGPTzOggjmZj7aUTsW +OqMFf6Dch9Wc/HKpoH145LcxVR5lu9RhsCFg7RAycsWSJR74kEoYeEfffjA3PlAb +2xzTa5qGUwew76wGePiEmf4hjUyAtgyC9mZweRrTT6PP8c9GsEsPPt2IYriMqQko +O3rHl+Ee5fSfwMCuJKDIodkP1nsmgmkyPacCAwEAAaNjMGEwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUAK3Zo/Z59m50qX8zPYEX10zPM94wHwYDVR0jBBgwFoAU +AK3Zo/Z59m50qX8zPYEX10zPM94wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB +BQUAA4IBAQB8itEfGDeC4Liwo+1WlchiYZwFos3CYiZhzRAW18y0ZTTQEYqtqKkF +Zu90821fnZmv9ov761KyBZiibyrFVL0lvV+uyIbqRizBs73B6UlwGBaXCBOMIOAb +LjpHyx7kADCVW/RFo8AasAFOq73AI25jP4BKxQft3OJvx8Fi8eNy1gTIdGcL+oir +oQHIb/AUr9KZzVGTfu0uOMe9zkZQPXLjeSWdm4grECDdpbgyn43gKd8hdIaC2y+C +MMbHNYaz+ZZfRtsMRf3zUMNvxsNIrUam4SdHCh0Om7bCd39j8uB9Gr784N/Xx6ds +sPmuujz9dLQR6FgNgLzTqIA6me11zEZ7 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBi +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3Qg +RzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBiMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu +Y29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3y +ithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1If +xp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDV +ySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfISKhmV1efVFiO +DCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jHtrHEtWoYOAMQ +jdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6MUSaM0C/ +CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCi +EhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADM +fRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QY +uKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXK +chYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4KJpn15GkvmB0t +9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +hjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD +ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2 +SV1EY+CtnJYYZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd ++SeuMIW59mdNOj6PWTkiU0TryF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWc +fFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy7zBZLq7gcfJW5GqXb5JQbZaNaHqa +sjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iahixTXTBmyUEFxPT9N +cCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN5r5N +0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie +4u1Ki7wb/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mI +r/OSmbaz5mEP0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1 +/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tKG48BtieVU+i2iW1bvGjUI+iLUaJW+fCm +gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+ +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEuzCCA6OgAwIBAgIBAjANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQGEwJVUzET +MBEGA1UEChMKQXBwbGUgSW5jLjEmMCQGA1UECxMdQXBwbGUgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkxFjAUBgNVBAMTDUFwcGxlIFJvb3QgQ0EwHhcNMDYwNDI1MjE0 +MDM2WhcNMzUwMjA5MjE0MDM2WjBiMQswCQYDVQQGEwJVUzETMBEGA1UEChMKQXBw +bGUgSW5jLjEmMCQGA1UECxMdQXBwbGUgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkx +FjAUBgNVBAMTDUFwcGxlIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQDkkakJH5HbHkdQ6wXtXnmELes2oldMVeyLGYne+Uts9QerIjAC6Bg+ ++FAJ039BqJj50cpmnCRrEdCju+QbKsMflZ56DKRHi1vUFjczy8QPTc4UadHJGXL1 +XQ7Vf1+b8iUDulWPTV0N8WQ1IxVLFVkds5T39pyez1C6wVhQZ48ItCD3y6wsIG9w +tj8BMIy3Q88PnT3zK0koGsj+zrW5DtleHNbLPbU6rfQPDgCSC7EhFi501TwN22IW +q6NxkkdTVcGvL0Gz+PvjcM3mo0xFfh9Ma1CWQYnEdGILEINBhzOKgbEwWOxaBDKM +aLOPHd5lc/9nXmW8Sdh2nzMUZaF3lMktAgMBAAGjggF6MIIBdjAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUK9BpR5R2Cf70a40uQKb3 +R01/CF4wHwYDVR0jBBgwFoAUK9BpR5R2Cf70a40uQKb3R01/CF4wggERBgNVHSAE +ggEIMIIBBDCCAQAGCSqGSIb3Y2QFATCB8jAqBggrBgEFBQcCARYeaHR0cHM6Ly93 +d3cuYXBwbGUuY29tL2FwcGxlY2EvMIHDBggrBgEFBQcCAjCBthqBs1JlbGlhbmNl +IG9uIHRoaXMgY2VydGlmaWNhdGUgYnkgYW55IHBhcnR5IGFzc3VtZXMgYWNjZXB0 +YW5jZSBvZiB0aGUgdGhlbiBhcHBsaWNhYmxlIHN0YW5kYXJkIHRlcm1zIGFuZCBj +b25kaXRpb25zIG9mIHVzZSwgY2VydGlmaWNhdGUgcG9saWN5IGFuZCBjZXJ0aWZp +Y2F0aW9uIHByYWN0aWNlIHN0YXRlbWVudHMuMA0GCSqGSIb3DQEBBQUAA4IBAQBc +NplMLXi37Yyb3PN3m/J20ncwT8EfhYOFG5k9RzfyqZtAjizUsZAS2L70c5vu0mQP +y3lPNNiiPvl4/2vIB+x9OYOLUyDTOMSxv5pPCmv/K/xZpwUJfBdAVhEedNO3iyM7 +R6PVbyTi69G3cN8PReEnyvFteO3ntRcXqNx+IjXKJdXZD9Zr1KIkIxH3oayPc4Fg +xhtbCS+SsvhESPBgOJ4V9T0mZyCKM2r3DYLP3uujL/lTaltkwGMzd/c6ByxW69oP +IQ7aunMZT7XZNn/Bh1XZp5m5MkL72NVxnn6hUrcbvZNCJBIqxw8dtk2cXmPIS4AX +UKqK1drk/NAJBzewdXUh +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIID9zCCAt+gAwIBAgIESJ8AATANBgkqhkiG9w0BAQUFADCBijELMAkGA1UEBhMC +Q04xMjAwBgNVBAoMKUNoaW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24g +Q2VudGVyMUcwRQYDVQQDDD5DaGluYSBJbnRlcm5ldCBOZXR3b3JrIEluZm9ybWF0 +aW9uIENlbnRlciBFViBDZXJ0aWZpY2F0ZXMgUm9vdDAeFw0xMDA4MzEwNzExMjVa +Fw0zMDA4MzEwNzExMjVaMIGKMQswCQYDVQQGEwJDTjEyMDAGA1UECgwpQ2hpbmEg +SW50ZXJuZXQgTmV0d29yayBJbmZvcm1hdGlvbiBDZW50ZXIxRzBFBgNVBAMMPkNo +aW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24gQ2VudGVyIEVWIENlcnRp +ZmljYXRlcyBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm35z +7r07eKpkQ0H1UN+U8i6yjUqORlTSIRLIOTJCBumD1Z9S7eVnAztUwYyZmczpwA// +DdmEEbK40ctb3B75aDFk4Zv6dOtouSCV98YPjUesWgbdYavi7NifFy2cyjw1l1Vx +zUOFsUcW9SxTgHbP0wBkvUCZ3czY28Sf1hNfQYOL+Q2HklY0bBoQCxfVWhyXWIQ8 +hBouXJE0bhlffxdpxWXvayHG1VA6v2G5BY3vbzQ6sm8UY78WO5upKv23KzhmBsUs +4qpnHkWnjQRmQvaPK++IIGmPMowUc9orhpFjIpryp9vOiYurXccUwVswah+xt54u +gQEC7c+WXmPbqOY4twIDAQABo2MwYTAfBgNVHSMEGDAWgBR8cks5x8DbYqVPm6oY +NJKiyoOCWTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4E +FgQUfHJLOcfA22KlT5uqGDSSosqDglkwDQYJKoZIhvcNAQEFBQADggEBACrDx0M3 +j92tpLIM7twUbY8opJhJywyA6vPtI2Z1fcXTIWd50XPFtQO3WKwMVC/GVhMPMdoG +52U7HW8228gd+f2ABsqjPWYWqJ1MFn3AlUa1UeTiH9fqBk1jjZaM7+czV0I664zB +echNdn3e9rG3geCg+aF4RhcaVpjwTj2rHO3sOdwHSPdj/gauwqRcalsyiMXHM4Ws +ZkJHwlgkmeHlPuV1LI5D1l08eB6olYIpUNHRFrrvwb562bTYzB5MRuF3sTGrvSrI +zo9uoV1/A3U05K2JRVRevq4opbs/eHnrc7MKDf2+yfdWrPa37S+bISnHOLaVxATy +wy39FCqQmbkHzJ8= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x +GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv +b3QgQ0EgMjAeFw0wNjExMjQxODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNV +BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W +YWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCa +GMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6XJxg +Fyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55J +WpzmM+Yklvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bB +rrcCaoF6qUWD4gXmuVbBlDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp ++ARz8un+XJiM9XOva7R+zdRcAitMOeGylZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1 +ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt66/3FsvbzSUr5R/7mp/i +Ucw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1JdxnwQ5hYIiz +PtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og +/zOhD7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UH +oycR7hYQe7xFSkyyBNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuI +yV77zGHcizN300QyNQliBJIWENieJ0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1Ud +EwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBQahGK8SEwzJQTU7tD2 +A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGUa6FJpEcwRTEL +MAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT +ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2f +BluornFdLwUvZ+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzn +g/iN/Ae42l9NLmeyhP3ZRPx3UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2Bl +fF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodmVjB3pjd4M1IQWK4/YY7yarHvGH5K +WWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK+JDSV6IZUaUtl0Ha +B0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrWIozc +hLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPR +TUIZ3Ph1WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWD +mbA4CD/pXvk1B+TJYm5Xf6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0Z +ohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y +4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8VCLAAVBpQ570su9t+Oza +8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIE5jCCA86gAwIBAgIEO45L/DANBgkqhkiG9w0BAQUFADBdMRgwFgYJKoZIhvcN +AQkBFglwa2lAc2suZWUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKExlBUyBTZXJ0aWZp +dHNlZXJpbWlza2Vza3VzMRAwDgYDVQQDEwdKdXVyLVNLMB4XDTAxMDgzMDE0MjMw +MVoXDTE2MDgyNjE0MjMwMVowXTEYMBYGCSqGSIb3DQEJARYJcGtpQHNrLmVlMQsw +CQYDVQQGEwJFRTEiMCAGA1UEChMZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEQ +MA4GA1UEAxMHSnV1ci1TSzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AIFxNj4zB9bjMI0TfncyRsvPGbJgMUaXhvSYRqTCZUXP00B841oiqBB4M8yIsdOB +SvZiF3tfTQou0M+LI+5PAk676w7KvRhj6IAcjeEcjT3g/1tf6mTll+g/mX8MCgkz +ABpTpyHhOEvWgxutr2TC+Rx6jGZITWYfGAriPrsfB2WThbkasLnE+w0R9vXW+RvH +LCu3GFH+4Hv2qEivbDtPL+/40UceJlfwUR0zlv/vWT3aTdEVNMfqPxZIe5EcgEMP +PbgFPtGzlc3Yyg/CQ2fbt5PgIoIuvvVoKIO5wTtpeyDaTpxt4brNj3pssAki14sL +2xzVWiZbDcDq5WDQn/413z8CAwEAAaOCAawwggGoMA8GA1UdEwEB/wQFMAMBAf8w +ggEWBgNVHSAEggENMIIBCTCCAQUGCisGAQQBzh8BAQEwgfYwgdAGCCsGAQUFBwIC +MIHDHoHAAFMAZQBlACAAcwBlAHIAdABpAGYAaQBrAGEAYQB0ACAAbwBuACAAdgDk +AGwAagBhAHMAdABhAHQAdQBkACAAQQBTAC0AaQBzACAAUwBlAHIAdABpAGYAaQB0 +AHMAZQBlAHIAaQBtAGkAcwBrAGUAcwBrAHUAcwAgAGEAbABhAG0ALQBTAEsAIABz +AGUAcgB0AGkAZgBpAGsAYQBhAHQAaQBkAGUAIABrAGkAbgBuAGkAdABhAG0AaQBz +AGUAawBzMCEGCCsGAQUFBwIBFhVodHRwOi8vd3d3LnNrLmVlL2Nwcy8wKwYDVR0f +BCQwIjAgoB6gHIYaaHR0cDovL3d3dy5zay5lZS9qdXVyL2NybC8wHQYDVR0OBBYE +FASqekej5ImvGs8KQKcYP2/v6X2+MB8GA1UdIwQYMBaAFASqekej5ImvGs8KQKcY +P2/v6X2+MA4GA1UdDwEB/wQEAwIB5jANBgkqhkiG9w0BAQUFAAOCAQEAe8EYlFOi +CfP+JmeaUOTDBS8rNXiRTHyoERF5TElZrMj3hWVcRrs7EKACr81Ptcw2Kuxd/u+g +kcm2k298gFTsxwhwDY77guwqYHhpNjbRxZyLabVAyJRld/JXIWY7zoVAtjNjGr95 +HvxcHdMdkxuLDF2FvZkwMhgJkVLpfKG6/2SSmuz+Ne6ML678IIbsSt4beDI3poHS +na9aEhbKmVv8b20OxaAehsmR0FyYgl9jDIpaq9iVpszLita/ZEuOyoqysOkhMp6q +qIWYNIE5ITuoOlIyPfZrN4YGWhWY3PARZv40ILcD9EEQfTmEeZZyY7aWAuVrua0Z +TbvGRNs2yyqcjg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICQzCCAcmgAwIBAgIILcX8iNLFS5UwCgYIKoZIzj0EAwMwZzEbMBkGA1UEAwwS +QXBwbGUgUm9vdCBDQSAtIEczMSYwJAYDVQQLDB1BcHBsZSBDZXJ0aWZpY2F0aW9u +IEF1dGhvcml0eTETMBEGA1UECgwKQXBwbGUgSW5jLjELMAkGA1UEBhMCVVMwHhcN +MTQwNDMwMTgxOTA2WhcNMzkwNDMwMTgxOTA2WjBnMRswGQYDVQQDDBJBcHBsZSBS +b290IENBIC0gRzMxJjAkBgNVBAsMHUFwcGxlIENlcnRpZmljYXRpb24gQXV0aG9y +aXR5MRMwEQYDVQQKDApBcHBsZSBJbmMuMQswCQYDVQQGEwJVUzB2MBAGByqGSM49 +AgEGBSuBBAAiA2IABJjpLz1AcqTtkyJygRMc3RCV8cWjTnHcFBbZDuWmBSp3ZHtf +TjjTuxxEtX/1H7YyYl3J6YRbTzBPEVoA/VhYDKX1DyxNB0cTddqXl5dvMVztK517 +IDvYuVTZXpmkOlEKMaNCMEAwHQYDVR0OBBYEFLuw3qFYM4iapIqZ3r6966/ayySr +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2gA +MGUCMQCD6cHEFl4aXTQY2e3v9GwOAEZLuN+yRhHFD/3meoyhpmvOwgPUnPWTxnS4 +at+qIxUCMG1mihDK1A3UT82NQz60imOlM27jbdoXt2QfyFMm+YhidDkLF1vLUagM +6BgD56KyKA== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIExTCCA62gAwIBAgIBADANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJFVTEn +MCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQL +ExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEgMB4GA1UEAxMXR2xvYmFsIENo +YW1iZXJzaWduIFJvb3QwHhcNMDMwOTMwMTYxNDE4WhcNMzcwOTMwMTYxNDE4WjB9 +MQswCQYDVQQGEwJFVTEnMCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgy +NzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEgMB4G +A1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwggEgMA0GCSqGSIb3DQEBAQUA +A4IBDQAwggEIAoIBAQCicKLQn0KuWxfH2H3PFIP8T8mhtxOviteePgQKkotgVvq0 +Mi+ITaFgCPS3CU6gSS9J1tPfnZdan5QEcOw/Wdm3zGaLmFIoCQLfxS+EjXqXd7/s +QJ0lcqu1PzKY+7e3/HKE5TWH+VX6ox8Oby4o3Wmg2UIQxvi1RMLQQ3/bvOSiPGpV +eAp3qdjqGTK3L/5cPxvusZjsyq16aUXjlg9V9ubtdepl6DJWk0aJqCWKZQbua795 +B9Dxt6/tLE2Su8CoX6dnfQTyFQhwrJLWfQTSM/tMtgsL+xrJxI0DqX5c8lCrEqWh +z0hQpe/SyBoT+rB/sYIcd2oPX9wLlY/vQ37mRQklAgEDo4IBUDCCAUwwEgYDVR0T +AQH/BAgwBgEB/wIBDDA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3JsLmNoYW1i +ZXJzaWduLm9yZy9jaGFtYmVyc2lnbnJvb3QuY3JsMB0GA1UdDgQWBBRDnDafsJ4w +TcbOX60Qq+UDpfqpFDAOBgNVHQ8BAf8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgAH +MCoGA1UdEQQjMCGBH2NoYW1iZXJzaWducm9vdEBjaGFtYmVyc2lnbi5vcmcwKgYD +VR0SBCMwIYEfY2hhbWJlcnNpZ25yb290QGNoYW1iZXJzaWduLm9yZzBbBgNVHSAE +VDBSMFAGCysGAQQBgYcuCgEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly9jcHMuY2hh +bWJlcnNpZ24ub3JnL2Nwcy9jaGFtYmVyc2lnbnJvb3QuaHRtbDANBgkqhkiG9w0B +AQUFAAOCAQEAPDtwkfkEVCeR4e3t/mh/YV3lQWVPMvEYBZRqHN4fcNs+ezICNLUM +bKGKfKX0j//U2K0X1S0E0T9YgOKBWYi+wONGkyT+kL0mojAt6JcmVzWJdJYY9hXi +ryQZVgICsroPFOrGimbBhkVVi76SvpykBMdJPJ7oKXqJ1/6v/2j1pReQvayZzKWG +VwlnRtvWFsJG8eSpUPWP0ZIV018+xgBJOm5YstHRJw0lyDL4IBHNfTIzSJRUTN3c +ecQwn+uOuFW114hcxWokPbLTBQNRxgfvzBRydD1ucs4YKIxKoHflCStFREest2d/ +AYoFWpO+ocH/+OcOZ6RHSXZddZAa9SaP8A== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRF +MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBD +bGFzcyAzIENBIDIgMjAwOTAeFw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NTha +ME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMM +HkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOADER03 +UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42 +tSHKXzlABF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9R +ySPocq60vFYJfxLLHLGvKZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsM +lFqVlNpQmvH/pStmMaTJOKDfHR+4CS7zp+hnUquVH+BGPtikw8paxTGA6Eian5Rp +/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUCAwEAAaOCARowggEWMA8G +A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ4PGEMA4G +A1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVj +dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUy +MENBJTIwMiUyMDIwMDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRl +cmV2b2NhdGlvbmxpc3QwQ6BBoD+GPWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3Js +L2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAwOS5jcmwwDQYJKoZIhvcNAQEL +BQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm2H6NMLVwMeni +acfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0 +o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4K +zCUqNQT4YJEVdT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8 +PIWmawomDeCTmGCufsYkl4phX5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3Y +Johw1+qRzT65ysCQblrGXnRl11z+o+I= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBI +MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x +FzAVBgNVBAMTDlNlY3VyZVRydXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIz +MTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1NlY3VyZVRydXN0IENv +cnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQXOZEz +Zum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO +0gMdA+9tDWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIao +wW8xQmxSPmjL8xk037uHGFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj +7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b01k/unK8RCSc43Oz969XL0Imnal0ugBS +8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmHursCAwEAAaOBnTCBmjAT +BgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB +/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCeg +JYYjaHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGC +NxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt3 +6Z3q059c4EVlew3KW+JwULKUBRSuSceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/ +3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHfmbx8IVQr5Fiiu1cprp6poxkm +D5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZnMUFdAvnZyPS +CPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR +3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDczCCAlugAwIBAgIBBDANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJLUjEN +MAsGA1UECgwES0lTQTEuMCwGA1UECwwlS29yZWEgQ2VydGlmaWNhdGlvbiBBdXRo +b3JpdHkgQ2VudHJhbDEWMBQGA1UEAwwNS0lTQSBSb290Q0EgMTAeFw0wNTA4MjQw +ODA1NDZaFw0yNTA4MjQwODA1NDZaMGQxCzAJBgNVBAYTAktSMQ0wCwYDVQQKDARL +SVNBMS4wLAYDVQQLDCVLb3JlYSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBDZW50 +cmFsMRYwFAYDVQQDDA1LSVNBIFJvb3RDQSAxMIIBIDANBgkqhkiG9w0BAQEFAAOC +AQ0AMIIBCAKCAQEAvATk+hM58DSWIGtsaLv623f/J/es7C/n/fB/bW+MKs0lCVsk +9KFo/CjsySXirO3eyDOE9bClCTqnsUdIxcxPjHmc+QZXfd3uOPbPFLKc6tPAXXdi +8EcNuRpAU1xkcK8IWsD3z3X5bI1kKB4g/rcbGdNaZoNy4rCbvdMlFQ0yb2Q3lIVG +yHK+d9VuHygvx2nt54OJM1jT3qC/QOhDUO7cTWu8peqmyGGO9cNkrwYV3CmLP3WM +vHFE2/yttRcdbYmDz8Yzvb9Fov4Kn6MRXw+5H5wawkbMnChmn3AmPC7fqoD+jMUE +CSVPzZNHPDfqAmeS/vwiJFys0izgXAEzisEZ2wIBA6MyMDAwHQYDVR0OBBYEFL+2 +J9gDWnZlTGEBQVYx5Yt7OtnMMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEF +BQADggEBABOvUQveimpb5poKyLGQSk6hAp3MiNKrZr097LuxQpVqslxa/6FjZJap +aBV/JV6K+KRzwYCKhQoOUugy50X4TmWAkZl0Q+VFnUkq8JSV3enhMNITbslOsXfl +BM+tWh6UCVrXPAgcrnrpFDLBRa3SJkhyrKhB2vAhhzle3/xk/2F0KpzZm4tfwjeT +2KM3LzuTa7IbB6d/CVDv0zq+IWuKkDsnSlFOa56ch534eJAx7REnxqhZvvwYC/uO +fi5C4e3nCSG9uRPFVmf0JqZCQ5BEVLRxm3bkGhKsGigA35vB1fjbXKP4krG9tNT5 +UNkAAk/bg9ART6RCVmE6fhMy04Qfybo= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1Ix +RDBCBgNVBAoTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1 +dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1p +YyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIFJvb3RDQSAyMDExMB4XDTExMTIw +NjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYTAkdSMUQwQgYDVQQK +EztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIENl +cnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl +c2VhcmNoIEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBAKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPz +dYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJ +fel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa71HFK9+WXesyHgLacEns +bgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u8yBRQlqD +75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSP +FEDH3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNV +HRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp +5dgTBCPuQSUwRwYDVR0eBEAwPqA8MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQu +b3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQub3JnMA0GCSqGSIb3DQEBBQUA +A4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVtXdMiKahsog2p +6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8 +TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7 +dIsXRSZMFpGD/md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8Acys +Nnq/onN694/BtZqhFLKPM58N7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXI +l7WdmplNsDz4SgCbZN2fOUvRJ9e4 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQG +EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3 +MDUGA1UECwwuVGFuw7pzw610dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNl +cnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBBcmFueSAoQ2xhc3MgR29sZCkgRsWR +dGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgxMjA2MTUwODIxWjCB +pzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxOZXRM +b2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlm +aWNhdGlvbiBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNz +IEdvbGQpIEbFkXRhbsO6c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAxCRec75LbRTDofTjl5Bu0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrT +lF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw/HpYzY6b7cNGbIRwXdrz +AZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAkH3B5r9s5 +VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRG +ILdwfzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2 +BJtr+UBdADTHLpl1neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAG +AQH/AgEEMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2M +U9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwWqZw8UQCgwBEIBaeZ5m8BiFRh +bvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTtaYtOUZcTh5m2C ++C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC +bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2F +uLjbvrW5KfnaNwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2 +XjG4Kvte9nHfRCaexOYNkbQudZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJHQjEb +MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow +GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEkMCIGA1UEAwwbU2VjdXJlIENlcnRp +ZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVow +fjELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G +A1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxJDAiBgNV +BAMMG1NlY3VyZSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBAMBxM4KK0HDrc4eCQNUd5MvJDkKQ+d40uaG6EfQlhfPM +cm3ye5drswfxdySRXyWP9nQ95IDC+DwN879A6vfIUtFyb+/Iq0G4bi4XKpVpDM3S +HpR7LZQdqnXXs5jLrLxkU0C8j6ysNstcrbvd4JQX7NFc0L/vpZXJkMWwrPsbQ996 +CF23uPJAGysnnlDOXmWCiIxe004MeuoIkbY2qitC++rCoznl2yY4rYsK7hljxxwk +3wN42ubqwUcaCwtGCd0C/N7Lh1/XMGNooa7cMqG6vv5Eq2i2pRcV/b3Vp6ea5EQz +6YiO/O1R65NxTq0B50SOqy3LqP4BSUjwwN3HaNiS/j0CAwEAAaOBxzCBxDAdBgNV +HQ4EFgQUPNiTiMLAggnMAZkGkyDpnnAJY08wDgYDVR0PAQH/BAQDAgEGMA8GA1Ud +EwEB/wQFMAMBAf8wgYEGA1UdHwR6MHgwO6A5oDeGNWh0dHA6Ly9jcmwuY29tb2Rv +Y2EuY29tL1NlY3VyZUNlcnRpZmljYXRlU2VydmljZXMuY3JsMDmgN6A1hjNodHRw +Oi8vY3JsLmNvbW9kby5uZXQvU2VjdXJlQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmww +DQYJKoZIhvcNAQEFBQADggEBAIcBbSMdflsXfcFhMs+P5/OKlFlm4J4oqF7Tt/Q0 +5qo5spcWxYJvMqTpjOev/e/C6LlLqqP05tqNZSH7uoDrJiiFGv45jN5bBAS0VPmj +Z55B+glSzAVIqMk/IQQezkhr/IXownuvf7fM+F86/TXGDe+X3EyrEeFryzHRbPtI +gKvcnDe4IRRLDXE97IMzbtFuMhbsmMcWi1mmNKsFVy2T96oTy9IT4rcuO81rUBcJ +aD61JlfutuC23bkpgHl9j6PwpCikFcSF9CfUa7/lXORlAnZUtOM3ZiTTGWHIUhDl +izeauan5Hb/qmZJhlv8BzaFfDbxxvA6sCx1HRR3B7Hzs/Sk= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIF0zCCA7ugAwIBAgIVALhZFHE/V9+PMcAzPdLWGXojF7TrMA0GCSqGSIb3DQEB +DQUAMIGAMQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dp +ZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBIDIwHhcNMTExMDA2 +MDgzOTU2WhcNNDYxMDA2MDgzOTU2WjCBgDELMAkGA1UEBhMCUEwxIjAgBgNVBAoT +GVVuaXpldG8gVGVjaG5vbG9naWVzIFMuQS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0 +aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIGA1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0 +d29yayBDQSAyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvfl4+ObV +gAxknYYblmRnPyI6HnUBfe/7XGeMycxca6mR5rlC5SBLm9qbe7mZXdmbgEvXhEAr +J9PoujC7Pgkap0mV7ytAJMKXx6fumyXvqAoAl4Vaqp3cKcniNQfrcE1K1sGzVrih +QTib0fsxf4/gX+GxPw+OFklg1waNGPmqJhCrKtPQ0WeNG0a+RzDVLnLRxWPa52N5 +RH5LYySJhi40PylMUosqp8DikSiJucBb+R3Z5yet/5oCl8HGUJKbAiy9qbk0WQq/ +hEr/3/6zn+vZnuCYI+yma3cWKtvMrTscpIfcRnNeGWJoRVfkkIJCu0LW8GHgwaM9 +ZqNd9BjuiMmNF0UpmTJ1AjHuKSbIawLmtWJFfzcVWiNoidQ+3k4nsPBADLxNF8tN +orMe0AZa3faTz1d1mfX6hhpneLO/lv403L3nUlbls+V1e9dBkQXcXWnjlQ1DufyD +ljmVe2yAWk8TcsbXfSl6RLpSpCrVQUYJIP4ioLZbMI28iQzV13D4h1L92u+sUS4H +s07+0AnacO+Y+lbmbdu1V0vc5SwlFcieLnhO+NqcnoYsylfzGuXIkosagpZ6w7xQ +EmnYDlpGizrrJvojybawgb5CAKT41v4wLsfSRvbljnX98sy50IdbzAYQYLuDNbde +Z95H7JlI8aShFf6tjGKOOVVPORa5sWOd/7cCAwEAAaNCMEAwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUtqFUOQLDoD+Oirz61PgcptE6Dv0wDgYDVR0PAQH/BAQD +AgEGMA0GCSqGSIb3DQEBDQUAA4ICAQCdU8KBJdw1LK4K3VqbRjBWu9S0bEuG5gql +0pKKmo3cj7TudvQDy+ubAXirKmu1uiNOMXy1LN0taWczbmNdORgS+KAoU0SHq2rE +kpYfKqIcup3dJ/tSTbCPWujtjcNo45KgJgyHkLAD6mplKAjERnjgW7oO8DPcJ7Z+ +iD29kqSWfkGogAh71jYSvBAVmyS8q619EYkvMe340s9Tjuu0U6fnBMovpiLEEdzr +mMkiXUFq3ApSBFu8LqB9x7aSuySg8zfRK0OozPFoeBp+b2OQe590yGvZC1X2eQM9 +g8dBQJL7dgs3JRc8rz76PFwbhvlKDD+KxF4OmPGt7s/g/SE1xzNhzKI3GEN8M+mu +doKCB0VIO8lnbq2jheiWVs+8u/qry7dXJ40aL5nzIzM0jspTY9NXNFBPz0nBBbrF +qId744aP+0OiEumsUewEdkzw+o+5MRPpCLckCfmgtwc2WFfPxLt+SWaVNQS2dzW4 +qVMpX5KF+FLEWk79BmE5+33QdkeSzOwrvYRu5ptFwX1isVMtnnWg58koUNflvKiq +B3hquXS0YPOEjQPcrpHadEQNe0Kpd9YrfKHGbBNTIqkSmqX5TyhFNbCXT0ZlhcX0 +/WKiomr8NDAGft8M4HOBlslEKt4fguxscletKWSk8cYpjjVgU85r2QK+OTB14Pdc +Y2rwQMEsjQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDQzCCAiugAwIBAgIQX/h7KCtU3I1CoxW1aMmt/zANBgkqhkiG9w0BAQUFADA1 +MRYwFAYDVQQKEw1DaXNjbyBTeXN0ZW1zMRswGQYDVQQDExJDaXNjbyBSb290IENB +IDIwNDgwHhcNMDQwNTE0MjAxNzEyWhcNMjkwNTE0MjAyNTQyWjA1MRYwFAYDVQQK +Ew1DaXNjbyBTeXN0ZW1zMRswGQYDVQQDExJDaXNjbyBSb290IENBIDIwNDgwggEg +MA0GCSqGSIb3DQEBAQUAA4IBDQAwggEIAoIBAQCwmrmrp68Kd6ficba0ZmKUeIhH +xmJVhEAyv8CrLqUccda8bnuoqrpu0hWISEWdovyD0My5jOAmaHBKeN8hF570YQXJ +FcjPFto1YYmUQ6iEqDGYeJu5Tm8sUxJszR2tKyS7McQr/4NEb7Y9JHcJ6r8qqB9q +VvYgDxFUl4F1pyXOWWqCZe+36ufijXWLbvLdT6ZeYpzPEApk0E5tzivMW/VgpSdH +jWn0f84bcN5wGyDWbs2mAag8EtKpP6BrXruOIIt6keO1aO6g58QBdKhTCytKmg9l +Eg6CTY5j/e/rmxrbU6YTYK/CfdfHbBcl1HP7R2RQgYCUTOG/rksc35LtLgXfAgED +o1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUJ/PI +FR5umgIJFq0roIlgX9p7L6owEAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZIhvcNAQEF +BQADggEBAJ2dhISjQal8dwy3U8pORFBi71R803UXHOjgxkhLtv5MOhmBVrBW7hmW +Yqpao2TB9k5UM8Z3/sUcuuVdJcr18JOagxEu5sv4dEX+5wW4q+ffy0vhN4TauYuX +cB7w4ovXsNgOnbFp1iqRe6lJT37mjpXYgyc81WhJDtSd9i7rp77rMKSsH0T8lasz +Bvt9YAretIpjsJyp8qS5UwGH0GikJ3+r/+n6yUA4iGe0OcaEb1fJU9u6ju7AQ7L4 +CYNu/2bPPu8Xs1gYJQk0XuPL1hS27PKSb3TkL4Eq1ZKR4OCXPDJoBYVL0fdX4lId +kxpUnwVwwEpxYB5DC2Ae/qPOgRnhCzU= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT +HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs +ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw +MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 +b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj +aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp +Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg +nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1 +HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N +Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN +dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0 +HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO +BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G +CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU +sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3 +4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg +8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K +pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1 +mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDzzCCAregAwIBAgIDAWweMA0GCSqGSIb3DQEBBQUAMIGNMQswCQYDVQQGEwJB +VDFIMEYGA1UECgw/QS1UcnVzdCBHZXMuIGYuIFNpY2hlcmhlaXRzc3lzdGVtZSBp +bSBlbGVrdHIuIERhdGVudmVya2VociBHbWJIMRkwFwYDVQQLDBBBLVRydXN0LW5R +dWFsLTAzMRkwFwYDVQQDDBBBLVRydXN0LW5RdWFsLTAzMB4XDTA1MDgxNzIyMDAw +MFoXDTE1MDgxNzIyMDAwMFowgY0xCzAJBgNVBAYTAkFUMUgwRgYDVQQKDD9BLVRy +dXN0IEdlcy4gZi4gU2ljaGVyaGVpdHNzeXN0ZW1lIGltIGVsZWt0ci4gRGF0ZW52 +ZXJrZWhyIEdtYkgxGTAXBgNVBAsMEEEtVHJ1c3QtblF1YWwtMDMxGTAXBgNVBAMM +EEEtVHJ1c3QtblF1YWwtMDMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +AQCtPWFuA/OQO8BBC4SAzewqo51ru27CQoT3URThoKgtUaNR8t4j8DRE/5TrzAUj +lUC5B3ilJfYKvUWG6Nm9wASOhURh73+nyfrBJcyFLGM/BWBzSQXgYHiVEEvc+RFZ +znF/QJuKqiTfC0Li21a8StKlDJu3Qz7dg9MmEALP6iPESU7l0+m0iKsMrmKS1GWH +2WrX9IWf5DMiJaXlyDO6w8dB3F/GaswADm0yqLaHNgBid5seHzTLkDx4iHQF63n1 +k3Flyp3HaxgtPVxO59X4PzF9j4fsCiIvI+n+u33J4PTs63zEsMMtYrWacdaxaujs +2e3Vcuy+VwHOBVWf3tFgiBCzAgMBAAGjNjA0MA8GA1UdEwEB/wQFMAMBAf8wEQYD +VR0OBAoECERqlWdVeRFPMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOC +AQEAVdRU0VlIXLOThaq/Yy/kgM40ozRiPvbY7meIMQQDbwvUB/tOdQ/TLtPAF8fG +KOwGDREkDg6lXb+MshOWcdzUzg4NCmgybLlBMRmrsQd7TZjTXLDR8KdCoLXEjq/+ +8T/0709GAHbrAvv5ndJAlseIOrifEXnzgGWovR/TeIGgUUw3tKZdJXDRZslo+S4R +FGjxVJgIrCaSD96JntT6s3kr0qN51OyLrIdTaEJMUVF0HhsnLuP1Hyl0Te2v9+GS +mYHovjrHF1D2t8b8m7CKa9aIA5GPBnc6hQLdmNVDeD/GMBWsm2vLV7eJUYs66MmE +DNuxUCAKGkq6ahq97BvIxYSazQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCB +rjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf +Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw +MDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNV +BAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0wODA0MDIwMDAwMDBa +Fw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhhd3Rl +LCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9u +MTgwNgYDVQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXpl +ZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEcz +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsr8nLPvb2FvdeHsbnndm +gcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2AtP0LMqmsywCPLLEHd5N/8 +YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC+BsUa0Lf +b1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS9 +9irY7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2S +zhkGcuYMXDhpxwTWvGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUk +OQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV +HQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJKoZIhvcNAQELBQADggEBABpA +2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweKA3rD6z8KLFIW +oCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu +t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7c +KUGRIjxpp7sC8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fM +m7v/OeZWYdMKp8RcTGB7BXcmer/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZu +MdRAGmI0Nj81Aa6sY6A= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFHjCCBAagAwIBAgIEAKA3oDANBgkqhkiG9w0BAQsFADCBtzELMAkGA1UEBhMC +Q1oxOjA4BgNVBAMMMUkuQ0EgLSBRdWFsaWZpZWQgQ2VydGlmaWNhdGlvbiBBdXRo +b3JpdHksIDA5LzIwMDkxLTArBgNVBAoMJFBydm7DrSBjZXJ0aWZpa2HEjW7DrSBh +dXRvcml0YSwgYS5zLjE9MDsGA1UECww0SS5DQSAtIEFjY3JlZGl0ZWQgUHJvdmlk +ZXIgb2YgQ2VydGlmaWNhdGlvbiBTZXJ2aWNlczAeFw0wOTA5MDEwMDAwMDBaFw0x +OTA5MDEwMDAwMDBaMIG3MQswCQYDVQQGEwJDWjE6MDgGA1UEAwwxSS5DQSAtIFF1 +YWxpZmllZCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSwgMDkvMjAwOTEtMCsGA1UE +CgwkUHJ2bsOtIGNlcnRpZmlrYcSNbsOtIGF1dG9yaXRhLCBhLnMuMT0wOwYDVQQL +DDRJLkNBIC0gQWNjcmVkaXRlZCBQcm92aWRlciBvZiBDZXJ0aWZpY2F0aW9uIFNl +cnZpY2VzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtTaEy0KC8M9l +4lSaWHMs4+sVV1LwzyJYiIQNeCrv1HHm/YpGIdY/Z640ceankjQvIX7m23BK4OSC +6KO8kZYA3zopOz6GFCOKV2PvLukbc+c2imF6kLHEv6qNA8WxhPbR3xKwlHDwB2yh +Wzo7V3QVgDRG83sugqQntKYC3LnlTGbJpNP+Az72gpO9AHUn/IBhFk4ksc8lYS2L +9GCy9CsmdKSBP78p9w8Lx7vDLqkDgt1/zBrcUWmSSb7AE/BPEeMryQV1IdI6nlGn +BhWkXOYf6GSdayJw86btuxC7viDKNrbp44HjQRaSxnp6O3eto1x4DfiYdw/YbJFe +7EjkxSQBywIDAQABo4IBLjCCASowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E +BAMCAQYwgecGA1UdIASB3zCB3DCB2QYEVR0gADCB0DCBzQYIKwYBBQUHAgIwgcAa +gb1UZW50byBjZXJ0aWZpa2F0IGplIHZ5ZGFuIGpha28ga3ZhbGlmaWtvdmFueSBz +eXN0ZW1vdnkgY2VydGlmaWthdCBwb2RsZSB6YWtvbmEgYy4gMjI3LzIwMDAgU2Iu +IHYgcGxhdG5lbSB6bmVuaS9UaGlzIGlzIHF1YWxpZmllZCBzeXN0ZW0gY2VydGlm +aWNhdGUgYWNjb3JkaW5nIHRvIEN6ZWNoIEFjdCBOby4gMjI3LzIwMDAgQ29sbC4w +HQYDVR0OBBYEFHnL0CPpOmdwkXRP01Hi4CD94Sj7MA0GCSqGSIb3DQEBCwUAA4IB +AQB9laU214hYaBHPZftbDS/2dIGLWdmdSbj1OZbJ8LIPBMxYjPoEMqzAR74tw96T +i6aWRa5WdOWaS6I/qibEKFZhJAVXX5mkx2ewGFLJ+0Go+eTxnjLOnhVF2V2s+57b +m8c8j6/bS6Ij6DspcHEYpfjjh64hE2r0aSpZDjGzKFM6YpqsCJN8qYe2X1qmGMLQ +wvNdjG+nPzCJOOuUEypIWt555ZDLXqS5F7ZjBjlfyDZjEfS2Es9Idok8alf563Mi +9/o+Ba46wMYOkk3P1IlU0RqCajdbliioACKDztAqubONU1guZVzV8tuMASVzbJeL +/GAB7ECTwe1RuKrLYtglMKI9 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW +MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg +Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM2WhcNMzYwOTE3MTk0NjM2WjB9 +MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi +U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh +cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA +A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk +pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf +OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C +Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT +Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi +HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM +Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w ++2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+ +Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3 +Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B +26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID +AQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE +FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9j +ZXJ0LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3Js +LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFM +BgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUHAgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0 +Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRwOi8vY2VydC5zdGFy +dGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYgU3Rh +cnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlh +YmlsaXR5LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2Yg +dGhlIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFp +bGFibGUgYXQgaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL3BvbGljeS5wZGYwEQYJ +YIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNT +TCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOCAgEAFmyZ +9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8 +jhvh3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUW +FjgKXlf2Ysd6AgXmvB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJz +ewT4F+irsfMuXGRuczE6Eri8sxHkfY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1 +ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3fsNrarnDy0RLrHiQi+fHLB5L +EUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZEoalHmdkrQYu +L6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq +yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuC +O3NJo2pXh5Tl1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6V +um0ABj6y6koQOdjQK/W/7HW/lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkySh +NOsF/5oirpt9P/FlUQqmMGqz9IgcgA38corog14= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIHhzCCBW+gAwIBAgIBLTANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJJTDEW +MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg +Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM3WhcNMzYwOTE3MTk0NjM2WjB9 +MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi +U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh +cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA +A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk +pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf +OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C +Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT +Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi +HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM +Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w ++2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+ +Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3 +Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B +26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID +AQABo4ICEDCCAgwwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD +VR0OBBYEFE4L7xqkQFulF2mHMMo0aEPQQa7yMB8GA1UdIwQYMBaAFE4L7xqkQFul +F2mHMMo0aEPQQa7yMIIBWgYDVR0gBIIBUTCCAU0wggFJBgsrBgEEAYG1NwEBATCC +ATgwLgYIKwYBBQUHAgEWImh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeS5w +ZGYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL2ludGVybWVk +aWF0ZS5wZGYwgc8GCCsGAQUFBwICMIHCMCcWIFN0YXJ0IENvbW1lcmNpYWwgKFN0 +YXJ0Q29tKSBMdGQuMAMCAQEagZZMaW1pdGVkIExpYWJpbGl0eSwgcmVhZCB0aGUg +c2VjdGlvbiAqTGVnYWwgTGltaXRhdGlvbnMqIG9mIHRoZSBTdGFydENvbSBDZXJ0 +aWZpY2F0aW9uIEF1dGhvcml0eSBQb2xpY3kgYXZhaWxhYmxlIGF0IGh0dHA6Ly93 +d3cuc3RhcnRzc2wuY29tL3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgG +CWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1 +dGhvcml0eTANBgkqhkiG9w0BAQsFAAOCAgEAjo/n3JR5fPGFf59Jb2vKXfuM/gTF +wWLRfUKKvFO3lANmMD+x5wqnUCBVJX92ehQN6wQOQOY+2IirByeDqXWmN3PH/UvS +Ta0XQMhGvjt/UfzDtgUx3M2FIk5xt/JxXrAaxrqTi3iSSoX4eA+D/i+tLPfkpLst +0OcNOrg+zvZ49q5HJMqjNTbOx8aHmNrs++myziebiMMEofYLWWivydsQD032ZGNc +pRJvkrKTlMeIFw6Ttn5ii5B/q06f/ON1FE8qMt9bDeD1e5MNq6HPh+GlBEXoPBKl +CcWw0bdT82AUuoVpaiF8H3VhFyAXe2w7QSlc4axa0c2Mm+tgHRns9+Ww2vl5GKVF +P0lDV9LdJNUso/2RjSe15esUBppMeyG7Oq0wBhjA2MFrLH9ZXF2RsXAiV+uKa0hK +1Q8p7MZAwC+ITGgBF3f0JBlPvfrhsiAhS90a2Cl9qrjeVOwhVYBsHvUwyKMQ5bLm +KhQxw4UtjJixhlpPiVktucf3HMiKf8CdBUrmQk9io20ppB+Fq9vlgcitKj1MXVuE +JnHEhV5xJMqlG2zYYdMa4FTbzrqpMrUi9nNBCV24F10OD5mQ1kfabwo6YigUZ4LZ +8dCAWZvLMdibD4x3TrVoivJs9iQOLWxwxXPR3hTQcY+203sC9uO41Alua551hDnm +fyWl8kgAwKQB2j8= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD +QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB +CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 +nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt +43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P +T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 +gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO +BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR +TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw +DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr +hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg +06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF +PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls +YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk +CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDkzCCAnugAwIBAgIQFBOWgxRVjOp7Y+X8NId3RDANBgkqhkiG9w0BAQUFADA0 +MRMwEQYDVQQDEwpDb21TaWduIENBMRAwDgYDVQQKEwdDb21TaWduMQswCQYDVQQG +EwJJTDAeFw0wNDAzMjQxMTMyMThaFw0yOTAzMTkxNTAyMThaMDQxEzARBgNVBAMT +CkNvbVNpZ24gQ0ExEDAOBgNVBAoTB0NvbVNpZ24xCzAJBgNVBAYTAklMMIIBIjAN +BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8ORUaSvTx49qROR+WCf4C9DklBKK +8Rs4OC8fMZwG1Cyn3gsqrhqg455qv588x26i+YtkbDqthVVRVKU4VbirgwTyP2Q2 +98CNQ0NqZtH3FyrV7zb6MBBC11PN+fozc0yz6YQgitZBJzXkOPqUm7h65HkfM/sb +2CEJKHxNGGleZIp6GZPKfuzzcuc3B1hZKKxC+cX/zT/npfo4sdAMx9lSGlPWgcxC +ejVb7Us6eva1jsz/D3zkYDaHL63woSV9/9JLEYhwVKZBqGdTUkJe5DSe5L6j7Kpi +Xd3DTKaCQeQzC6zJMw9kglcq/QytNuEMrkvF7zuZ2SOzW120V+x0cAwqTwIDAQAB +o4GgMIGdMAwGA1UdEwQFMAMBAf8wPQYDVR0fBDYwNDAyoDCgLoYsaHR0cDovL2Zl +ZGlyLmNvbXNpZ24uY28uaWwvY3JsL0NvbVNpZ25DQS5jcmwwDgYDVR0PAQH/BAQD +AgGGMB8GA1UdIwQYMBaAFEsBmz5WGmU2dst7l6qSBe4y5ygxMB0GA1UdDgQWBBRL +AZs+VhplNnbLe5eqkgXuMucoMTANBgkqhkiG9w0BAQUFAAOCAQEA0Nmlfv4pYEWd +foPPbrxHbvUanlR2QnG0PFg/LUAlQvaBnPGJEMgOqnhPOAlXsDzACPw1jvFIUY0M +cXS6hMTXcpuEfDhOZAYnKuGntewImbQKDdSFc8gS4TXt8QUxHXOZDOuWyt3T5oWq +8Ir7dcHyCTxlZWTzTNity4hp8+SDtwy9F1qWF8pb/627HOkthIDYIb6FUtnUdLlp +hbpN7Sgy6/lhSuTENh4Z3G+EER+V9YMoGKgzkkMn3V0TBEVPh9VGzT2ouvDzuFYk +Res3x+F2T3I5GN9+dHLHcy056mDmrRGiVod7w2ia/viMcKjfZTL0pECMocJEAw6U +AGegcQCCSA== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEZDCCA0ygAwIBAgIQRL4Mi1AAJLQR0zYwS8AzdzANBgkqhkiG9w0BAQUFADCB +ozELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug +Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho +dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzApBgNVBAMTIlVUTi1VU0VSRmlyc3Qt +TmV0d29yayBBcHBsaWNhdGlvbnMwHhcNOTkwNzA5MTg0ODM5WhcNMTkwNzA5MTg1 +NzQ5WjCBozELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0 +IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYD +VQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzApBgNVBAMTIlVUTi1VU0VS +Rmlyc3QtTmV0d29yayBBcHBsaWNhdGlvbnMwggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQCz+5Gh5DZVhawGNFugmliy+LUPBXeDrjKxdpJo7CNKyXY/45y2 +N3kDuatpjQclthln5LAbGHNhSuh+zdMvZOOmfAz6F4CjDUeJT1FxL+78P/m4FoCH +iZMlIJpDgmkkdihZNaEdwH+DBmQWICzTSaSFtMBhf1EI+GgVkYDLpdXuOzr0hARe +YFmnjDRy7rh4xdE7EkpvfmUnuaRVxblvQ6TFHSyZwFKkeEwVs0CYCGtDxgGwenv1 +axwiP8vv/6jQOkt2FZ7S0cYu49tXGzKiuG/ohqY/cKvlcJKrRB5AUPuco2LkbG6g +yN7igEL66S/ozjIEj3yNtxyjNTwV3Z7DrpelAgMBAAGjgZEwgY4wCwYDVR0PBAQD +AgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFPqGydvguul49Uuo1hXf8NPh +ahQ8ME8GA1UdHwRIMEYwRKBCoECGPmh0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9V +VE4tVVNFUkZpcnN0LU5ldHdvcmtBcHBsaWNhdGlvbnMuY3JsMA0GCSqGSIb3DQEB +BQUAA4IBAQCk8yXM0dSRgyLQzDKrm5ZONJFUICU0YV8qAhXhi6r/fWRRzwr/vH3Y +IWp4yy9Rb/hCHTO967V7lMPDqaAt39EpHx3+jz+7qEUqf9FuVSTiuwL7MT++6Lzs +QCv4AdRWOOTKRIK1YSAhZ2X28AvnNPilwpyjXEAfhZOVBt5P1CeptqX8Fs1zMT+4 +ZSfP1FMa8Kxun08FDAOBp4QpxFq9ZFdyrTvPNximmMatBrTcCKME1SmklpoSZ0qM +YEWd8SOasACcaLWYUNPvji6SZbFIPiG+FTAqDbUMo2s/rn9X9R+WfN9v3YIwLGUb +QErNaLly7HF27FSOH4UMAWr6pjisH8SE +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv +b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl +cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c +JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP +mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+ +wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4 +VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/ +AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB +AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW +BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun +pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC +dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf +fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm +NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx +H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe ++o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDEL +MAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMp +IDIwMDcgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAi +BgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMjAeFw0wNzExMDUwMDAw +MDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh +d3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBGb3Ig +YXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9v +dCBDQSAtIEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/ +BebfowJPDQfGAFG6DAJSLSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6 +papu+7qzcMBniKI11KOasf2twu8x+qi58/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8E +BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUmtgAMADna3+FGO6Lts6K +DPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUNG4k8VIZ3 +KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41ox +XZ3Krr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIETTCCAzWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBtMQswCQYDVQQGEwJDSDEO +MAwGA1UEChMFYWRtaW4xETAPBgNVBAsTCFNlcnZpY2VzMSIwIAYDVQQLExlDZXJ0 +aWZpY2F0aW9uIEF1dGhvcml0aWVzMRcwFQYDVQQDEw5BZG1pbkNBLUNELVQwMTAe +Fw0wNjAxMjUxMzM2MTlaFw0xNjAxMjUxMjM2MTlaMG0xCzAJBgNVBAYTAkNIMQ4w +DAYDVQQKEwVhZG1pbjERMA8GA1UECxMIU2VydmljZXMxIjAgBgNVBAsTGUNlcnRp +ZmljYXRpb24gQXV0aG9yaXRpZXMxFzAVBgNVBAMTDkFkbWluQ0EtQ0QtVDAxMIIB +IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0jQlMZmpLDhV+GNR9TAoSNle +JgQB4xAXJELQf5/ySMfoFA4MmjKqYXQkB6MGPuQKwR9XRRSPf61vqb8YPsdjRmgp +byHBcUd5t0N8RX6wRZUnPMW+bCCo2VqAU4XFbnlc2gHKaam0wdTtbBTXEkv0ieIH +fxCfFxXqSsSr60IkF/2/xbrAgV/QD5yHk6Ie8feAVWwi5UtaFqtu4LiFEh2QMyxs +Oyz1OcvKzkM2g873tyiE7jzMgZP+Ww3tibk2F9+e6ZeiB37TLOmVtvgpmrws4fiI +rFNXEYSWBVrUTbn81U47yWzOgf5fEHP07bRV5QOCzCm99qNimsbL6CG7nT78CQID +AQABo4H3MIH0MBIGA1UdEwEB/wQIMAYBAf8CAQAwga4GA1UdIASBpjCBozCBoAYI +YIV0AREDFQEwgZMwSAYIKwYBBQUHAgIwPBo6VGhpcyBpcyB0aGUgQWRtaW5DQS1D +RC1UMDEgQ2VydGlmaWNhdGUgUHJhY3RpY2UgU3RhdGVtZW50LjBHBggrBgEFBQcC +ARY7aHR0cDovL3d3dy5wa2kuYWRtaW4uY2gvcG9saWN5L0NQU18yXzE2Xzc1Nl8x +XzE3XzNfMjFfMS5wZGYwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBQqxGkKocZV +xgNucM6GgbOkD6oZ2zANBgkqhkiG9w0BAQUFAAOCAQEAn356bbusjI5glGXRQ1DR +v21qQf0S4s3GHyZm7cqdOkFleM70ArBT+kOP5Nm7rlSAFyVgEkmBdOg7s9tlXClU +yeZFnp6UEYRUcijPN8D1VaNRK6PIUObpDBQT0C+kAfxG9z4v29T0SxT4sgAdC/xQ +Fyv58Fp9bPn7owuKwKcyCH1XSyi/Bp4XFELlLOaigBZO/w+dPBz4FcJSdZjU+BaJ +0E3nKAjHlShO5ouBSZnaJz3p+nkw2Wyo36s6GxCK0XbkSP45iniIG4FmwwZkonYF +ypQntHbx2oL7tUQQY0PDo8bGBMcPy/G2j+dciqZRlsnfgMy10SCzQ9MUx92xUG2V +eg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFVTCCBD2gAwIBAgIEO/OB0DANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQGEwJj +aDEOMAwGA1UEChMFYWRtaW4xETAPBgNVBAsTCFNlcnZpY2VzMSIwIAYDVQQLExlD +ZXJ0aWZpY2F0aW9uIEF1dGhvcml0aWVzMRYwFAYDVQQDEw1BZG1pbi1Sb290LUNB +MB4XDTAxMTExNTA4NTEwN1oXDTIxMTExMDA3NTEwN1owbDELMAkGA1UEBhMCY2gx +DjAMBgNVBAoTBWFkbWluMREwDwYDVQQLEwhTZXJ2aWNlczEiMCAGA1UECxMZQ2Vy +dGlmaWNhdGlvbiBBdXRob3JpdGllczEWMBQGA1UEAxMNQWRtaW4tUm9vdC1DQTCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMvgr0QUIv5qF0nyXZ3PXAJi +C4C5Wr+oVTN7oxIkXkxvO0GJToM9n7OVJjSmzBL0zJ2HXj0MDRcvhSY+KiZZc6Go +vDvr5Ua481l7ILFeQAFtumeza+vvxeL5Nd0Maga2miiacLNAKXbAcUYRa0Ov5VZB +++YcOYNNt/aisWbJqA2y8He+NsEgJzK5zNdayvYXQTZN+7tVgWOck16Da3+4FXdy +fH1NCWtZlebtMKtERtkVAaVbiWW24CjZKAiVfggjsiLo3yVMPGj3budLx5D9hEEm +vlyDOtcjebca+AcZglppWMX/iHIrx7740y0zd6cWEqiLIcZCrnpkr/KzwO135GkC +AwEAAaOCAf0wggH5MA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIASBkTCBjjCBiwYI +YIV0AREDAQAwfzArBggrBgEFBQcCAjAfGh1UaGlzIGlzIHRoZSBBZG1pbi1Sb290 +LUNBIENQUzBQBggrBgEFBQcCARZEaHR0cDovL3d3dy5pbmZvcm1hdGlrLmFkbWlu +LmNoL1BLSS9saW5rcy9DUFNfMl8xNl83NTZfMV8xN18zXzFfMC5wZGYwfwYDVR0f +BHgwdjB0oHKgcKRuMGwxFjAUBgNVBAMTDUFkbWluLVJvb3QtQ0ExIjAgBgNVBAsT +GUNlcnRpZmljYXRpb24gQXV0aG9yaXRpZXMxETAPBgNVBAsTCFNlcnZpY2VzMQ4w +DAYDVQQKEwVhZG1pbjELMAkGA1UEBhMCY2gwHQYDVR0OBBYEFIKf+iNzIPGXi7JM +Tb5CxX9mzWToMIGZBgNVHSMEgZEwgY6AFIKf+iNzIPGXi7JMTb5CxX9mzWTooXCk +bjBsMQswCQYDVQQGEwJjaDEOMAwGA1UEChMFYWRtaW4xETAPBgNVBAsTCFNlcnZp +Y2VzMSIwIAYDVQQLExlDZXJ0aWZpY2F0aW9uIEF1dGhvcml0aWVzMRYwFAYDVQQD +Ew1BZG1pbi1Sb290LUNBggQ784HQMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0B +AQUFAAOCAQEAeE96XCYRpy6umkPKXDWCRn7INo96ZrWpMggcDORuofHIwdTkgOeM +vWOxDN/yuT7CC3FAaUajbPRbDw0hRMcqKz0aC8CgwcyIyhw/rFK29mfNTG3EviP9 +QSsEbnelFnjpm1wjz4EaBiFjatwpUbI6+Zv3XbEt9QQXBn+c6DeFLe4xvC4B+MTr +a440xTk59pSYux8OHhEvqIwHCkiijGqZhTS3KmGFeBopaR+dJVBRBMoXwzk4B3Hn +0Zib1dEYFZa84vPJZyvxCbLOnPRDJgH6V2uQqbG+6DXVaf/wORVOvF/wzzv0viM/ +RWbEtJZdvo8N3sdtCULzifnxP/V0T9+4ZQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIG0TCCBbmgAwIBAgIBezANBgkqhkiG9w0BAQUFADCByTELMAkGA1UEBhMCSFUx +ETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0 +b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9rMUIwQAYDVQQD +EzlOZXRMb2NrIE1pbm9zaXRldHQgS296amVneXpvaSAoQ2xhc3MgUUEpIFRhbnVz +aXR2YW55a2lhZG8xHjAcBgkqhkiG9w0BCQEWD2luZm9AbmV0bG9jay5odTAeFw0w +MzAzMzAwMTQ3MTFaFw0yMjEyMTUwMTQ3MTFaMIHJMQswCQYDVQQGEwJIVTERMA8G +A1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRvbnNh +Z2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxQjBABgNVBAMTOU5l +dExvY2sgTWlub3NpdGV0dCBLb3pqZWd5em9pIChDbGFzcyBRQSkgVGFudXNpdHZh +bnlraWFkbzEeMBwGCSqGSIb3DQEJARYPaW5mb0BuZXRsb2NrLmh1MIIBIjANBgkq +hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx1Ilstg91IRVCacbvWy5FPSKAtt2/Goq +eKvld/Bu4IwjZ9ulZJm53QE+b+8tmjwi8F3JV6BVQX/yQ15YglMxZc4e8ia6AFQe +r7C8HORSjKAyr7c3sVNnaHRnUPYtLmTeriZ539+Zhqurf4XsoPuAzPS4DB6TRWO5 +3Lhbm+1bOdRfYrCnjnxmOCyqsQhjF2d9zL2z8cM/z1A57dEZgxXbhxInlrfa6uWd +vLrqOU+L73Sa58XQ0uqGURzk/mQIKAR5BevKxXEOC++r6uwSEaEYBTJp0QwsGj0l +mT+1fMptsK6ZmfoIYOcZwvK9UdPM0wKswREMgM6r3JSda6M5UzrWhQIDAMV9o4IC +wDCCArwwEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNVHQ8BAf8EBAMCAQYwggJ1Bglg +hkgBhvhCAQ0EggJmFoICYkZJR1lFTEVNISBFemVuIHRhbnVzaXR2YW55IGEgTmV0 +TG9jayBLZnQuIE1pbm9zaXRldHQgU3pvbGdhbHRhdGFzaSBTemFiYWx5emF0YWJh +biBsZWlydCBlbGphcmFzb2sgYWxhcGphbiBrZXN6dWx0LiBBIG1pbm9zaXRldHQg +ZWxla3Ryb25pa3VzIGFsYWlyYXMgam9naGF0YXMgZXJ2ZW55ZXN1bGVzZW5laywg +dmFsYW1pbnQgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUgYSBNaW5vc2l0ZXR0IFN6 +b2xnYWx0YXRhc2kgU3phYmFseXphdGJhbiwgYXogQWx0YWxhbm9zIFN6ZXJ6b2Rl +c2kgRmVsdGV0ZWxla2JlbiBlbG9pcnQgZWxsZW5vcnplc2kgZWxqYXJhcyBtZWd0 +ZXRlbGUuIEEgZG9rdW1lbnR1bW9rIG1lZ3RhbGFsaGF0b2sgYSBodHRwczovL3d3 +dy5uZXRsb2NrLmh1L2RvY3MvIGNpbWVuIHZhZ3kga2VyaGV0b2sgYXogaW5mb0Bu +ZXRsb2NrLm5ldCBlLW1haWwgY2ltZW4uIFdBUk5JTkchIFRoZSBpc3N1YW5jZSBh +bmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGFyZSBzdWJqZWN0IHRvIHRo +ZSBOZXRMb2NrIFF1YWxpZmllZCBDUFMgYXZhaWxhYmxlIGF0IGh0dHBzOi8vd3d3 +Lm5ldGxvY2suaHUvZG9jcy8gb3IgYnkgZS1tYWlsIGF0IGluZm9AbmV0bG9jay5u +ZXQwHQYDVR0OBBYEFAlqYhaSsFq7VQ7LdTI6MuWyIckoMA0GCSqGSIb3DQEBBQUA +A4IBAQCRalCc23iBmz+LQuM7/KbD7kPgz/PigDVJRXYC4uMvBcXxKufAQTPGtpvQ +MznNwNuhrWw3AkxYQTvyl5LGSKjN5Yo5iWH5Upfpvfb5lHTocQ68d4bDBsxafEp+ +NFAwLvt/MpqNPfMgW/hqyobzMUwsWYACff44yTB1HLdV47yfuqhthCgFdbOLDcCR +VCHnpgu0mfVRQdzNo0ci2ccBgcTcR08m6h/t280NmPSjnLRzMkqWmf68f8glWPhY +83ZmiVSkpj7EUFy6iRiCdUgh0k8T6GB+B3bbELVR5qq5aKrN9p2QdRLqOBrKROi3 +macqaJVmlaut74nLYKkGEsaUR+ko +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQsw +CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu +ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe +Fw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVTMRUw +EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x +IDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0CAQYF +K4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FG +fp4tn+6OYwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPO +Z9wj/wMco+I+o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAd +BgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNpYim8S8YwCgYIKoZIzj0EAwMDaAAwZQIx +AK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y3maTD/HMsQmP3Wyr+mt/ +oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34VOKa5Vt8 +sycX +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFkjCCA3qgAwIBAgIBCDANBgkqhkiG9w0BAQUFADA6MQswCQYDVQQGEwJDTjER +MA8GA1UEChMIVW5pVHJ1c3QxGDAWBgNVBAMTD1VDQSBHbG9iYWwgUm9vdDAeFw0w +ODAxMDEwMDAwMDBaFw0zNzEyMzEwMDAwMDBaMDoxCzAJBgNVBAYTAkNOMREwDwYD +VQQKEwhVbmlUcnVzdDEYMBYGA1UEAxMPVUNBIEdsb2JhbCBSb290MIICIjANBgkq +hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA2rPlBlA/9nP3xDK/RqUlYjOHsGj+p9+I +A2N9Apb964fJ7uIIu527u+RBj8cwiQ9tJMAEbBSUgU2gDXRm8/CFr/hkGd656YGT +0CiFmUdCSiw8OCdKzP/5bBnXtfPvm65bNAbXj6ITBpyKhELVs6OQaG2BkO5NhOxM +cE4t3iQ5zhkAQ5N4+QiGHUPR9HK8BcBn+sBR0smFBySuOR56zUHSNqth6iur8CBV +mTxtLRwuLnWW2HKX4AzKaXPudSsVCeCObbvaE/9GqOgADKwHLx25urnRoPeZnnRc +GQVmMc8+KlL+b5/zub35wYH1N9ouTIElXfbZlJrTNYsgKDdfUet9Ysepk9H50DTL +qScmLCiQkjtVY7cXDlRzq6987DqrcDOsIfsiJrOGrCOp139tywgg8q9A9f9ER3Hd +J90TKKHqdjn5EKCgTUCkJ7JZFStsLSS3JGN490MYeg9NEePorIdCjedYcaSrbqLA +l3y74xNLytu7awj5abQEctXDRrl36v+6++nwOgw19o8PrgaEFt2UVdTvyie3AzzF +HCYq9TyopZWbhvGKiWf4xwxmse1Bv4KmAGg6IjTuHuvlb4l0T2qqaqhXZ1LUIGHB +zlPL/SR/XybfoQhplqCe/klD4tPq2sTxiDEhbhzhzfN1DiBEFsx9c3Q1RSw7gdQg +7LYJjD5IskkCAwEAAaOBojCBnzALBgNVHQ8EBAMCAQYwDAYDVR0TBAUwAwEB/zBj +BgNVHSUEXDBaBggrBgEFBQcDAQYIKwYBBQUHAwIGCCsGAQUFBwMDBggrBgEFBQcD +BAYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEFBQcDBwYIKwYBBQUHAwgGCCsGAQUF +BwMJMB0GA1UdDgQWBBTZw9P4gJJnzF3SOqLXcaK0xDiALTANBgkqhkiG9w0BAQUF +AAOCAgEA0Ih5ygiq9ws0oE4Jwul+NUiJcIQjL1HDKy9e21NrW3UIKlS6Mg7VxnGF +sZdJgPaE0PC6t3GUyHlrpsVE6EKirSUtVy/m1jEp+hmJVCl+t35HNmktbjK81HXa +QnO4TuWDQHOyXd/URHOmYgvbqm4FjMh/Rk85hZCdvBtUKayl1/7lWFZXbSyZoUkh +1WHGjGHhdSTBAd0tGzbDLxLMC9Z4i3WA6UG5iLHKPKkWxk4V43I29tSgQYWvimVw +TbVEEFDs7d9t5tnGwBLxSzovc+k8qe4bqi81pZufTcU0hF8mFGmzI7GJchT46U1R +IgP/SobEHOh7eQrbRyWBfvw0hKxZuFhD5D1DCVR0wtD92e9uWfdyYJl2b/Unp7uD +pEqB7CmB9HdL4UISVdSGKhK28FWbAS7d9qjjGcPORy/AeGEYWsdl/J1GW1fcfA67 +loMQfFUYCQSu0feLKj6g5lDWMDbX54s4U+xJRODPpN/xU3uLWrb2EZBL1nXz/gLz +Ka/wI3J9FO2pXd96gZ6bkiL8HvgBRUGXx2sBYb4zaPKgZYRmvOAqpGjTcezHCN6j +w8k2SjTxF+KAryAhk5Qe5hXTVGLxtTgv48y5ZwSpuuXu+RBuyy5+E6+SFP7zJ3N7 +OPxzbbm5iPZujAv1/P8JDrMtXnt145Ik4ubhWD5LKAN1axibRww= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDdjCCAl6gAwIBAgIEOhsEBTANBgkqhkiG9w0BAQUFADBRMQswCQYDVQQGEwJE +SzEMMAoGA1UEChMDS01EMQ8wDQYDVQQLEwZLTUQtQ0ExIzAhBgNVBAMTGktNRC1D +QSBLdmFsaWZpY2VyZXQgUGVyc29uMB4XDTAwMTEyMTIzMjQ1OVoXDTE1MTEyMjIz +MjQ1OVowUTELMAkGA1UEBhMCREsxDDAKBgNVBAoTA0tNRDEPMA0GA1UECxMGS01E +LUNBMSMwIQYDVQQDExpLTUQtQ0EgS3ZhbGlmaWNlcmV0IFBlcnNvbjCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBANriF4Xd6yD7ZlBE317UBDObn+vRMVc6 +p3wNQODdEDJe2z1ncCz9NJvhoLGdOJhyg7VVPh0P2c+KZ9WI9mWOKZI2bp2WkLju +jCcxbhTrurY3Wfc6gwLBqqFV8wWgaZKmvVWizjw9Kyi25f3yX4fOho6Qq2lvVbub +tvVFXAd51GJ+/2Yed+a4Or2bz2RcqHS81B3pywsD4mgJR5xREv5jqPfwNP+V7bkc +X+pfO4kVhZ/V+8MSPdQHgcV/iB3wP2mwgWyIBNc1reBidGTiz8unnWu55hcNfsvt +LJbTs9OHhsR7naRuy+S402nDnD5vnONOFEsiHn46w+T0rtu7h6j4OvkCAwEAAaNW +MFQwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUeWLqmhI42Jxj7DifDsW+ +DlQhKD0wHwYDVR0jBBgwFoAUeWLqmhI42Jxj7DifDsW+DlQhKD0wDQYJKoZIhvcN +AQEFBQADggEBANML/P42OuJ9aUV/0fItuIyc1JhqWvSqn5bXj+9eyEegcp8bHLHY +42D1O+z0lNipdjYPSdMJ0wZOEUhr+150SdDQ1P/zQL8AUaLEBkRt7ZdzXPVH3PER +qnf9IrpYBknZKfCAoVchA6Rr9WU3Sd8bMoRfMLKg8c0M8G6EPwCTcOFriSkbtvNG +zd8r8I+WfUYIN/p8DI9JT9qfjVODnYPRMUm6KPvq27TsrGruKrqyaV94kWc8co8A +v3zFLeCtghvUiRBdx+8Q7m5t4CkuSr0WINrqjIPFW2QrM1r82y09Fd16RkqL4LOg +Lh6vB5KnTApv62rWdw7zWwYnjY6/vXYY1Aw= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIF4DCCA8igAwIBAgIRAPL6ZOJ0Y9ON/RAdBB92ylgwDQYJKoZIhvcNAQELBQAw +ZzELMAkGA1UEBhMCY2gxETAPBgNVBAoTCFN3aXNzY29tMSUwIwYDVQQLExxEaWdp +dGFsIENlcnRpZmljYXRlIFNlcnZpY2VzMR4wHAYDVQQDExVTd2lzc2NvbSBSb290 +IEVWIENBIDIwHhcNMTEwNjI0MDk0NTA4WhcNMzEwNjI1MDg0NTA4WjBnMQswCQYD +VQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0YWwgQ2Vy +dGlmaWNhdGUgU2VydmljZXMxHjAcBgNVBAMTFVN3aXNzY29tIFJvb3QgRVYgQ0Eg +MjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMT3HS9X6lds93BdY7Bx +UglgRCgzo3pOCvrY6myLURYaVa5UJsTMRQdBTxB5f3HSek4/OE6zAMaVylvNwSqD +1ycfMQ4jFrclyxy0uYAyXhqdk/HoPGAsp15XGVhRXrwsVgu42O+LgrQ8uMIkqBPH +oCE2G3pXKSinLr9xJZDzRINpUKTk4RtiGZQJo/PDvO/0vezbE53PnUgJUmfANykR +HvvSEaeFGHR55E+FFOtSN+KxRdjMDUN/rhPSays/p8LiqG12W0OfvrSdsyaGOx9/ +5fLoZigWJdBLlzin5M8J0TbDC77aO0RYjb7xnglrPvMyxyuHxuxenPaHZa0zKcQv +idm5y8kDnftslFGXEBuGCxobP/YCfnvUxVFkKJ3106yDgYjTdLRZncHrYTNaRdHL +OdAGalNgHa/2+2m8atwBz735j9m9W8E6X47aD0upm50qKGsaCnw8qyIL5XctcfaC +NYGu+HuB5ur+rPQam3Rc6I8k9l2dRsQs0h4rIWqDJ2dVSqTjyDKXZpBy2uPUZC5f +46Fq9mDU5zXNysRojddxyNMkM3OxbPlq4SjbX8Y96L5V5jcb7STZDxmPX2MYWFCB +UWVv8p9+agTnNCRxunZLWB4ZvRVgRaoMEkABnRDixzgHcgplwLa7JSnaFp6LNYth +7eVxV4O1PHGf40+/fh6Bn0GXAgMBAAGjgYYwgYMwDgYDVR0PAQH/BAQDAgGGMB0G +A1UdIQQWMBQwEgYHYIV0AVMCAgYHYIV0AVMCAjASBgNVHRMBAf8ECDAGAQH/AgED +MB0GA1UdDgQWBBRF2aWBbj2ITY1x0kbBbkUe88SAnTAfBgNVHSMEGDAWgBRF2aWB +bj2ITY1x0kbBbkUe88SAnTANBgkqhkiG9w0BAQsFAAOCAgEAlDpzBp9SSzBc1P6x +XCX5145v9Ydkn+0UjrgEjihLj6p7jjm02Vj2e6E1CqGdivdj5eu9OYLU43otb98T +PLr+flaYC/NUn81ETm484T4VvwYmneTwkLbUwp4wLh/vx3rEUMfqe9pQy3omywC0 +Wqu1kx+AiYQElY2NfwmTv9SoqORjbdlk5LgpWgi/UOGED1V7XwgiG/W9mR4U9s70 +WBCCswo9GcG/W6uqmdjyMb3lOGbcWAXH7WMaLgqXfIeTK7KK4/HsGOV1timH59yL +Gn602MnTihdsfSlEvoqq9X46Lmgxk7lq2prg2+kupYTNHAq4Sgj5nPFhJpiTt3tm +7JFe3VE/23MPrQRYCd0EApUKPtN236YQHoA96M2kZNEzx5LH4k5E4wnJTsJdhw4S +nr8PyQUQ3nqjsTzyP6WqJ3mtMX0f/fwZacXduT98zca0wjAefm6S139hdlqP65VN +vBFuIXxZN5nQBrz5Bm0yFqXZaajh3DyAHmBR3NdUIR7KYndP+tiPsys6DXhyyWhB +WkdKwqPrGtcKqzwyVcgKEZzfdNbwQBUdyLmPtTbFr/giuMod89a2GQ+fYWVq6nTI +fI/DT11lgh/ZDYnadXL77/FHZxOzyNEZiCcmmpl5fx7kLD977vHeTYuWl8PVP3wb +I+2ksx0WckNLIOFZfsLorSa/ovc= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4 +MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6 +ZW5wZS5jb20wHhcNMDcxMjEzMTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYD +VQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5j +b20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ03rKDx6sp4boFmVq +scIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAKClaO +xdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6H +LmYRY2xU+zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFX +uaOKmMPsOzTFlUFpfnXCPCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQD +yCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxTOTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+ +JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbKF7jJeodWLBoBHmy+E60Q +rLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK0GqfvEyN +BjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8L +hij+0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIB +QFqNeb+Lz0vPqhbBleStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+ +HMh3/1uaD7euBUbl8agW7EekFwIDAQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2lu +Zm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+SVpFTlBFIFMuQS4gLSBDSUYg +QTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBGNjIgUzgxQzBB +BgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx +MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwHQYDVR0OBBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUA +A4ICAQB4pgwWSp9MiDrAyw6lFn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWb +laQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbgakEyrkgPH7UIBzg/YsfqikuFgba56 +awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8qhT/AQKM6WfxZSzwo +JNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Csg1lw +LDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCT +VyvehQP5aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGk +LhObNA5me0mrZJfQRsN5nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJb +UjWumDqtujWTI6cfSN01RpiyEGjkpTHCClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/ +QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZoQ0iy2+tzJOeRf1SktoA+ +naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1ZWrOZyGls +QyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDczCCAlugAwIBAgIQMDAwMDk3Mzc1NzM4NjAwMDANBgkqhkiG9w0BAQUFADBV +MQswCQYDVQQGEwJGUjETMBEGA1UEChMKQ2VydGlOb21pczEcMBoGA1UECxMTQUMg +UmFjaW5lIC0gUm9vdCBDQTETMBEGA1UEAxMKQ2VydGlOb21pczAeFw0wMDExMDkw +MDAwMDBaFw0xMjExMDkwMDAwMDBaMFUxCzAJBgNVBAYTAkZSMRMwEQYDVQQKEwpD +ZXJ0aU5vbWlzMRwwGgYDVQQLExNBQyBSYWNpbmUgLSBSb290IENBMRMwEQYDVQQD +EwpDZXJ0aU5vbWlzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8SWb +4mS5RXB3ENSIcfrEzCj/TRUQuT1tMCU0YUfXFSgcPdWglIzCv3kvh07QoB+8xMl+ +fQHvSSduAxnNewz0GBY9rApCPKlP6CcnJr74OSVZIiWt9wLfl4wwhNhZOiikIpZp +EdOXWqRc84P5cUlN3Lwmr1sjCWmHfTSS4cAKxfDbFLfE61etosyoFZUTQbIhb1Bf +JL5xRXAUZudQiU42n/yAoSUrN4FLUfPQNlOe1AB81pIgX8g2ojwxDjfgqSs1JmBF +uLKJ45uVLEenQBPmQCGjL3maV86IRmR3a9UGlgvKAk0NBdh8mrQyQvcUlLBIQBCm +l7wppt6maQHUNEPQSwIDAQABoz8wPTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQU+F4ho6ijFeb4tRG7/kIEXU2OgnowDQYJKoZIhvcNAQEF +BQADggEBACe9FJayK6bXkJQrilBFMh75QPdFOks9PJuo86OMUlBDZGYFTCh9Arex +N3KYCnAEzazYIALwr7eASJJDIQMu1Q+pkx/7ACde4kP47F27M2rm+v5HnGooCLz2 +s7Fe/WUycTQqgwF5lNp03m1ce/TvovgkEZeVN5wM/7+SsZLJGDigXGeq48j2g2hn +8OckX9Ciyo0U3/1IVeigNBisiaOlsHSZOEPBZQRiZULob+NVbXVPo8nM1OyP3aHI +LQex1yYcCr9m93nOiZyKkur3Uedf1yMTBe+fflnPFKGYnVqvTGXCKVdHzQBfpILA +AuaC+5ykZhSiSMf8nmL2oPMcLO7YQw4= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx +KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd +BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl +YyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgxMDAxMTAyOTU2WhcNMzMxMDAxMjM1 +OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy +aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50 +ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN +8ELg63iIVl6bmlQdTQyK9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/ +RLyTPWGrTs0NvvAgJ1gORH8EGoel15YUNpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4 +hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZFiP0Zf3WHHx+xGwpzJFu5 +ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W0eDrXltM +EnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGj +QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1 +A/d2O2GCahKqGFPrAyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOy +WL6ukK2YJ5f+AbGwUgC4TeQbIXQbfsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ +1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzTucpH9sry9uetuUg/vBa3wW30 +6gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7hP0HHRwA11fXT +91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml +e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4p +TpPDpFQUWw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G +A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp +Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1 +MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG +A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL +v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8 +eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq +tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd +C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa +zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB +mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH +V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n +bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG +3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs +J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO +291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS +ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd +AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7 +TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDoTCCAomgAwIBAgIQKTZHquOKrIZKI1byyrdhrzANBgkqhkiG9w0BAQUFADBO +MQswCQYDVQQGEwJ1czEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQ0wCwYDVQQL +EwRGQkNBMRYwFAYDVQQDEw1Db21tb24gUG9saWN5MB4XDTA3MTAxNTE1NTgwMFoX +DTI3MTAxNTE2MDgwMFowTjELMAkGA1UEBhMCdXMxGDAWBgNVBAoTD1UuUy4gR292 +ZXJubWVudDENMAsGA1UECxMERkJDQTEWMBQGA1UEAxMNQ29tbW9uIFBvbGljeTCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJeNvTMn5K1b+3i9L0dHbsd4 +6ZOcpN7JHP0vGzk4rEcXwH53KQA7Ax9oD81Npe53uCxiazH2+nIJfTApBnznfKM9 +hBiKHa4skqgf6F5PjY7rPxr4nApnnbBnTfAu0DDew5SwoM8uCjR/VAnTNr2kSVdS +c+md/uRIeUYbW40y5KVIZPMiDZKdCBW/YDyD90ciJSKtKXG3d+8XyaK2lF7IMJCk +FEhcVlcLQUwF1CpMP64Sm1kRdXAHImktLNMxzJJ+zM2kfpRHqpwJCPZLr1LoakCR +xVW9QLHIbVeGlRfmH3O+Ry4+i0wXubklHKVSFzYIWcBCvgortFZRPBtVyYyQd+sC +AwEAAaN7MHkwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O +BBYEFC9Yl9ipBZilVh/72at17wI8NjTHMBIGCSsGAQQBgjcVAQQFAgMBAAEwIwYJ +KwYBBAGCNxUCBBYEFHa3YJbdFFYprHWF03BjwbxHhhyLMA0GCSqGSIb3DQEBBQUA +A4IBAQBgrvNIFkBypgiIybxHLCRLXaCRc+1leJDwZ5B6pb8KrbYq+Zln34PFdx80 +CTj5fp5B4Ehg/uKqXYeI6oj9XEWyyWrafaStsU+/HA2fHprA1RRzOCuKeEBuMPdi +4c2Z/FFpZ2wR3bgQo2jeJqVW/TZsN5hs++58PGxrcD/3SDcJjwtCga1GRrgLgwb0 +Gzigf0/NC++DiYeXHIowZ9z9VKEDfgHLhUyxCynDvux84T8PCVI8L6eaSP436REG +WOE2QYrEtr+O3c5Ks7wawM36GpnScZv6z7zyxFSjiDV2zBssRm8MtNHDYXaSdBHq +S4CNHIkRi+xb/xfJSPzn4AYR4oRe +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFYzCCA0ugAwIBAgIBOzANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJJTDEW +MBQGA1UEChMNU3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlm +aWNhdGlvbiBBdXRob3JpdHkgRzIwHhcNMTAwMTAxMDEwMDAxWhcNMzkxMjMxMjM1 +OTAxWjBTMQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjEsMCoG +A1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgRzIwggIiMA0G +CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2iTZbB7cgNr2Cu+EWIAOVeq8Oo1XJ +JZlKxdBWQYeQTSFgpBSHO839sj60ZwNq7eEPS8CRhXBF4EKe3ikj1AENoBB5uNsD +vfOpL9HG4A/LnooUCri99lZi8cVytjIl2bLzvWXFDSxu1ZJvGIsAQRSCb0AgJnoo +D/Uefyf3lLE3PbfHkffiAez9lInhzG7TNtYKGXmu1zSCZf98Qru23QumNK9LYP5/ +Q0kGi4xDuFby2X8hQxfqp0iVAXV16iulQ5XqFYSdCI0mblWbq9zSOdIxHWDirMxW +RST1HFSr7obdljKF+ExP6JV2tgXdNiNnvP8V4so75qbsO+wmETRIjfaAKxojAuuK +HDp2KntWFhxyKrOq42ClAJ8Em+JvHhRYW6Vsi1g8w7pOOlz34ZYrPu8HvKTlXcxN +nw3h3Kq74W4a7I/htkxNeXJdFzULHdfBR9qWJODQcqhaX2YtENwvKhOuJv4KHBnM +0D4LnMgJLvlblnpHnOl68wVQdJVznjAJ85eCXuaPOQgeWeU1FEIT/wCc976qUM/i +UUjXuG+v+E5+M5iSFGI6dWPPe/regjupuznixL0sAA7IF6wT700ljtizkC+p2il9 +Ha90OrInwMEePnWjFqmveiJdnxMaz6eg6+OGCtP95paV1yPIN93EfKo2rJgaErHg +TuixO/XWb/Ew1wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE +AwIBBjAdBgNVHQ4EFgQUS8W0QGutHLOlHGVuRjaJhwUMDrYwDQYJKoZIhvcNAQEL +BQADggIBAHNXPyzVlTJ+N9uWkusZXn5T50HsEbZH77Xe7XRcxfGOSeD8bpkTzZ+K +2s06Ctg6Wgk/XzTQLwPSZh0avZyQN8gMjgdalEVGKua+etqhqaRpEpKwfTbURIfX +UfEpY9Z1zRbkJ4kd+MIySP3bmdCPX1R0zKxnNBFi2QwKN4fRoxdIjtIXHfbX/dtl +6/2o1PXWT6RbdejF0mCy2wl+JYt7ulKSnj7oxXehPOBKc2thz4bcQ///If4jXSRK +9dNtD2IEBVeC2m6kMyV5Sy5UGYvMLD0w6dEG/+gyRr61M3Z3qAFdlsHB1b6uJcDJ +HgoJIIihDsnzb02CVAAgp9KP5DlUFy6NHrgbuxu9mk47EDTcnIhT76IxW1hPkWLI +wpqazRVdOKnWvvgTtZ8SafJQYqz7Fzf07rh1Z2AQ+4NQ+US1dZxAF7L+/XldblhY +XzD8AK6vM8EOTmy6p6ahfzLbOOCxchcKK5HsamMm7YnUeMx0HgX4a/6ManY5Ka5l +IxKVCCIcl85bBu4M4ru8H0ST9tg4RQUh7eStqxK2A6RCLi3ECToDZ2mEmuFZkIoo +hdVddLHRDiBYmxOlsGOm7XtH/UVVMKTumtTm4ofvmMkyghEpIrwACjFeLQ/Ajulr +so8uBtjRkcfGEvRM/TAXw8HaOFvjqermobp573PYtlNXLfbQ4ddI +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEP +MA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAx +MDQwNjA3Mjk0MFoXDTIxMDQwNjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNV +BAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMiBDQTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3/Ei9vX+ALTU74W+o +Z6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybTdXnt +5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s +3TmVToMGf+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2Ej +vOr7nQKV0ba5cTppCD8PtOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu +8nYybieDwnPz3BjotJPqdURrBGAgcVeHnfO+oJAjPYok4doh28MCAwEAAaMzMDEw +DwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITTXjwwCwYDVR0PBAQDAgEG +MA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt0jSv9zil +zqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/ +3DEIcbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvD +FNr450kkkdAdavphOe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6 +Tk6ezAyNlNzZRZxe7EJQY670XcSxEtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2 +ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLHllpwrN9M +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDoDCCAoigAwIBAgIBMTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJKUDEO +MAwGA1UEChMFTEdQS0kxGjAYBgNVBAsTEUFwcGxpY2F0aW9uIENBIEcyMB4XDTA2 +MDMzMTE1MDAwMFoXDTE2MDMzMTE0NTk1OVowOTELMAkGA1UEBhMCSlAxDjAMBgNV +BAoTBUxHUEtJMRowGAYDVQQLExFBcHBsaWNhdGlvbiBDQSBHMjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBALk1xhD422jbB8RATLAdHjbcw0H2z1UVbQh/ +XMZoVeXnV/GWUebhTXgPbkAVcDtl/hHf59PWWDU74Z8C/JRSRi6znmCbAp7JgtL2 +464JT4REtmKbAFFouDqt7GTRMkvplESDtA7OIYlrsDbAmMZLnMI+W2AqCTErLatM +3rGg/VhWwoMdILzEhAmHe6iVl8YljoPgPpMN0cd9c6mo/BkAQC4iuHozQfV4/Vpx +54LZSIhc7KiFhy1tgIlnGmm+EMBaju2IfT5vLDhrN85H2KIxMN5+U2Vsi4ZTQSBs +vUilfq8AWlYSWIHR3IlZ+bXu+E2a2EQpi3mn9yKq6nxctBaIIA0CAwEAAaOBsjCB +rzAdBgNVHQ4EFgQUf7hdjsQYa8Z9zC7prs405xdd4KEwDgYDVR0PAQH/BAQDAgEG +MEwGA1UdHwRFMEMwQaA/oD2kOzA5MQswCQYDVQQGEwJKUDEOMAwGA1UEChMFTEdQ +S0kxGjAYBgNVBAsTEUFwcGxpY2F0aW9uIENBIEcyMA8GA1UdEwEB/wQFMAMBAf8w +HwYDVR0jBBgwFoAUf7hdjsQYa8Z9zC7prs405xdd4KEwDQYJKoZIhvcNAQEFBQAD +ggEBADzYczZABkhKVBn1J0g5JaVuQue2zRvLOTS3m+xPKr535MqE/B3rmyJA1fT7 +aIdy/Eddag5SSuO1XUjGIpbmM21tq/bN18skWoyoRZ4+YYJ9lNUF8Bo1X3EvLlS1 +QQXvhg1S75yYG/EsTDrR84bTjD56L4ZFjoMyJlu/U8oOUVbcmsJaMBkNp57Vqpsg +OWl4IfSXbdEOEUwu0xtasPmXeFwqj1Jl7kxCJcI3MA5tKzWUgwbor0U7BGanMLv5 +4CE7Y259RF06alPvERck/VSyWmxzViHJbC2XpEKzJ2EFIWNt6ii8TxpvQtyYq1XT +HhvAkj+bweY7F1bixJhDJe62ywA= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICZzCCAdCgAwIBAgIBBDANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQGEwJVUzEY +MBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxDDAKBgNVBAsT +A1BLSTEcMBoGA1UEAxMTRG9EIENMQVNTIDMgUm9vdCBDQTAeFw0wMDA1MTkxMzEz +MDBaFw0yMDA1MTQxMzEzMDBaMGExCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMu +IEdvdmVybm1lbnQxDDAKBgNVBAsTA0RvRDEMMAoGA1UECxMDUEtJMRwwGgYDVQQD +ExNEb0QgQ0xBU1MgMyBSb290IENBMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB +gQC1MP5kvurMbe2BLPd/6Rm6DmlqKOGpqcuVWB/x5pppU+CIP5HFUbljl6jmIYwT +XjY8qFf6+HAsTGrLvzCnTBbkMlz4ErBR+BZXjS+0TfouqJToKmHUVw1Hzm4sL36Y +Z8wACKu2lhY1woWR5VugCsdmUmLzYXWVF668KlYppeArUwIDAQABoy8wLTAdBgNV +HQ4EFgQUbJyl8FyPbUGNxBc7kFfCD6PNbf4wDAYDVR0TBAUwAwEB/zANBgkqhkiG +9w0BAQUFAAOBgQCvcUT5lyPMaGmMQwdBuoggsyIAQciYoFUczT9usZNcrfoYmrsc +c2/9JEKPh59Rz76Gn+nXikhPCNlplKw/5g8tlw8ok3ZPYt//oM1h+KaGDDE0INx/ +L6j7Ob6V7jhZAmLB3mwVT+DfnbvkeXMk/WNklfdKqJkfSGWVx3u/eDLneg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFUjCCBDqgAwIBAgIBAjANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJLUjEN +MAsGA1UEChMES0lTQTEuMCwGA1UECxMlS29yZWEgQ2VydGlmaWNhdGlvbiBBdXRo +b3JpdHkgQ2VudHJhbDEWMBQGA1UEAxMNS0lTQSBSb290Q0EgMzAeFw0wNDExMTkw +NjM5NTFaFw0xNDExMTkwNjM5NTFaMGQxCzAJBgNVBAYTAktSMQ0wCwYDVQQKEwRL +SVNBMS4wLAYDVQQLEyVLb3JlYSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBDZW50 +cmFsMRYwFAYDVQQDEw1LSVNBIFJvb3RDQSAzMIIBIDANBgkqhkiG9w0BAQEFAAOC +AQ0AMIIBCAKCAQEA3rrtF2Wu0b1KPazbgHLMWOHn4ZPazDB6z+8Lri2nQ6u/p0LP +CFYIpEcdffqG79gwlyY0YTyADvjU65/8IjAboW0+40zSVU4WQDfC9gdu2we1pYyW +geKbXH6UYcjOhDyx+gDmctMJhXfp3F4hT7TkTvTiF6tQrxz/oTlYdVsSspa5jfBw +YkhbVigqpYeRNrkeJPW5unu2UlFbF1pgBWycwubGjD756t08jP+J3kNwrB248XXN +OMpTDUdoasY8GMq94bS+DvTQ49IT+rBRERHUQavo9DmO4TSETwuTqmo4/OXGeEeu +dhf6oYA3BgAVCP1rI476cg2V1ktisWjC3TSbXQIBA6OCAg8wggILMB8GA1UdIwQY +MBaAFI+B8NqmzXQ8vmb0FWtGpP4GKMyqMB0GA1UdDgQWBBSPgfDaps10PL5m9BVr +RqT+BijMqjAOBgNVHQ8BAf8EBAMCAQYwggEuBgNVHSAEggElMIIBITCCAR0GBFUd +IAAwggETMDAGCCsGAQUFBwIBFiRodHRwOi8vd3d3LnJvb3RjYS5vci5rci9yY2Ev +Y3BzLmh0bWwwgd4GCCsGAQUFBwICMIHRHoHOx3QAIMd4yZ3BHLKUACCs9cd4x3jJ +ncEcx4WyyLLkACgAVABoAGkAcwAgAGMAZQByAHQAaQBmAGkAYwBhAHQAZQAgAGkA +cwAgAGEAYwBjAHIAZQBkAGkAdABlAGQAIAB1AG4AZABlAHIAIABFAGwAZQBjAHQA +cgBvAG4AaQBjACAAUwBpAGcAbgBhAHQAdQByAGUAIABBAGMAdAAgAG8AZgAgAHQA +aABlACAAUgBlAHAAdQBiAGwAaQBjACAAbwBmACAASwBvAHIAZQBhACkwMwYDVR0R +BCwwKqQoMCYxJDAiBgNVBAMMG+2VnOq1reygleuztOuztO2YuOynhO2dpeybkDAz +BgNVHRIELDAqpCgwJjEkMCIGA1UEAwwb7ZWc6rWt7KCV67O067O07Zi47KeE7Z2l +7JuQMA8GA1UdEwEB/wQFMAMBAf8wDAYDVR0kBAUwA4ABADANBgkqhkiG9w0BAQUF +AAOCAQEAz9b3Dv2wjG4FFY6oXCuyWtEeV6ZeGKqCEQj8mbdbp+PI0qLT+SQ09+Pk +rolUR9NpScmAwRHr4inH9gaLX7riXs+rw87P7pIl3J85Hg4D9N6QW6FwmVzHc07J +pHVJeyWhn4KSjU3sYcUMMqfHODiAVToqgx2cZHm5Dac1Smjvj/8F2LpOVmHY+Epw +mAiWk9hgxzrsX58dKzVPSBShmrtv7tIDhlPxEMcHVGJeNo7iHCsdF03m9VrvirqC +6HfZKBF+N4dKlArJQOk1pTr7ZD7yXxZ683bXzu4/RB1Fql8RqlMcOh9SUWJUD6OQ +Nc9Nb7rHviwJ8TX4Absk3TC8SA/u2Q== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G +A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp +Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4 +MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG +A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8 +RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT +gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm +KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd +QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ +XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw +DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o +LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU +RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp +jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK +6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX +mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs +Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH +WD9f +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkG +A1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3 +d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVu +dHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEzMDEGA1UEAxMq +RW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRUMxMB4XDTEy +MTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYwFAYD +VQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0 +L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0g +Zm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBD +ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEVDMTB2MBAGByqGSM49AgEGBSuBBAAi +A2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHyAsWfoPZb1YsGGYZPUxBt +ByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef9eNi1KlH +Bz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O +BBYEFLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVC +R98crlOZF7ZvHH3hvxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nX +hTcGtXsI/esni0qU+eH6p44mCOh8kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIHTzCCBTegAwIBAgIJAKPaQn6ksa7aMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYD +VQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0 +IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3 +MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xKTAnBgNVBAMTIENoYW1iZXJz +IG9mIENvbW1lcmNlIFJvb3QgLSAyMDA4MB4XDTA4MDgwMTEyMjk1MFoXDTM4MDcz +MTEyMjk1MFowga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBj +dXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIw +EAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEp +MCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwggIiMA0G +CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCvAMtwNyuAWko6bHiUfaN/Gh/2NdW9 +28sNRHI+JrKQUrpjOyhYb6WzbZSm891kDFX29ufyIiKAXuFixrYp4YFs8r/lfTJq +VKAyGVn+H4vXPWCGhSRv4xGzdz4gljUha7MI2XAuZPeEklPWDrCQiorjh40G072Q +DuKZoRuGDtqaCrsLYVAGUvGef3bsyw/QHg3PmTA9HMRFEFis1tPo1+XqxQEHd9ZR +5gN/ikilTWh1uem8nk4ZcfUyS5xtYBkL+8ydddy/Js2Pk3g5eXNeJQ7KXOt3EgfL +ZEFHcpOrUMPrCXZkNNI5t3YRCQ12RcSprj1qr7V9ZS+UWBDsXHyvfuK2GNnQm05a +Sd+pZgvMPMZ4fKecHePOjlO+Bd5gD2vlGts/4+EhySnB8esHnFIbAURRPHsl18Tl +UlRdJQfKFiC4reRB7noI/plvg6aRArBsNlVq5331lubKgdaX8ZSD6e2wsWsSaR6s ++12pxZjptFtYer49okQ6Y1nUCyXeG0+95QGezdIp1Z8XGQpvvwyQ0wlf2eOKNcx5 +Wk0ZN5K3xMGtr/R5JJqyAQuxr1yW84Ay+1w9mPGgP0revq+ULtlVmhduYJ1jbLhj +ya6BXBg14JC7vjxPNyK5fuvPnnchpj04gftI2jE9K+OJ9dC1vX7gUMQSibMjmhAx +hduub+84Mxh2EQIDAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBDDAdBgNV +HQ4EFgQU+SSsD7K1+HnA+mCIG8TZTQKeFxkwgeMGA1UdIwSB2zCB2IAU+SSsD7K1 ++HnA+mCIG8TZTQKeFxmhgbSkgbEwga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpN +YWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29t +L2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVy +ZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAt +IDIwMDiCCQCj2kJ+pLGu2jAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRV +HSAAMCowKAYIKwYBBQUHAgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20w +DQYJKoZIhvcNAQEFBQADggIBAJASryI1wqM58C7e6bXpeHxIvj99RZJe6dqxGfwW +PJ+0W2aeaufDuV2I6A+tzyMP3iU6XsxPpcG1Lawk0lgH3qLPaYRgM+gQDROpI9CF +5Y57pp49chNyM/WqfcZjHwj0/gF/JM8rLFQJ3uIrbZLGOU8W6jx+ekbURWpGqOt1 +glanq6B8aBMz9p0w8G8nOSQjKpD9kCk18pPfNKXG9/jvjA9iSnyu0/VU+I22mlaH +FoI6M6taIgj3grrqLuBHmrS1RaMFO9ncLkVAO+rcf+g769HsJtg1pDDFOqxXnrN2 +pSB7+R5KBWIBpih1YJeSDW4+TTdDDZIVnBgizVGZoCkaPF+KMjNbMMeJL0eYD6MD +xvbxrN8y8NmBGuScvfaAFPDRLLmF9dijscilIeUcE5fuDr3fKanvNFNb0+RqE4QG +tjICxFKuItLcsiFCGtpA8CnJ7AoMXOLQusxI0zcKzBIKinmwPQN/aUv0NCB9szTq +jktk9T79syNnFQ0EuPAtwQlRPLJsFfClI9eDdOTlLsn+mCdCxqvGnrDQWzilm1De +fhiYtUU79nm06PcaewaD+9CL2rvHvRirCG88gGtAPxkZumWK5r7VXNM21+9AUiRg +OGcEMeyP84LG3rlV8zsxkVrctQgVrXYlCg17LofiDKYGvCYQbTed7N14jHyAxfDZ +d0jQ +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV +BAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2ln +biBHb2xkIENBIC0gRzIwHhcNMDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBF +MQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMR8wHQYDVQQDExZT +d2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC +CgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUqt2/8 +76LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+ +bbqBHH5CjCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c +6bM8K8vzARO/Ws/BtQpgvd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqE +emA8atufK+ze3gE/bk3lUIbLtK/tREDFylqM2tIrfKjuvqblCqoOpd8FUrdVxyJd +MmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvRAiTysybUa9oEVeXBCsdt +MDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuendjIj3o02y +MszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69y +FGkOpeUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPi +aG59je883WX0XaxR7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxM +gI93e2CaHt+28kgeDrpOVG2Y4OGiGqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCB +qTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUWyV7 +lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64OfPAeGZe6Drn +8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov +L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe6 +45R88a7A3hfm5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczO +UYrHUDFu4Up+GC9pWbY9ZIEr44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5 +O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOfMke6UiI0HTJ6CVanfCU2qT1L2sCC +bwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6mGu6uLftIdxf+u+yv +GPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxpmo/a +77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCC +hdiDyyJkvC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid3 +92qgQmwLOM7XdVAyksLfKzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEpp +Ld6leNcG2mqeSz53OiATIgHQv2ieY2BrNU0LbbqhPcCT4H8js1WtciVORvnSFu+w +ZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6LqjviOvrv1vA+ACOzB2+htt +Qc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNV +BAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4X +DTA3MDYyOTE1MTMwNVoXDTI3MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQ +BgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwIQ2VydGlnbmEwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7qXOEm7RFHYeGifBZ4 +QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyHGxny +gQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbw +zBfsV1/pogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q +130yGLMLLGq/jj8UEYkgDncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2 +JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKfIrjxwo1p3Po6WAbfAgMBAAGjgbwwgbkw +DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQtCRZvgHyUtVF9lo53BEw +ZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJBgNVBAYT +AkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzj +AQ/JSP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG +9w0BAQUFAAOCAQEAhQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8h +bV6lUmPOEvjvKtpv6zf+EwLHyzs+ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFnc +fca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1kluPBS1xp81HlDQwY9qcEQCYsuu +HWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY1gkIl2PlwS6w +t0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw +WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDUzCCAjugAwIBAgIBAjANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEd +MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3Mg +Q2xhc3MgMyBDQSAxMB4XDTA1MDUwOTE0MTMwM1oXDTE1MDUwOTE0MTMwM1owSzEL +MAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MR0wGwYD +VQQDDBRCdXlwYXNzIENsYXNzIDMgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAKSO13TZKWTeXx+HgJHqTjnmGcZEC4DVC69TB4sSveZn8AKxifZg +isRbsELRwCGoy+Gb72RRtqfPFfV0gGgEkKBYouZ0plNTVUhjP5JW3SROjvi6K//z +NIqeKNc0n6wv1g/xpC+9UrJJhW05NfBEMJNGJPO251P7vGGvqaMU+8IXF4Rs4HyI ++MkcVyzwPX6UvCWThOiaAJpFBUJXgPROztmuOfbIUxAMZTpHe2DC1vqRycZxbL2R +hzyRhkmr8w+gbCZ2Xhysm3HljbybIR6c1jh+JIAVMYKWsUnTYjdbiAwKYjT+p0h+ +mbEwi5A3lRyoH6UsjfRVyNvdWQrCrXig9IsCAwEAAaNCMEAwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUOBTmyPCppAP0Tj4io1vy1uCtQHQwDgYDVR0PAQH/BAQD +AgEGMA0GCSqGSIb3DQEBBQUAA4IBAQABZ6OMySU9E2NdFm/soT4JXJEVKirZgCFP +Bdy7pYmrEzMqnji3jG8CcmPHc3ceCQa6Oyh7pEfJYWsICCD8igWKH7y6xsL+z27s +EzNxZy5p+qksP2bAEllNC1QCkoS72xLvg3BweMhT+t/Gxv/ciC8HwEmdMldg0/L2 +mSlf56oBzKwzqBwKu5HEA6BvtjT5htOzdlSY9EqBs1OdTUDs5XcTRa9bqh/YL0yC +e/4qxFi7T/ye/QNlGioOw6UgFpRreaaiErS7GqQjel/wroQk5PMr+4okoyeYZdow +dXb8GZHo2+ubPzK/QJcHJrrM85SFSnonk8+QQtS4Wxam58tAA915 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDqzCCApOgAwIBAgIRAMcoRwmzuGxFjB36JPU2TukwDQYJKoZIhvcNAQEFBQAw +PDEbMBkGA1UEAxMSQ29tU2lnbiBTZWN1cmVkIENBMRAwDgYDVQQKEwdDb21TaWdu +MQswCQYDVQQGEwJJTDAeFw0wNDAzMjQxMTM3MjBaFw0yOTAzMTYxNTA0NTZaMDwx +GzAZBgNVBAMTEkNvbVNpZ24gU2VjdXJlZCBDQTEQMA4GA1UEChMHQ29tU2lnbjEL +MAkGA1UEBhMCSUwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGtWhf +HZQVw6QIVS3joFd67+l0Kru5fFdJGhFeTymHDEjWaueP1H5XJLkGieQcPOqs49oh +gHMhCu95mGwfCP+hUH3ymBvJVG8+pSjsIQQPRbsHPaHA+iqYHU4Gk/v1iDurX8sW +v+bznkqH7Rnqwp9D5PGBpX8QTz7RSmKtUxvLg/8HZaWSLWapW7ha9B20IZFKF3ue +Mv5WJDmyVIRD9YTC2LxBkMyd1mja6YJQqTtoz7VdApRgFrFD2UNd3V2Hbuq7s8lr +9gOUCXDeFhF6K+h2j0kQmHe5Y1yLM5d19guMsqtb3nQgJT/j8xH5h2iGNXHDHYwt +6+UarA9z1YJZQIDTAgMBAAGjgacwgaQwDAYDVR0TBAUwAwEB/zBEBgNVHR8EPTA7 +MDmgN6A1hjNodHRwOi8vZmVkaXIuY29tc2lnbi5jby5pbC9jcmwvQ29tU2lnblNl +Y3VyZWRDQS5jcmwwDgYDVR0PAQH/BAQDAgGGMB8GA1UdIwQYMBaAFMFL7XC29z58 +ADsAj8c+DkWfHl3sMB0GA1UdDgQWBBTBS+1wtvc+fAA7AI/HPg5Fnx5d7DANBgkq +hkiG9w0BAQUFAAOCAQEAFs/ukhNQq3sUnjO2QiBq1BW9Cav8cujvR3qQrFHBZE7p +iL1DRYHjZiM/EoZNGeQFsOY3wo3aBijJD4mkU6l1P7CW+6tMM1X5eCZGbxs2mPtC +dsGCuY7e+0X5YxtiOzkGynd6qDwJz2w2PQ8KRUtpFhpFfTMDZflScZAmlaxMDPWL +kz/MdXSFmLr/YnpNH4n+rr2UAJm/EaXc4HnFFgt9AmEd6oX5AhVP51qJThRv4zdL +hfXBPGHg/QVBspJ/wx2g0K5SZGBrGMYmnNj1ZOQ2GmKfig8+/21OGVZOIJFsnzQz +OjRXUDpvgV4GxvU+fE6OK85lBi5d0ipTdF7Tbieejw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCB +mDELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsT +MChjKSAyMDA4IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s +eTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv +cml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIzNTk1OVowgZgxCzAJ +BgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg +MjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0 +BgNVBAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg +LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz ++uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5jK/BGvESyiaHAKAxJcCGVn2TAppMSAmUm +hsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdEc5IiaacDiGydY8hS2pgn +5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3CIShwiP/W +JmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exAL +DmKudlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZC +huOl1UcCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw +HQYDVR0OBBYEFMR5yo6hTgMdHNxr2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IB +AQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9cr5HqQ6XErhK8WTTOd8lNNTB +zU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbEAp7aDHdlDkQN +kv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD +AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUH +SJsMC8tJP33st/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2G +spki4cErx5z481+oghLrGREt +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBe +MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0 +ZC4xKjAoBgNVBAsMIWVQS0kgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe +Fw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMxMjdaMF4xCzAJBgNVBAYTAlRXMSMw +IQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEqMCgGA1UECwwhZVBL +SSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEF +AAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAH +SyZbCUNsIZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAh +ijHyl3SJCRImHJ7K2RKilTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3X +DZoTM1PRYfl61dd4s5oz9wCGzh1NlDivqOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1 +TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX12ruOzjjK9SXDrkb5wdJ +fzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0OWQqraffA +sgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uU +WH1+ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLS +nT0IFaUQAS2zMnaolQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pH +dmX2Os+PYhcZewoozRrSgx4hxyy/vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJip +NiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXiZo1jDiVN1Rmy5nk3pyKdVDEC +AwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/QkqiMAwGA1UdEwQF +MAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH +ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGB +uvl2ICO1J2B01GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6Yl +PwZpVnPDimZI+ymBV3QGypzqKOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkP +JXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdVxrsStZf0X4OFunHB2WyBEXYKCrC/ +gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEPNXubrjlpC2JgQCA2 +j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+rGNm6 +5ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUB +o2M3IUxExJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS +/jQ6fbjpKdx2qcgw+BRxgMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2z +Gp1iro2C6pSe3VkQw63d4k3jMdXH7OjysP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTE +W9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmODBCEIZ43ygknQW/2xzQ+D +hNQ+IIX3Sj0rnP0qCglN6oH4EZw= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEXzCCA0egAwIBAgIBATANBgkqhkiG9w0BAQUFADCB0DELMAkGA1UEBhMCRVMx +SDBGBgNVBAoTP0laRU5QRSBTLkEuIC0gQ0lGIEEtMDEzMzcyNjAtUk1lcmMuVml0 +b3JpYS1HYXN0ZWl6IFQxMDU1IEY2MiBTODFCMEAGA1UEBxM5QXZkYSBkZWwgTWVk +aXRlcnJhbmVvIEV0b3JiaWRlYSAzIC0gMDEwMTAgVml0b3JpYS1HYXN0ZWl6MRMw +EQYDVQQDEwpJemVucGUuY29tMR4wHAYJKoZIhvcNAQkBFg9JbmZvQGl6ZW5wZS5j +b20wHhcNMDMwMTMwMjMwMDAwWhcNMTgwMTMwMjMwMDAwWjCB0DELMAkGA1UEBhMC +RVMxSDBGBgNVBAoTP0laRU5QRSBTLkEuIC0gQ0lGIEEtMDEzMzcyNjAtUk1lcmMu +Vml0b3JpYS1HYXN0ZWl6IFQxMDU1IEY2MiBTODFCMEAGA1UEBxM5QXZkYSBkZWwg +TWVkaXRlcnJhbmVvIEV0b3JiaWRlYSAzIC0gMDEwMTAgVml0b3JpYS1HYXN0ZWl6 +MRMwEQYDVQQDEwpJemVucGUuY29tMR4wHAYJKoZIhvcNAQkBFg9JbmZvQGl6ZW5w +ZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC1btoCXXhp3xIW +D+Bxl8nUCxkyiazWfpt0e68t+Qt9+lZjKZSdEw2Omj4qvr+ovRmDXO3iWpWVOWDl +3JHJjAzFCe8ZEBNDH+QNYwZHmPBaMYFOYFdbAFVHWvys152C308hcFJ6xWWGmjvl +2eMiEl9P2nR2LWue368DCu+ak7j3gjAXaCOdP1a7Bfr+RW3X2SC5R4Xyp8iHlL5J +PHJD/WBkLrezwzQPdACw8m9EG7q9kUwlNpL32mROujS3ZkT6mQTzJieLiE3X04s0 +uIUqVkk5MhjcHFf7al0N5CzjtTcnXYJKN2Z9EDVskk4olAdGi46eSoZXbjUOP5gk +Ej6wVZAXAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG +MB0GA1UdDgQWBBTqVk/sPIOhFIh4gbIrBSLAB0FbQjANBgkqhkiG9w0BAQUFAAOC +AQEAYp7mEzzhw6o5Hf5+T5kcI+t4BJyiIWy7vHlLs/G8dLYXO81aN/Mzg928eMTR +TxxYZL8dd9uwsJ50TVfX6L0R4Dyw6wikh3fHRrat9ufXi63j5K91Ysr7aXqnF38d +iAgHYkrwC3kuxHBb9C0KBz6h8Q45/KCyN7d37wWAq38yyhPDlaOvyoE6bdUuK5hT +m5EYA5JmPyrhQ1moDOyueWBAjxzMEMj+OAY1H90cLv6wszsqerxRrdTOHBdv7MjB +EIpvEEQkXUxVXAzFuuT6m2t91Lfnwfl/IvljHaVC7DlyyhRYHD6D4Rx+4QKp4tWL +vpw6LkI+gKNJ/YdMCsRZQzEEFA== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBi +MQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu +MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3Jp +dHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMxMjM1OTU5WjBiMQswCQYDVQQGEwJV +UzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydO +ZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwz +c7MEL7xxjOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPP +OCwGJgl6cvf6UDL4wpPTaaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rl +mGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXTcrA/vGp97Eh/jcOrqnErU2lBUzS1sLnF +BgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc/Qzpf14Dl847ABSHJ3A4 +qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMBAAGjgZcw +gZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIB +BjAPBgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwu +bmV0c29sc3NsLmNvbS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3Jp +dHkuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc8 +6fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q4LqILPxFzBiwmZVRDuwduIj/ +h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/GGUsyfJj4akH +/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv +wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHN +pGxlaKFJdlxDydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCB +vTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL +ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJp +U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MTgwNgYDVQQDEy9W +ZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe +Fw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJVUzEX +MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0 +IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9y +IGF1dGhvcml6ZWQgdXNlIG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNh +bCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj1mCOkdeQmIN65lgZOIzF +9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGPMiJhgsWH +H26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+H +LL729fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN +/BMReYTtXlT2NJ8IAfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPT +rJ9VAMf2CGqUuV/c4DPxhGD5WycRtPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1Ud +EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0GCCsGAQUFBwEMBGEwX6FdoFsw +WTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2Oa8PPgGrUSBgs +exkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud +DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4 +sAPmLGd75JR3Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+ +seQxIcaBlVZaDrHC1LGmWazxY8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz +4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTxP/jgdFcrGJ2BtMQo2pSXpXDrrB2+ +BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+PwGZsY6rp2aQW9IHR +lRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4mJO3 +7M2CYfE45k+XmCpajQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIECTCCAvGgAwIBAgIQDV6ZCtadt3js2AdWO4YV2TANBgkqhkiG9w0BAQUFADBb +MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3Qx +ETAPBgNVBAsTCERTVCBBQ0VTMRcwFQYDVQQDEw5EU1QgQUNFUyBDQSBYNjAeFw0w +MzExMjAyMTE5NThaFw0xNzExMjAyMTE5NThaMFsxCzAJBgNVBAYTAlVTMSAwHgYD +VQQKExdEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdDERMA8GA1UECxMIRFNUIEFDRVMx +FzAVBgNVBAMTDkRTVCBBQ0VTIENBIFg2MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAuT31LMmU3HWKlV1j6IR3dma5WZFcRt2SPp/5DgO0PWGSvSMmtWPu +ktKe1jzIDZBfZIGxqAgNTNj50wUoUrQBJcWVHAx+PhCEdc/BGZFjz+iokYi5Q1K7 +gLFViYsx+tC3dr5BPTCapCIlF3PoHuLTrCq9Wzgh1SpL11V94zpVvddtawJXa+ZH +fAjIgrrep4c9oW24MFbCswKBXy314powGCi4ZtPLAZZv6opFVdbgnf9nKxcCpk4a +ahELfrd755jWjHZvwTvbUJN+5dCOHze4vbrGn2zpfDPyMjwmR/onJALJfh1biEIT +ajV8fTXpLmaRcpPVMibEdPVTo7NdmvYJywIDAQABo4HIMIHFMA8GA1UdEwEB/wQF +MAMBAf8wDgYDVR0PAQH/BAQDAgHGMB8GA1UdEQQYMBaBFHBraS1vcHNAdHJ1c3Rk +c3QuY29tMGIGA1UdIARbMFkwVwYKYIZIAWUDAgEBATBJMEcGCCsGAQUFBwIBFjto +dHRwOi8vd3d3LnRydXN0ZHN0LmNvbS9jZXJ0aWZpY2F0ZXMvcG9saWN5L0FDRVMt +aW5kZXguaHRtbDAdBgNVHQ4EFgQUCXIGThhDD+XWzMNqizF7eI+og7gwDQYJKoZI +hvcNAQEFBQADggEBAKPYjtay284F5zLNAdMEA+V25FYrnJmQ6AgwbN99Pe7lv7Uk +QIRJ4dEorsTCOlMwiPH1d25Ryvr/ma8kXxug/fKshMrfqfBfBC6tFr8hlxCBPeP/ +h40y3JTlR4peahPJlJU90u7INJXQgNStMgiAVDzgvVJT11J8smk/f3rPanTK+gQq +nExaBqXpIK1FZg9p8d2/6eMyi/rgwYZNcjwu2JN4Cir42NInPRmJX1p7ijvMDNpR +rscL9yuwNwXsvFcj4jjSm2jzVhKIT0J8uDHEtdvkyCE06UgRNe76x5JXxZ805Mf2 +9w4LTJxoeHtxMcfrHuBnQfO3oKfN5XozNmr6mis= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBl +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv +b3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl +cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSA +n61UQbVH35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4Htecc +biJVMWWXvdMX0h5i89vqbFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9Hp +EgjAALAcKxHad3A2m67OeYfcgnDmCXRwVWmvo2ifv922ebPynXApVfSr/5Vh88lA +bx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OPYLfykqGxvYmJHzDNw6Yu +YjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+RnlTGNAgMB +AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQW +BBTOw0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPI +QW5pJ6d1Ee88hjZv0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I +0jJmwYrA8y8678Dj1JGG0VDjA9tzd29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4Gni +lmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAWhsI6yLETcDbYz+70CjTVW0z9 +B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0MjomZmWzwPDCv +ON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo +IhNzbM8m9Yop5w== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzES +MBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFU +V0NBIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMz +WhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJVEFJV0FO +LUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlm +aWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +AQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFE +AcK0HMMxQhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HH +K3XLfJ+utdGdIzdjp9xCoi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeX +RfwZVzsrb+RH9JlF/h3x+JejiB03HFyP4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/z +rX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1ry+UPizgN7gr8/g+YnzAx +3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkq +hkiG9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeC +MErJk/9q56YAf4lCmtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdls +XebQ79NqZp4VKIV66IIArB6nCWlWQtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62D +lhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVYT0bf+215WfKEIlKuD8z7fDvn +aspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocnyYh0igzyXxfkZ +YiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIE5zCCA8+gAwIBAgIBADANBgkqhkiG9w0BAQUFADCBjTELMAkGA1UEBhMCQ0Ex +EDAOBgNVBAgTB09udGFyaW8xEDAOBgNVBAcTB1Rvcm9udG8xHTAbBgNVBAoTFEVj +aG93b3J4IENvcnBvcmF0aW9uMR8wHQYDVQQLExZDZXJ0aWZpY2F0aW9uIFNlcnZp +Y2VzMRowGAYDVQQDExFFY2hvd29yeCBSb290IENBMjAeFw0wNTEwMDYxMDQ5MTNa +Fw0zMDEwMDcxMDQ5MTNaMIGNMQswCQYDVQQGEwJDQTEQMA4GA1UECBMHT250YXJp +bzEQMA4GA1UEBxMHVG9yb250bzEdMBsGA1UEChMURWNob3dvcnggQ29ycG9yYXRp +b24xHzAdBgNVBAsTFkNlcnRpZmljYXRpb24gU2VydmljZXMxGjAYBgNVBAMTEUVj +aG93b3J4IFJvb3QgQ0EyMIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKCAQEA +utU/5BkV15UBf+s+JQruKQxr77s3rjp/RpOtmhHILIiO5gsEWP8MMrfrVEiidjI6 +Qh6ans0KAWc2Dw0/j4qKAQzOSyAZgjcdypNTBZ7muv212DA2Pu41rXqwMrlBrVi/ +KTghfdLlNRu6JrC5y8HarrnRFSKF1Thbzz921kLDRoCi+FVs5eVuK5LvIfkhNAqA +byrTgO3T9zfZgk8upmEkANPDL1+8y7dGPB/d6lk0I5mv8PESKX02TlvwgRSIiTHR +k8++iOPLBWlGp7ZfqTEXkPUZhgrQQvxcrwCUo6mk8TqgxCDP5FgPoHFiPLef5szP +ZLBJDWp7GLyE1PmkQI6WiwIBA6OCAVAwggFMMA8GA1UdEwEB/wQFMAMBAf8wCwYD +VR0PBAQDAgEGMB0GA1UdDgQWBBQ74YEboKs/OyGC1eISrq5QqxSlEzCBugYDVR0j +BIGyMIGvgBQ74YEboKs/OyGC1eISrq5QqxSlE6GBk6SBkDCBjTELMAkGA1UEBhMC +Q0ExEDAOBgNVBAgTB09udGFyaW8xEDAOBgNVBAcTB1Rvcm9udG8xHTAbBgNVBAoT +FEVjaG93b3J4IENvcnBvcmF0aW9uMR8wHQYDVQQLExZDZXJ0aWZpY2F0aW9uIFNl +cnZpY2VzMRowGAYDVQQDExFFY2hvd29yeCBSb290IENBMoIBADBQBgNVHSAESTBH +MEUGCysGAQQB+REKAQMBMDYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cuZWNob3dv +cnguY29tL2NhL3Jvb3QyL2Nwcy5wZGYwDQYJKoZIhvcNAQEFBQADggEBAG+nrPi/ +0RpfEzrj02C6JGPUar4nbjIhcY6N7DWNeqBoUulBSIH/PYGNHYx7/lnJefiixPGE +7TQ5xPgElxb9bK8zoAApO7U33OubqZ7M7DlHnFeCoOoIAZnG1kuwKwD5CXKB2a74 +HzcqNnFW0IsBFCYqrVh/rQgJOzDA8POGbH0DeD0xjwBBooAolkKT+7ZItJF1Pb56 +QpDL9G+16F7GkmnKlAIYT3QTS3yFGYChnJcd+6txUPhKi9sSOOmAIaKHnkH9Scz+ +A2cSi4A3wUYXVatuVNHpRb2lygfH3SuCX9MU8Ure3zBlSU1LALtMqI4JmcQmQpIq +zIzvO2jHyu9PQqo= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEqjCCA5KgAwIBAgIOLmoAAQACH9dSISwRXDswDQYJKoZIhvcNAQEFBQAwdjEL +MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNV +BAsTGVRDIFRydXN0Q2VudGVyIENsYXNzIDIgQ0ExJTAjBgNVBAMTHFRDIFRydXN0 +Q2VudGVyIENsYXNzIDIgQ0EgSUkwHhcNMDYwMTEyMTQzODQzWhcNMjUxMjMxMjI1 +OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIgR21i +SDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQTElMCMGA1UEAxMc +VEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAKuAh5uO8MN8h9foJIIRszzdQ2Lu+MNF2ujhoF/RKrLqk2jf +tMjWQ+nEdVl//OEd+DFwIxuInie5e/060smp6RQvkL4DUsFJzfb95AhmC1eKokKg +uNV/aVyQMrKXDcpK3EY+AlWJU+MaWss2xgdW94zPEfRMuzBwBJWl9jmM/XOBCH2J +XjIeIqkiRUuwZi4wzJ9l/fzLganx4Duvo4bRierERXlQXa7pIXSSTYtZgo+U4+lK +8edJsBTj9WLL1XK9H7nSn6DNqPoByNkN39r8R52zyFTfSUrxIan+GE7uSNQZu+99 +5OKdy1u2bv/jzVrndIIFuoAlOMvkaZ6vQaoahPUCAwEAAaOCATQwggEwMA8GA1Ud +EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTjq1RMgKHbVkO3 +kUrL84J6E1wIqzCB7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRy +dXN0Y2VudGVyLmRlL2NybC92Mi90Y19jbGFzc18yX2NhX0lJLmNybIaBn2xkYXA6 +Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBUcnVzdENlbnRlciUyMENsYXNz +JTIwMiUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21iSCxPVT1yb290 +Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u +TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEAjNfffu4bgBCzg/XbEeprS6iS +GNn3Bzn1LL4GdXpoUxUc6krtXvwjshOg0wn/9vYua0Fxec3ibf2uWWuFHbhOIprt +ZjluS5TmVfwLG4t3wVMTZonZKNaL80VKY7f9ewthXbhtvsPcW3nS7Yblok2+XnR8 +au0WOB9/WIFaGusyiC2y8zl3gK9etmF1KdsjTYjKUCjLhdLTEKJZbtOTVAB6okaV +hgWcqRmY5TFyDADiZ9lA4CQze28suVyrZZ0srHbqNZn1l7kPJOzHdiEoZa5X6AeI +dUpWoNIFOqTmjZKILPPy4cHGYdtBxceb9w4aUUXCYWvcZCcXjFq32nQozZfkvQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCB +gjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEk +MCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRY +UmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQxMTAxMTcx +NDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3 +dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2Vy +dmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS6 +38eMpSe2OAtp87ZOqCwuIR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCP +KZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMxfoArtYzAQDsRhtDLooY2YKTVMIJt2W7Q +DxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FEzG+gSqmUsE3a56k0enI4 +qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqsAxcZZPRa +JSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNVi +PvryxS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0P +BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASs +jVy16bYbMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0 +eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQEwDQYJKoZIhvcNAQEFBQAD +ggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc/Kh4ZzXxHfAR +vbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt +qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLa +IR9NmXmd4c8nnxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSy +i6mx5O+aGtA9aZnuqCij4Tyz8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQ +O+7ETPTsJ3xCwnR8gooJybQDJbw= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDOzCCAiOgAwIBAgIRANAeRlAAACmMAAAAAgAAAAIwDQYJKoZIhvcNAQEFBQAw +PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD +Ew5EU1QgUm9vdCBDQSBYNDAeFw0wMDA5MTMwNjIyNTBaFw0yMDA5MTMwNjIyNTBa +MD8xJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjEXMBUGA1UE +AxMORFNUIFJvb3QgQ0EgWDQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +AQCthX3OFEYY8gSeIYur0O4ypOT68HnDrjLfIutL5PZHRwQGjzCPb9PFo/ihboJ8 +RvfGhBAqpQCo47zwYEhpWm1jB+L/OE/dBBiyn98krfU2NiBKSom2J58RBeAwHGEy +cO+lewyjVvbDDLUy4CheY059vfMjPAftCRXjqSZIolQb9FdPcAoa90mFwB7rKniE +J7vppdrUScSS0+eBrHSUPLdvwyn4RGp+lSwbWYcbg5EpSpE0GRJdchic0YDjvIoC +YHpe7Rkj93PYRTQyU4bhC88ck8tMqbvRYqMRqR+vobbkrj5LLCOQCHV5WEoxWh+0 +E2SpIFe7RkV++MmpIAc0h1tZAgMBAAGjMjAwMA8GA1UdEwEB/wQFMAMBAf8wHQYD +VR0OBBYEFPCD6nPIP1ubWzdf9UyPWvf0hki9MA0GCSqGSIb3DQEBBQUAA4IBAQCE +G85wl5eEWd7adH6XW/ikGN5salvpq/Fix6yVTzE6CrhlP5LBdkf6kx1bSPL18M45 +g0rw2zA/MWOhJ3+S6U+BE0zPGCuu8YQaZibR7snm3HiHUaZNMu5c8D0x0bcMxDjY +AVVcHCoNiL53Q4PLW27nbY6wwG0ffFKmgV3blxrYWfuUDgGpyPwHwkfVFvz9qjaV +mf12VJffL6W8omBPtgteb6UaT/k1oJ7YI0ldGf+ngpVbRhD+LC3cUtT6GO/BEPZu +8YTV/hbiDH5v3khVqMIeKT6o8IuXGG7F6a6vKwP1F1FwTXf4UC/ivhme7vdUH7B/ +Vv4AEbT8dNfEeFxrkDbh +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEb +MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow +GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDElMCMGA1UEAwwcVHJ1c3RlZCBDZXJ0 +aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEwMDAwMDBaFw0yODEyMzEyMzU5NTla +MH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO +BgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSUwIwYD +VQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNlcnZpY2VzMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEA33FvNlhTWvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWW +fnJSoBVC21ndZHoa0Lh73TkVvFVIxO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMt +TGo87IvDktJTdyR0nAducPy9C1t2ul/y/9c3S0pgePfw+spwtOpZqqPOSC+pw7IL +fhdyFgymBwwbOM/JYrc/oJOlh0Hyt3BAd9i+FHzjqMB6juljatEPmsbS9Is6FARW +1O24zG71++IsWL1/T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsSivnkBbA7 +kUlcsutT6vifR4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0G +A1UdDgQWBBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21v +ZG9jYS5jb20vVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMuY3JsMDqgOKA2hjRo +dHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMu +Y3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8NtwuleGFTQQuS9/ +HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdTmw7pSqBYaWcOrp32 +pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+Cl5EfKNsYEYwq5GWDVxIS +jBc/lDb+XbDABHcTuPQV1T84zJQ6VdCsmPW6AF/ghhmBeC8owH7TzEIK9a5QoNE+ +xqFx7D+gIIxmOom0jtTYsU0lR+4viMi14QVFwL4Ucd56/Y57fU0IlqUSc/Atyjcn +dBInTMu2l+nZrghtWjlA3QVHdWpaIbOjGM9O9y5Xt5hwXsjEeLBi +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBK +MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x +GTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkx +MjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3Qg +Q29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jxYDiJ +iQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa +/FHtaMbQbqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJ +jnIFHovdRIWCQtBJwB1g8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnI +HmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYVHDGA76oYa8J719rO+TMg1fW9ajMtgQT7 +sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi0XPnj3pDAgMBAAGjgZ0w +gZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCsw +KaAnoCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsG +AQQBgjcVAQQDAgEAMA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0L +URYD7xh8yOOvaliTFGCRsoTciE6+OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXO +H0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cnCDpOGR86p1hcF895P4vkp9Mm +I50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/53CYNv6ZHdAbY +iNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc +f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIID+TCCAuGgAwIBAgIQW1fXqEywr9nTb0ugMbTW4jANBgkqhkiG9w0BAQUFADB5 +MQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRl +cm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xKjAoBgNVBAMTIVZpc2EgSW5m +b3JtYXRpb24gRGVsaXZlcnkgUm9vdCBDQTAeFw0wNTA2MjcxNzQyNDJaFw0yNTA2 +MjkxNzQyNDJaMHkxCzAJBgNVBAYTAlVTMQ0wCwYDVQQKEwRWSVNBMS8wLQYDVQQL +EyZWaXNhIEludGVybmF0aW9uYWwgU2VydmljZSBBc3NvY2lhdGlvbjEqMCgGA1UE +AxMhVmlzYSBJbmZvcm1hdGlvbiBEZWxpdmVyeSBSb290IENBMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyREA4R/QkkfpLx0cYjga/EhIPZpchH0MZsRZ +FfP6C2ITtf/Wc+MtgD4yTK0yoiXvni3d+aCtEgK3GDvkdgYrgF76ROJFZwUQjQ9l +x42gRT05DbXvWFoy7dTglCZ9z/Tt2Cnktv9oxKgmkeHY/CyfpCBg1S8xth2JlGMR +0ug/GMO5zANuegZOv438p5Lt5So+du2Gl+RMFQqEPwqN5uJSqAe0VtmB4gWdQ8on +Bj2ZAM2R73QW7UW0Igt2vA4JaSiNtaAG/Y/58VXWHGgbq7rDtNK1R30X0kJV0rGA +ib3RSwB3LpG7bOjbIucV5mQgJoVjoA1e05w6g1x/KmNTmOGRVwIDAQABo30wezAP +BgNVHRMBAf8EBTADAQH/MDkGA1UdIAQyMDAwLgYFZ4EDAgEwJTAVBggrBgEFBQcC +ARYJMS4yLjMuNC41MAwGCCsGAQUFBwICMAAwDgYDVR0PAQH/BAQDAgEGMB0GA1Ud +DgQWBBRPitp2/2d3I5qmgH1924h1hfeBejANBgkqhkiG9w0BAQUFAAOCAQEACUW1 +QdUHdDJydgDPmYt+telnG/Su+DPaf1cregzlN43bJaJosMP7NwjoJY/H2He4XLWb +5rXEkl+xH1UyUwF7mtaUoxbGxEvt8hPZSTB4da2mzXgwKvXuHyzF5Qjy1hOB0/pS +WaF9ARpVKJJ7TOJQdGKBsF2Ty4fSCLqZLgfxbqwMsd9sysXI3rDXjIhekqvbgeLz +PqZr+pfgFhwCCLSMQWl5Ll3u7Qk9wR094DZ6jj6+JCVCRUS3HyabH4OlM0Vc2K+j +INsF/64Or7GNtRf9HYEJvrPxHINxl3JVwhYj4ASeaO4KwhVbwtw94Tc/XrGcexDo +c5lC3rAi4/UZqweYCw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT +HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs +ZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5 +MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYD +VQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFy +ZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2Vy +dmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20p +OsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm2 +8xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1K +Ts9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufe +hRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk +6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAw +DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+q +AdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMI +bw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXB +ve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1z +qwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd +iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn +0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN +sSi6 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl +MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp +U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw +NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE +ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp +ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3 +DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf +8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN ++lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0 +X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa +K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA +1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G +A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR +zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0 +YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD +bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w +DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3 +L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D +eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl +xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp +VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY +WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEqjCCA5KgAwIBAgIOSkcAAQAC5aBd1j8AUb8wDQYJKoZIhvcNAQEFBQAwdjEL +MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNV +BAsTGVRDIFRydXN0Q2VudGVyIENsYXNzIDMgQ0ExJTAjBgNVBAMTHFRDIFRydXN0 +Q2VudGVyIENsYXNzIDMgQ0EgSUkwHhcNMDYwMTEyMTQ0MTU3WhcNMjUxMjMxMjI1 +OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIgR21i +SDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQTElMCMGA1UEAxMc +VEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBALTgu1G7OVyLBMVMeRwjhjEQY0NVJz/GRcekPewJDRoeIMJW +Ht4bNwcwIi9v8Qbxq63WyKthoy9DxLCyLfzDlml7forkzMA5EpBCYMnMNWju2l+Q +Vl/NHE1bWEnrDgFPZPosPIlY2C8u4rBo6SI7dYnWRBpl8huXJh0obazovVkdKyT2 +1oQDZogkAHhg8fir/gKya/si+zXmFtGt9i4S5Po1auUZuV3bOx4a+9P/FRQI2Alq +ukWdFHlgfa9Aigdzs5OW03Q0jTo3Kd5c7PXuLjHCINy+8U9/I1LZW+Jk2ZyqBwi1 +Rb3R0DHBq1SfqdLDYmAD8bs5SpJKPQq5ncWg/jcCAwEAAaOCATQwggEwMA8GA1Ud +EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTUovyfs8PYA9NX +XAek0CSnwPIA1DCB7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRy +dXN0Y2VudGVyLmRlL2NybC92Mi90Y19jbGFzc18zX2NhX0lJLmNybIaBn2xkYXA6 +Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBUcnVzdENlbnRlciUyMENsYXNz +JTIwMyUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21iSCxPVT1yb290 +Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u +TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEANmDkcPcGIEPZIxpC8vijsrlN +irTzwppVMXzEO2eatN9NDoqTSheLG43KieHPOh6sHfGcMrSOWXaiQYUlN6AT0PV8 +TtXqluJucsG7Kv5sbviRmEb8yRtXW+rIGjs/sFGYPAfaLFkB2otE6OF0/ado3VS6 +g0bsyEa1+K+XwDsJHI/OcpY9M1ZwvJbL2NV9IJqDnxrcOfHFcqMRA/07QlIp2+gB +95tejNaNhk4Z+rwcvsUhpYeeeC422wlxo3I0+GzjBgnyXlal092Y+tTmBvTwtiBj +S+opvaqCZh77gaqnN60TGOaSw4HBM7uIHqHn4rS9MWwOUT1v+5ZWgOI2F9Hc5A== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBY +MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMo +R2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEx +MjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgxCzAJBgNVBAYTAlVTMRYwFAYDVQQK +Ew1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQcmltYXJ5IENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9 +AWbK7hWNb6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjA +ZIVcFU2Ix7e64HXprQU9nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE0 +7e9GceBrAqg1cmuXm2bgyxx5X9gaBGgeRwLmnWDiNpcB3841kt++Z8dtd1k7j53W +kBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGttm/81w7a4DSwDRp35+MI +mO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G +A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJ +KoZIhvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ1 +6CePbJC/kRYkRj5KTs4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl +4b7UVXGYNTq+k+qurUKykG/g/CFNNWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6K +oKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHaFloxt/m0cYASSJlyc1pZU8Fj +UjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG1riR/aYNKxoU +AT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UE +BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWdu +IFNpbHZlciBDQSAtIEcyMB4XDTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0Nlow +RzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMY +U3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A +MIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644N0Mv +Fz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7br +YT7QbNHm+/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieF +nbAVlDLaYQ1HTWBCrpJH6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH +6ATK72oxh9TAtvmUcXtnZLi2kUpCe2UuMGoM9ZDulebyzYLs2aFK7PayS+VFheZt +eJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5hqAaEuSh6XzjZG6k4sIN/ +c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5FZGkECwJ +MoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRH +HTBsROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTf +jNFusB3hB48IHpmccelM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb6 +5i/4z3GcRm25xBWNOHkDRUjvxF3XCO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOB +rDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU +F6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRBtjpbO8tFnb0c +wpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0 +cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIB +AHPGgeAn0i0P4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShp +WJHckRE1qTodvBqlYJ7YH39FkWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9 +xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L3XWgwF15kIwb4FDm3jH+mHtwX6WQ +2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx/uNncqCxv1yL5PqZ +IseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFaDGi8 +aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2X +em1ZqSqPe97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQR +dAtq/gsD/KNVV4n+SsuuWxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/ +OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJDIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+ +hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ubDgEj8Z+7fNzcbBGXJbLy +tGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEAzCCAuugAwIBAgIQVID5oHPtPwBMyonY43HmSjANBgkqhkiG9w0BAQUFADB1 +MQswCQYDVQQGEwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1 +czEoMCYGA1UEAwwfRUUgQ2VydGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYG +CSqGSIb3DQEJARYJcGtpQHNrLmVlMCIYDzIwMTAxMDMwMTAxMDMwWhgPMjAzMDEy +MTcyMzU5NTlaMHUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKDBlBUyBTZXJ0aWZpdHNl +ZXJpbWlza2Vza3VzMSgwJgYDVQQDDB9FRSBDZXJ0aWZpY2F0aW9uIENlbnRyZSBS +b290IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwggEiMA0GCSqGSIb3DQEB +AQUAA4IBDwAwggEKAoIBAQDIIMDs4MVLqwd4lfNE7vsLDP90jmG7sWLqI9iroWUy +euuOF0+W2Ap7kaJjbMeMTC55v6kF/GlclY1i+blw7cNRfdCT5mzrMEvhvH2/UpvO +bntl8jixwKIy72KyaOBhU8E2lf/slLo2rpwcpzIP5Xy0xm90/XsY6KxX7QYgSzIw +WFv9zajmofxwvI6Sc9uXp3whrj3B9UiHbCe9nyV0gVWw93X2PaRka9ZP585ArQ/d +MtO8ihJTmMmJ+xAdTX7Nfh9WDSFwhfYggx/2uh8Ej+p3iDXE/+pOoYtNP2MbRMNE +1CV2yreN1x5KZmTNXMWcg+HCCIia7E6j8T4cLNlsHaFLAgMBAAGjgYowgYcwDwYD +VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBLyWj7qVhy/ +zQas8fElyalL1BSZMEUGA1UdJQQ+MDwGCCsGAQUFBwMCBggrBgEFBQcDAQYIKwYB +BQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYIKwYBBQUHAwkwDQYJKoZIhvcNAQEF +BQADggEBAHv25MANqhlHt01Xo/6tu7Fq1Q+e2+RjxY6hUFaTlrg4wCQiZrxTFGGV +v9DHKpY5P30osxBAIWrEr7BSdxjhlthWXePdNl4dp1BUoMUq5KqMlIpPnTX/dqQG +E5Gion0ARD9V04I8GtVbvFZMIi5GQ4okQC3zErg7cBqklrkar4dBGmoYDQZPxz5u +uSlNDUmJEYcyW+ZLBMjkXOZ0c5RdFpgTlf7727FE5TpwrDdr5rMzcijJs1eg9gIW +iAYLtqZLICjU3j2LrTcFU3T+bsy8QxdxXvnFzBqpYe73dgzzcvRyrc9yAjYHR8/v +GVCJYMzpJJUPwssd8m92kMfMdcGWxZ0= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB +yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL +ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp +U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW +ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL +MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW +ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln +biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp +U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y +aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1 +nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex +t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz +SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG +BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+ +rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/ +NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E +BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH +BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy +aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv +MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE +p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y +5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK +WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ +4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N +hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDoDCCAoigAwIBAgIBMTANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJKUDEc +MBoGA1UEChMTSmFwYW5lc2UgR292ZXJubWVudDEWMBQGA1UECxMNQXBwbGljYXRp +b25DQTAeFw0wNzEyMTIxNTAwMDBaFw0xNzEyMTIxNTAwMDBaMEMxCzAJBgNVBAYT +AkpQMRwwGgYDVQQKExNKYXBhbmVzZSBHb3Zlcm5tZW50MRYwFAYDVQQLEw1BcHBs +aWNhdGlvbkNBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp23gdE6H +j6UG3mii24aZS2QNcfAKBZuOquHMLtJqO8F6tJdhjYq+xpqcBrSGUeQ3DnR4fl+K +f5Sk10cI/VBaVuRorChzoHvpfxiSQE8tnfWuREhzNgaeZCw7NCPbXCbkcXmP1G55 +IrmTwcrNwVbtiGrXoDkhBFcsovW8R0FPXjQilbUfKW1eSvNNcr5BViCH/OlQR9cw +FO5cjFW6WY2H/CPek9AEjP3vbb3QesmlOmpyM8ZKDQUXKi17safY1vC+9D/qDiht +QWEjdnjDuGWk81quzMKq2edY3rZ+nYVunyoKb58DKTCXKB28t89UKU5RMfkntigm +/qJj5kEW8DOYRwIDAQABo4GeMIGbMB0GA1UdDgQWBBRUWssmP3HMlEYNllPqa0jQ +k/5CdTAOBgNVHQ8BAf8EBAMCAQYwWQYDVR0RBFIwUKROMEwxCzAJBgNVBAYTAkpQ +MRgwFgYDVQQKDA/ml6XmnKzlm73mlL/lupwxIzAhBgNVBAsMGuOCouODl+ODquOC +seODvOOCt+ODp+ODs0NBMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD +ggEBADlqRHZ3ODrso2dGD/mLBqj7apAxzn7s2tGJfHrrLgy9mTLnsCTWw//1sogJ +hyzjVOGjprIIC8CFqMjSnHH2HZ9g/DgzE+Ge3Atf2hZQKXsvcJEPmbo0NI2VdMV+ +eKlmXb3KIXdCEKxmJj3ekav9FfBv7WxfEPjzFvYDio+nEhEMy/0/ecGc/WLuo89U +DNErXxc+4z6/wCs+CZv+iKZ+tJIX/COUgb1up8WMwusRRdv4QcmWdupwX3kSa+Sj +B1oF7ydJzyGfikwJcGapJsErEU4z0g781mzSDjJkaP+tBXhfAx2o45CsJOAPQKdL +rosot4LKGAfmt1t06SAZf7IbiVQ= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDIDCCAgigAwIBAgIBJDANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEP +MA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MxIENBMB4XDTAx +MDQwNjEwNDkxM1oXDTIxMDQwNjEwNDkxM1owOTELMAkGA1UEBhMCRkkxDzANBgNV +BAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMSBDQTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBALWJHytPZwp5/8Ue+H887dF+2rDNbS82rDTG +29lkFwhjMDMiikzujrsPDUJVyZ0upe/3p4zDq7mXy47vPxVnqIJyY1MPQYx9EJUk +oVqlBvqSV536pQHydekfvFYmUk54GWVYVQNYwBSujHxVX3BbdyMGNpfzJLWaRpXk +3w0LBUXl0fIdgrvGE+D+qnr9aTCU89JFhfzyMlsy3uhsXR/LpCJ0sICOXZT3BgBL +qdReLjVQCfOAl/QMF6452F/NM8EcyonCIvdFEu1eEpOdY6uCLrnrQkFEy0oaAIIN +nvmLVz5MxxftLItyM19yejhW1ebZrgUaHXVFsculJRwSVzb9IjcCAwEAAaMzMDEw +DwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQIR+IMi/ZTiFIwCwYDVR0PBAQDAgEG +MA0GCSqGSIb3DQEBBQUAA4IBAQCLGrLJXWG04bkruVPRsoWdd44W7hE928Jj2VuX +ZfsSZ9gqXLar5V7DtxYvyOirHYr9qxp81V9jz9yw3Xe5qObSIjiHBxTZ/75Wtf0H +DjxVyhbMp6Z3N/vbXB9OWQaHowND9Rart4S9Tu+fMTfwRvFAttEMpWT4Y14h21VO +TzF2nBBhjrZTOqMRvq9tfB69ri3iDGnHhVNoomG6xT60eVR4ngrHAr5i0RGCS2Uv +kVrCqIexVmiUefkl98HVrhq4uz2PqYo4Ffdz0Fpg0YCw8NzVUM1O7pJIae2yIx4w +zMiUyLb1O4Z/P6Yun/Y+LLWSlj7fLJOK/4GMDw9ZIRlXvVWa +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/ +MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT +DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow +PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD +Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O +rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq +OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b +xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw +7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD +aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV +HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG +SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69 +ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr +AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz +R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5 +JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo +Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFGTCCBAGgAwIBAgIEPki9xDANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQGEwJE +SzEMMAoGA1UEChMDVERDMRQwEgYDVQQDEwtUREMgT0NFUyBDQTAeFw0wMzAyMTEw +ODM5MzBaFw0zNzAyMTEwOTA5MzBaMDExCzAJBgNVBAYTAkRLMQwwCgYDVQQKEwNU +REMxFDASBgNVBAMTC1REQyBPQ0VTIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEArGL2YSCyz8DGhdfjeebM7fI5kqSXLmSjhFuHnEz9pPPEXyG9VhDr +2y5h7JNp46PMvZnDBfwGuMo2HP6QjklMxFaaL1a8z3sM8W9Hpg1DTeLpHTk0zY0s +2RKY+ePhwUp8hjjEqcRhiNJerxomTdXkoCJHhNlktxmW/OwZ5LKXJk5KTMuPJItU +GBxIYXvViGjaXbXqzRowwYCDdlCqT9HU3Tjw7xb04QxQBr/q+3pJoSgrHPb8FTKj +dGqPqcNiKXEx5TukYBdedObaE+3pHx8b0bJoc8YQNHVGEBDjkAB2QMuLt0MJIf+r +TpPGWOmlgtt3xDqZsXKVSQTwtyv6e1mO3QIDAQABo4ICNzCCAjMwDwYDVR0TAQH/ +BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwgewGA1UdIASB5DCB4TCB3gYIKoFQgSkB +AQEwgdEwLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuY2VydGlmaWthdC5kay9yZXBv +c2l0b3J5MIGdBggrBgEFBQcCAjCBkDAKFgNUREMwAwIBARqBgUNlcnRpZmlrYXRl +ciBmcmEgZGVubmUgQ0EgdWRzdGVkZXMgdW5kZXIgT0lEIDEuMi4yMDguMTY5LjEu +MS4xLiBDZXJ0aWZpY2F0ZXMgZnJvbSB0aGlzIENBIGFyZSBpc3N1ZWQgdW5kZXIg +T0lEIDEuMi4yMDguMTY5LjEuMS4xLjARBglghkgBhvhCAQEEBAMCAAcwgYEGA1Ud +HwR6MHgwSKBGoESkQjBAMQswCQYDVQQGEwJESzEMMAoGA1UEChMDVERDMRQwEgYD +VQQDEwtUREMgT0NFUyBDQTENMAsGA1UEAxMEQ1JMMTAsoCqgKIYmaHR0cDovL2Ny +bC5vY2VzLmNlcnRpZmlrYXQuZGsvb2Nlcy5jcmwwKwYDVR0QBCQwIoAPMjAwMzAy +MTEwODM5MzBagQ8yMDM3MDIxMTA5MDkzMFowHwYDVR0jBBgwFoAUYLWF7FZkfhIZ +J2cdUBVLc647+RIwHQYDVR0OBBYEFGC1hexWZH4SGSdnHVAVS3OuO/kSMB0GCSqG +SIb2fQdBAAQQMA4bCFY2LjA6NC4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEACrom +JkbTc6gJ82sLMJn9iuFXehHTuJTXCRBuo7E4A9G28kNBKWKnctj7fAXmMXAnVBhO +inxO5dHKjHiIzxvTkIvmI/gLDjNDfZziChmPyQE+dF10yYscA+UYyAFMP8uXBV2Y +caaYb7Z8vTd/vuGTJW1v8AqtFxjhA7wHKcitJuj4YfD9IQl+mo6paH1IYnK9AOoB +mbgGglGBTvH1tJFUuSN6AJqfXY3gPGS5GhKSKseCRHI53OI8xthV9RVOyAUO28bQ +YqbsFbS1AoLbrIyigfCbmTH1ICCoiGEKB5+U/NDXG8wuF/MEJ3Zn61SD/aSQfgY9 +BKNDLdr8C2LqL19iUw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDYTCCAkmgAwIBAgIQCgEBAQAAAnwAAAAKAAAAAjANBgkqhkiG9w0BAQUFADA6 +MRkwFwYDVQQKExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0EgU2VjdXJp +dHkgMjA0OCBWMzAeFw0wMTAyMjIyMDM5MjNaFw0yNjAyMjIyMDM5MjNaMDoxGTAX +BgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAbBgNVBAsTFFJTQSBTZWN1cml0eSAy +MDQ4IFYzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt49VcdKA3Xtp +eafwGFAyPGJn9gqVB93mG/Oe2dJBVGutn3y+Gc37RqtBaB4Y6lXIL5F4iSj7Jylg +/9+PjDvJSZu1pJTOAeo+tWN7fyb9Gd3AIb2E0S1PRsNO3Ng3OTsor8udGuorryGl +wSMiuLgbWhOHV4PR8CDn6E8jQrAApX2J6elhc5SYcSa8LWrg903w8bYqODGBDSnh +AMFRD0xS+ARaqn1y07iHKrtjEAMqs6FPDVpeRrc9DvV07Jmf+T0kgYim3WBU6JU2 +PcYJk5qjEoAAVZkZR73QpXzDuvsf9/UP+Ky5tfQ3mBMY3oVbtwyCO4dvlTlYMNpu +AWgXIszACwIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +BjAfBgNVHSMEGDAWgBQHw1EwpKrpRa41JPr/JCwz0LGdjDAdBgNVHQ4EFgQUB8NR +MKSq6UWuNST6/yQsM9CxnYwwDQYJKoZIhvcNAQEFBQADggEBAF8+hnZuuDU8TjYc +HnmYv/3VEhF5Ug7uMYm83X/50cYVIeiKAVQNOvtUudZj1LGqlk2iQk3UUx+LEN5/ +Zb5gEydxiKRz44Rj0aRV4VCT5hsOedBnvEbIvz8XDZXmxpBp3ue0L96VfdASPz0+ +f00/FGj1EVDVwfSQpQgdMWD/YIwjVAqv/qFuxdF6Kmh4zx6CCiC0H63lhbJqaHVO +rSU3lIW+vaHU6rcMSzyd6BIA8F+sDeGscGNz9395nzIlQnQFgCi/vcEkllgVsRch +6YlL2weIZ/QVrXA+L02FO8K32/6YaCOJ4XQP3vTFhGMpG8zLB8kApKnXwiJPZ9d3 +7CAFYd4= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UE +BhMCRVMxQjBABgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1h +cHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEy +MzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIwQAYDVQQDDDlBdXRvcmlkYWQgZGUg +Q2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBBNjI2MzQwNjgwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDDUtd9 +thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQM +cas9UX4PB99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefG +L9ItWY16Ck6WaVICqjaY7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15i +NA9wBj4gGFrO93IbJWyTdBSTo3OxDqqHECNZXyAFGUftaI6SEspd/NYrspI8IM/h +X68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyIplD9amML9ZMWGxmPsu2b +m8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctXMbScyJCy +Z/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirja +EbsXLZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/T +KI8xWVvTyQKmtFLKbpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF +6NkBiDkal4ZkQdU7hwxu+g/GvUgUvzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVh +OSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1UdEwEB/wQIMAYBAf8CAQEwDgYD +VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNHDhpkLzCBpgYD +VR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp +cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBv +ACAAZABlACAAbABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBl +AGwAbwBuAGEAIAAwADgAMAAxADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF +661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx51tkljYyGOylMnfX40S2wBEqgLk9 +am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qkR71kMrv2JYSiJ0L1 +ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaPT481 +PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS +3a/DTg4fJl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5k +SeTy36LssUzAKh3ntLFlosS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF +3dvd6qJ2gHN99ZwExEWN57kci57q13XRcrHedUTnQn3iV2t93Jm8PYMo6oCTjcVM +ZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoRsaS8I8nkvof/uZS2+F0g +StRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTDKCOM/icz +Q0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQB +jLMi6Et8Vcad+qMUu2WFbm5PEn4KPJ2V +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU +MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs +IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290 +MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux +FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h +bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v +dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt +H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9 +uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX +mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX +a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN +E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0 +WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD +VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0 +Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU +cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx +IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN +AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH +YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5 +6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC +Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX +c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a +mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJVUzEc +MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBT +ZWN1cmUgZUJ1c2luZXNzIENBLTEwHhcNOTkwNjIxMDQwMDAwWhcNMjAwNjIxMDQw +MDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5j +LjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNzIENBLTEwgZ8wDQYJ +KoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fek6lfWg0XTzQaDJj0ItlZ1MRo +RvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5/VGcqiTZ9J2DKocKIdMSODRsjQBu +WqDZQu4aIZX5UkxVWsUPOE9G+m34LjXWHXzr4vCwdYDIqROsvojvOm6rXyo4YgKw +Env+j6YDAgMBAAGjZjBkMBEGCWCGSAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTAD +AQH/MB8GA1UdIwQYMBaAFEp4MlIR21kWNl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRK +eDJSEdtZFjZe38EUNkBqR3xMoTANBgkqhkiG9w0BAQQFAAOBgQB1W6ibAxHm6VZM +zfmpTMANmvPMZWnmJXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5lSE/9dR+ +WB5Hh1Q+WKG1tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN +/Bf+KpYrtWKmpj29f5JZzVoqgrI3eQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBM +MSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5D +ZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBU +cnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIyMTIwNzM3WhcNMjkxMjMxMTIwNzM3 +WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMg +Uy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSIw +IAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rH +UV+rpDKmYYe2bg+G0jACl/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LM +TXPb865Px1bVWqeWifrzq2jUI4ZZJ88JJ7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVU +BBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4fOQtf/WsX+sWn7Et0brM +kUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0cvW0QM8x +AcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNV +HQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15y +sHhE49wcrwn9I0j6vSrEuVUEtRCjjSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfL +I9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1mS1FhIrlQgnXdAIv94nYmem8 +J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5ajZt3hrvJBW8qY +VoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI +03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT +EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp +ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz +NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH +EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE +AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD +E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH +/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy +DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh +GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR +tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA +AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE +FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX +WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu +9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr +gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo +2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO +LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI +4uJEvlz36hz1 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFkjCCA3qgAwIBAgIBATANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJGUjET +MBEGA1UEChMKQ2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxHTAb +BgNVBAMTFENlcnRpbm9taXMgLSBSb290IENBMB4XDTEzMTAyMTA5MTcxOFoXDTMz +MTAyMTA5MTcxOFowWjELMAkGA1UEBhMCRlIxEzARBgNVBAoTCkNlcnRpbm9taXMx +FzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMR0wGwYDVQQDExRDZXJ0aW5vbWlzIC0g +Um9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANTMCQosP5L2 +fxSeC5yaah1AMGT9qt8OHgZbn1CF6s2Nq0Nn3rD6foCWnoR4kkjW4znuzuRZWJfl +LieY6pOod5tK8O90gC3rMB+12ceAnGInkYjwSond3IjmFPnVAy//ldu9n+ws+hQV +WZUKxkd8aRi5pwP5ynapz8dvtF4F/u7BUrJ1Mofs7SlmO/NKFoL21prbcpjp3vDF +TKWrteoB4owuZH9kb/2jJZOLyKIOSY008B/sWEUuNKqEUL3nskoTuLAPrjhdsKkb +5nPJWqHZZkCqqU2mNAKthH6yI8H7KsZn9DS2sJVqM09xRLWtwHkziOC/7aOgFLSc +CbAK42C++PhmiM1b8XcF4LVzbsF9Ri6OSyemzTUK/eVNfaoqoynHWmgE6OXWk6Ri +wsXm9E/G+Z8ajYJJGYrKWUM66A0ywfRMEwNvbqY/kXPLynNvEiCL7sCCeN5LLsJJ +wx3tFvYk9CcbXFcx3FXuqB5vbKziRcxXV4p1VxngtViZSTYxPDMBbRZKzbgqg4SG +m/lg0h9tkQPTYKbVPZrdd5A9NaSfD171UkRpucC63M9933zZxKyGIjK8e2uR73r4 +F2iw4lNVYC2vPsKD2NkJK/DAZNuHi5HMkesE/Xa0lZrmFAYb1TQdvtj/dBxThZng +WVJKYe2InmtJiUZ+IFrZ50rlau7SZRFDAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIB +BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTvkUz1pcMw6C8I6tNxIqSSaHh0 +2TAfBgNVHSMEGDAWgBTvkUz1pcMw6C8I6tNxIqSSaHh02TANBgkqhkiG9w0BAQsF +AAOCAgEAfj1U2iJdGlg+O1QnurrMyOMaauo++RLrVl89UM7g6kgmJs95Vn6RHJk/ +0KGRHCwPT5iVWVO90CLYiF2cN/z7ZMF4jIuaYAnq1fohX9B0ZedQxb8uuQsLrbWw +F6YSjNRieOpWauwK0kDDPAUwPk2Ut59KA9N9J0u2/kTO+hkzGm2kQtHdzMjI1xZS +g081lLMSVX3l4kLr5JyTCcBMWwerx20RoFAXlCOotQqSD7J6wWAsOMwaplv/8gzj +qh8c3LigkyfeY+N/IZ865Z764BNqdeuWXGKRlI5nU7aJ+BIJy29SWwNyhlCVCNSN +h4YVH5Uk2KRvms6knZtt0rJ2BobGVgjF6wnaNsIbW0G+YSrjcOa4pvi2WsS9Iff/ +ql+hbHY5ZtbqTFXhADObE5hjyW/QASAJN1LnDE8+zbz1X5YnpyACleAu6AdBBR8V +btaw5BngDwKTACdyxYvRVB9dSsNAl35VpnzBMwQUAR1JIGkLGZOdblgi90AMRgwj +Y/M50n92Uaf0yKHxDHYiI0ZSKS3io0EHVmmY0gUJvGnHWmHNj4FgFU2A3ZDifcRQ +8ow7bkrHxuaAKzyBvBGAFhAn1/DNP3nMcyrDflOR1m749fPH0FFNjkulW+YZFzvW +gQncItzujrnEj1PhZ7szuIgVRs/taTX/dQ1G885x4cVrhkIGuUE= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFujCCBKKgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBhjELMAkGA1UEBhMCVVMx +HTAbBgNVBAoTFEFwcGxlIENvbXB1dGVyLCBJbmMuMS0wKwYDVQQLEyRBcHBsZSBD +b21wdXRlciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxKTAnBgNVBAMTIEFwcGxlIFJv +b3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTA1MDIxMDAwMTgxNFoXDTI1MDIx +MDAwMTgxNFowgYYxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRBcHBsZSBDb21wdXRl +ciwgSW5jLjEtMCsGA1UECxMkQXBwbGUgQ29tcHV0ZXIgQ2VydGlmaWNhdGUgQXV0 +aG9yaXR5MSkwJwYDVQQDEyBBcHBsZSBSb290IENlcnRpZmljYXRlIEF1dGhvcml0 +eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOSRqQkfkdseR1DrBe1e +eYQt6zaiV0xV7IsZid75S2z1B6siMALoGD74UAnTf0GomPnRymacJGsR0KO75Bsq +wx+VnnoMpEeLW9QWNzPLxA9NzhRp0ckZcvVdDtV/X5vyJQO6VY9NXQ3xZDUjFUsV +WR2zlPf2nJ7PULrBWFBnjwi0IPfLrCwgb3C2PwEwjLdDzw+dPfMrSSgayP7OtbkO +2V4c1ss9tTqt9A8OAJILsSEWLnTVPA3bYharo3GSR1NVwa8vQbP4++NwzeajTEV+ +H0xrUJZBicR0YgsQg0GHM4qBsTBY7FoEMoxos48d3mVz/2deZbxJ2HafMxRloXeU +yS0CAwEAAaOCAi8wggIrMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/ +MB0GA1UdDgQWBBQr0GlHlHYJ/vRrjS5ApvdHTX8IXjAfBgNVHSMEGDAWgBQr0GlH +lHYJ/vRrjS5ApvdHTX8IXjCCASkGA1UdIASCASAwggEcMIIBGAYJKoZIhvdjZAUB +MIIBCTBBBggrBgEFBQcCARY1aHR0cHM6Ly93d3cuYXBwbGUuY29tL2NlcnRpZmlj +YXRlYXV0aG9yaXR5L3Rlcm1zLmh0bWwwgcMGCCsGAQUFBwICMIG2GoGzUmVsaWFu +Y2Ugb24gdGhpcyBjZXJ0aWZpY2F0ZSBieSBhbnkgcGFydHkgYXNzdW1lcyBhY2Nl +cHRhbmNlIG9mIHRoZSB0aGVuIGFwcGxpY2FibGUgc3RhbmRhcmQgdGVybXMgYW5k +IGNvbmRpdGlvbnMgb2YgdXNlLCBjZXJ0aWZpY2F0ZSBwb2xpY3kgYW5kIGNlcnRp +ZmljYXRpb24gcHJhY3RpY2Ugc3RhdGVtZW50cy4wRAYDVR0fBD0wOzA5oDegNYYz +aHR0cHM6Ly93d3cuYXBwbGUuY29tL2NlcnRpZmljYXRlYXV0aG9yaXR5L3Jvb3Qu +Y3JsMFUGCCsGAQUFBwEBBEkwRzBFBggrBgEFBQcwAoY5aHR0cHM6Ly93d3cuYXBw +bGUuY29tL2NlcnRpZmljYXRlYXV0aG9yaXR5L2Nhc2lnbmVycy5odG1sMA0GCSqG +SIb3DQEBBQUAA4IBAQCd2i0oWC99dgS5BNM+zrdmY06PL9T+S61yvaM5xlJNBZhS +9YlRASR5vhoy9+VEi0tEBzmC1lrKtCBe2a4VXR2MHTK/ODFiSF3H4ZCx+CRA+F9Y +m1FdV53B5f88zHIhbsTp6aF31ywXJsM/65roCwO66bNKcuszCVut5mIxauivL9Wv +Hld2j383LS4CXN1jyfJxuCZA3xWNdUQ/eb3mHZnhQyw+rW++uaT+DjUZUWOxw961 +kj5ReAFziqQjyqSI8R5cH0EWLX6VCqrpiUGYGxrdyyC/R14MJsVVNU3GMIuZZxTH +CR+6R8faAQmHJEKVvRNgGQrv6n8Obs3BREM6StXj +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIGZjCCBE6gAwIBAgIPB35Sk3vgFeNX8GmMy+wMMA0GCSqGSIb3DQEBBQUAMHsx +CzAJBgNVBAYTAkNPMUcwRQYDVQQKDD5Tb2NpZWRhZCBDYW1lcmFsIGRlIENlcnRp +ZmljYWNpw7NuIERpZ2l0YWwgLSBDZXJ0aWPDoW1hcmEgUy5BLjEjMCEGA1UEAwwa +QUMgUmHDrXogQ2VydGljw6FtYXJhIFMuQS4wHhcNMDYxMTI3MjA0NjI5WhcNMzAw +NDAyMjE0MjAyWjB7MQswCQYDVQQGEwJDTzFHMEUGA1UECgw+U29jaWVkYWQgQ2Ft +ZXJhbCBkZSBDZXJ0aWZpY2FjacOzbiBEaWdpdGFsIC0gQ2VydGljw6FtYXJhIFMu +QS4xIzAhBgNVBAMMGkFDIFJhw616IENlcnRpY8OhbWFyYSBTLkEuMIICIjANBgkq +hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAq2uJo1PMSCMI+8PPUZYILrgIem08kBeG +qentLhM0R7LQcNzJPNCNyu5LF6vQhbCnIwTLqKL85XXbQMpiiY9QngE9JlsYhBzL +fDe3fezTf3MZsGqy2IiKLUV0qPezuMDU2s0iiXRNWhU5cxh0T7XrmafBHoi0wpOQ +Y5fzp6cSsgkiBzPZkc0OnB8OIMfuuzONj8LSWKdf/WU34ojC2I+GdV75LaeHM/J4 +Ny+LvB2GNzmxlPLYvEqcgxhaBvzz1NS6jBUJJfD5to0EfhcSM2tXSExP2yYe68yQ +54v5aHxwD6Mq0Do43zeX4lvegGHTgNiRg0JaTASJaBE8rF9ogEHMYELODVoqDA+b +MMCm8Ibbq0nXl21Ii/kDwFJnmxL3wvIumGVC2daa49AZMQyth9VXAnow6IYm+48j +ilSH5L887uvDdUhfHjlvgWJsxS3EF1QZtzeNnDeRyPYL1epjb4OsOMLzP96a++Ej +YfDIJss2yKHzMI+ko6Kh3VOz3vCaMh+DkXkwwakfU5tTohVTP92dsxA7SH2JD/zt +A/X7JWR1DhcZDY8AFmd5ekD8LVkH2ZD6mq093ICK5lw1omdMEWux+IBkAC1vImHF +rEsm5VoQgpukg3s0956JkSCXjrdCx2bD0Omk1vUgjcTDlaxECp1bczwmPS9KvqfJ +pxAe+59QafMCAwEAAaOB5jCB4zAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE +AwIBBjAdBgNVHQ4EFgQU0QnQ6dfOeXRU+Tows/RtLAMDG2gwgaAGA1UdIASBmDCB +lTCBkgYEVR0gADCBiTArBggrBgEFBQcCARYfaHR0cDovL3d3dy5jZXJ0aWNhbWFy +YS5jb20vZHBjLzBaBggrBgEFBQcCAjBOGkxMaW1pdGFjaW9uZXMgZGUgZ2FyYW50 +7WFzIGRlIGVzdGUgY2VydGlmaWNhZG8gc2UgcHVlZGVuIGVuY29udHJhciBlbiBs +YSBEUEMuMA0GCSqGSIb3DQEBBQUAA4ICAQBclLW4RZFNjmEfAygPU3zmpFmps4p6 +xbD/CHwso3EcIRNnoZUSQDWDg4902zNc8El2CoFS3UnUmjIz75uny3XlesuXEpBc +unvFm9+7OSPI/5jOCk0iAUgHforA1SBClETvv3eiiWdIG0ADBaGJ7M9i4z0ldma/ +Jre7Ir5v/zlXdLp6yQGVwZVR6Kss+LGGIOk/yzVb0hfpKv6DExdA7ohiZVvVO2Dp +ezy4ydV/NgIlqmjCMRW3MGXrfx1IebHPOeJCgBbT9ZMj/EyXyVo3bHwi2ErN0o42 +gzmRkBDI8ck1fj+404HGIGQatlDCIaR43NAvO2STdPCWkPHv+wlaNECW8DYSwaN0 +jJN+Qd53i+yG2dIPPy3RzECiiWZIHiCznCNZc6lEc7wkeZBWN7PGKX6jD/EpOe9+ +XCgycDWs2rjIdWb8m0w5R44bb5tNAlQiM+9hup4phO9OSzNHdpdqy35f/RWmnkJD +W2ZaiogN9xa5P1FlK2Zqi9E4UqLWRhH6/JocdJ6PlwsCT2TG9WjTSy3/pDceiz+/ +RL5hRqGEPQgnTIEgd4kI6mdAXmwIUV80WoyWaM3X94nCHNMyAK9Sy9NgWyo6R35r +MDOhYil/SrnhLecUIw4OGEfhefwVVdCx/CVxY3UzHCMrr1zZ7Ud3YA47Dx7SwNxk +BYn8eNZcLCZDqQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDUzCCAjugAwIBAgIBATANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEd +MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3Mg +Q2xhc3MgMiBDQSAxMB4XDTA2MTAxMzEwMjUwOVoXDTE2MTAxMzEwMjUwOVowSzEL +MAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MR0wGwYD +VQQDDBRCdXlwYXNzIENsYXNzIDIgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAIs8B0XY9t/mx8q6jUPFR42wWsE425KEHK8T1A9vNkYgxC7McXA0 +ojTTNy7Y3Tp3L8DrKehc0rWpkTSHIln+zNvnma+WwajHQN2lFYxuyHyXA8vmIPLX +l18xoS830r7uvqmtqEyeIWZDO6i88wmjONVZJMHCR3axiFyCO7srpgTXjAePzdVB +HfCuuCkslFJgNJQ72uA40Z0zPhX0kzLFANq1KWYOOngPIVJfAuWSeyXTkh4vFZ2B +5J2O6O+JzhRMVB0cgRJNcKi+EAUXfh/RuFdV7c27UsKwHnjCTTZoy1YmwVLBvXb3 +WNVyfh9EdrsAiR0WnVE1703CVu9r4Iw7DekCAwEAAaNCMEAwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUP42aWYv8e3uco684sDntkHGA1sgwDgYDVR0PAQH/BAQD +AgEGMA0GCSqGSIb3DQEBBQUAA4IBAQAVGn4TirnoB6NLJzKyQJHyIdFkhb5jatLP +gcIV1Xp+DCmsNx4cfHZSldq1fyOhKXdlyTKdqC5Wq2B2zha0jX94wNWZUYN/Xtm+ +DKhQ7SLHrQVMdvvt7h5HZPb3J31cKA9FxVxiXqaakZG3Uxcu3K1gnZZkOb1naLKu +BctN518fV4bVIJwo+28TOPX2EZL2fZleHwzoq0QkKXJAPTZSr4xYkHPB7GEseaHs +h7U/2k3ZIQAw3pDaDtMaSKk+hQsUi4y8QZ5q9w5wwDX3OaJdZtB7WZ+oRxKaJyOk +LY4ng5IgodcVf/EuGO70SH8vf/GhGLWhC5SgYiAynB321O+/TIho +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFnDCCA4SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJGUjET +MBEGA1UEChMKQ2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxJjAk +BgNVBAMMHUNlcnRpbm9taXMgLSBBdXRvcml0w6kgUmFjaW5lMB4XDTA4MDkxNzA4 +Mjg1OVoXDTI4MDkxNzA4Mjg1OVowYzELMAkGA1UEBhMCRlIxEzARBgNVBAoTCkNl +cnRpbm9taXMxFzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMSYwJAYDVQQDDB1DZXJ0 +aW5vbWlzIC0gQXV0b3JpdMOpIFJhY2luZTCCAiIwDQYJKoZIhvcNAQEBBQADggIP +ADCCAgoCggIBAJ2Fn4bT46/HsmtuM+Cet0I0VZ35gb5j2CN2DpdUzZlMGvE5x4jY +F1AMnmHawE5V3udauHpOd4cN5bjr+p5eex7Ezyh0x5P1FMYiKAT5kcOrJ3NqDi5N +8y4oH3DfVS9O7cdxbwlyLu3VMpfQ8Vh30WC8Tl7bmoT2R2FFK/ZQpn9qcSdIhDWe +rP5pqZ56XjUl+rSnSTV3lqc2W+HN3yNw2F1MpQiD8aYkOBOo7C+ooWfHpi2GR+6K +/OybDnT0K0kCe5B1jPyZOQE51kqJ5Z52qz6WKDgmi92NjMD2AR5vpTESOH2VwnHu +7XSu5DaiQ3XV8QCb4uTXzEIDS3h65X27uK4uIJPT5GHfceF2Z5c/tt9qc1pkIuVC +28+BA5PY9OMQ4HL2AHCs8MF6DwV/zzRpRbWT5BnbUhYjBYkOjUjkJW+zeL9i9Qf6 +lSTClrLooyPCXQP8w9PlfMl1I9f09bze5N/NgL+RiH2nE7Q5uiy6vdFrzPOlKO1E +nn1So2+WLhl+HPNbxxaOu2B9d2ZHVIIAEWBsMsGoOBvrbpgT1u449fCfDu/+MYHB +0iSVL1N6aaLwD4ZFjliCK0wi1F6g530mJ0jfJUaNSih8hp75mxpZuWW/Bd22Ql09 +5gBIgl4g9xGC3srYn+Y3RyYe63j3YcNBZFgCQfna4NH4+ej9Uji29YnfAgMBAAGj +WzBZMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBQN +jLZh2kS40RR9w759XkjwzspqsDAXBgNVHSAEEDAOMAwGCiqBegFWAgIAAQEwDQYJ +KoZIhvcNAQEFBQADggIBACQ+YAZ+He86PtvqrxyaLAEL9MW12Ukx9F1BjYkMTv9s +ov3/4gbIOZ/xWqndIlgVqIrTseYyCYIDbNc/CMf4uboAbbnW/FIyXaR/pDGUu7ZM +OH8oMDX/nyNTt7buFHAAQCvaR6s0fl6nVjBhK4tDrP22iCj1a7Y+YEq6QpA0Z43q +619FVDsXrIvkxmUP7tCMXWY5zjKn2BCXwH40nJ+U8/aGH88bc62UeYdocMMzpXDn +2NU4lG9jeeu/Cg4I58UvD0KgKxRA/yHgBcUn4YQRE7rWhh1BCxMjidPJC+iKunqj +o3M3NYB9Ergzd0A4wPpeMNLytqOx1qKVl4GbUu1pTP+A5FPbVFsDbVRfsbjvJL1v +nxHDx2TCDyhihWZeGnuyt++uNckZM6i4J9szVb9o4XVIRFb7zdNIu0eJOqxp9YDG +5ERQL1TEqkPFMTFYvZbF6nVsmnWxTfj3l/+WFvKXTej28xH5On2KOG4Ey+HTRRWq +pdEdnV1j6CTmNhTih60bWfVEm/vXd3wfAXBioSAaosUaKPQhA+4u2cGA6rnZgtZb +dsLLO7XSAPCjDuGtbkD326C00EauFddEwk01+dIL8hf2rGbVJLJP0RyZwG71fet0 +BLj5TXcJ17TPBzAJ8bgAVtkXFhYKK4bfjwEZGuW7gmP/vgt2Fl43N+bYdJeimUV5 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYT +AlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBD +QTAeFw0wNjA3MDQxNzIwMDRaFw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJP +MREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7IJUqOtdu0KBuqV5Do +0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHHrfAQ +UySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5d +RdY4zTW2ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQ +OA7+j0xbm0bqQfWwCHTD0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwv +JoIQ4uNllAoEwF73XVv4EOLQunpL+943AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08C +AwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAcYwHQYDVR0O +BBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IBAQA+0hyJ +LjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecY +MnQ8SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ +44gx+FkagQnIl6Z0x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6I +Jd1hJyMctTEHBDa0GpC9oHRxUIltvBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNw +i/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7NzTogVZ96edhBiIL5VaZVDADlN +9u6wWk5JRFRYX0KD +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x +GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv +b3QgQ0EgMzAeFw0wNjExMjQxOTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNV +BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W +YWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDM +V0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNggDhoB +4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUr +H556VOijKTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd +8lyyBTNvijbO0BNO/79KDDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9Cabwv +vWhDFlaJKjdhkf2mrk7AyxRllDdLkgbvBNDInIjbC3uBr7E9KsRlOni27tyAsdLT +mZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwpp5ijJUMv7/FfJuGITfhe +btfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8nT8KKdjc +T5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDt +WAEXMJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZ +c6tsgLjoC2SToJyMGf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A +4iLItLRkT9a6fUg+qGkM17uGcclzuD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYD +VR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHTBgkrBgEEAb5YAAMwgcUwgZMG +CCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0 +aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0 +aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVu +dC4wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2Nw +czALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4G +A1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4ywLQoUmkRzBFMQswCQYDVQQGEwJC +TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UEAxMSUXVvVmFkaXMg +Um9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZVqyM0 +7ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSem +d1o417+shvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd ++LJ2w/w4E6oM3kJpK27zPOuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B +4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadN +t54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp8kokUvd0/bpO5qgdAm6x +DYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBCbjPsMZ57 +k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6s +zHXug/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0j +Wy10QJLZYxkNc91pvGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeT +mJlglFwjz1onl14LBQaTNx47aTbrqZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK +4SVhM7JZG+Ju1zdXtg2pEto= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDVTCCAj2gAwIBAgIESTMAATANBgkqhkiG9w0BAQUFADAyMQswCQYDVQQGEwJD +TjEOMAwGA1UEChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1QwHhcNMDcwNDE2 +MDcwOTE0WhcNMjcwNDE2MDcwOTE0WjAyMQswCQYDVQQGEwJDTjEOMAwGA1UEChMF +Q05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1QwggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQDTNfc/c3et6FtzF8LRb+1VvG7q6KR5smzDo+/hn7E7SIX1mlwh +IhAsxYLO2uOabjfhhyzcuQxauohV3/2q2x8x6gHx3zkBwRP9SFIhxFXf2tizVHa6 +dLG3fdfA6PZZxU3Iva0fFNrfWEQlMhkqx35+jq44sDB7R3IJMfAw28Mbdim7aXZO +V/kbZKKTVrdvmW7bCgScEeOAH8tjlBAKqeFkgjH5jCftppkA9nCTGPihNIaj3XrC +GHn2emU1z5DrvTOTn1OrczvmmzQgLx3vqR1jGqCA2wMv+SYahtKNu6m+UjqHZ0gN +v7Sg2Ca+I19zN38m5pIEo3/PIKe38zrKy5nLAgMBAAGjczBxMBEGCWCGSAGG+EIB +AQQEAwIABzAfBgNVHSMEGDAWgBRl8jGtKvf33VKWCscCwQ7vptU7ETAPBgNVHRMB +Af8EBTADAQH/MAsGA1UdDwQEAwIB/jAdBgNVHQ4EFgQUZfIxrSr3991SlgrHAsEO +76bVOxEwDQYJKoZIhvcNAQEFBQADggEBAEs17szkrr/Dbq2flTtLP1se31cpolnK +OOK5Gv+e5m4y3R6u6jW39ZORTtpC4cMXYFDy0VwmuYK36m3knITnA3kXr5g9lNvH +ugDnuL8BV8F3RTIMO/G0HAiw/VGgod2aHRM2mm23xzy54cXZF/qD1T0VoDy7Hgvi +yJA/qIYM/PmLXoXLT1tLYhFHxUV8BS9BsZ4QaRuZluBVeftOhpm4lNqGOGqTo+fL +buXf6iFViZx9fX+Y9QCJ7uOEwFyWtcVG6kbghVW2G8kS1sHNzYDzAgE8yGnLRUhj +2JTQ7IUOO04RZfSCjKY9ri4ilAnIXOo8gV0WKgOXFlUJ24pBgp5mmxE= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT +MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i +YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG +EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg +R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9 +9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq +fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv +iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU +1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+ +bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW +MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA +ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l +uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn +Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS +tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF +PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un +hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV +5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDyzCCArOgAwIBAgIDAOJIMA0GCSqGSIb3DQEBBQUAMIGLMQswCQYDVQQGEwJB +VDFIMEYGA1UECgw/QS1UcnVzdCBHZXMuIGYuIFNpY2hlcmhlaXRzc3lzdGVtZSBp +bSBlbGVrdHIuIERhdGVudmVya2VociBHbWJIMRgwFgYDVQQLDA9BLVRydXN0LVF1 +YWwtMDIxGDAWBgNVBAMMD0EtVHJ1c3QtUXVhbC0wMjAeFw0wNDEyMDIyMzAwMDBa +Fw0xNDEyMDIyMzAwMDBaMIGLMQswCQYDVQQGEwJBVDFIMEYGA1UECgw/QS1UcnVz +dCBHZXMuIGYuIFNpY2hlcmhlaXRzc3lzdGVtZSBpbSBlbGVrdHIuIERhdGVudmVy +a2VociBHbWJIMRgwFgYDVQQLDA9BLVRydXN0LVF1YWwtMDIxGDAWBgNVBAMMD0Et +VHJ1c3QtUXVhbC0wMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJaR +q9eOsFm4Ab20Hq2Z/aH86gyWa48uSUjY6eQkguHYuszr3gdcSMYZggFHQgnhfLmf +ro/27l5rqKhWiDhWs+b+yZ1PNDhRPJy+86ycHMg9XJqErveULBSyZDdgjhSwOyrN +ibUir/fkf+4sKzP5jjytTKJXD/uCxY4fAd9TjMEVpN3umpIS0ijpYhclYDHvzzGU +833z5Dwhq5D8bc9jp8YSAHFJ1xzIoO1jmn3jjyjdYPnY5harJtHQL73nDQnfbtTs +5ThT9GQLulrMgLU4WeyAWWWEMWpfVZFMJOUkmoOEer6A8e5fIAeqdxdsC+JVqpZ4 +CAKel/Arrlj1gFA//jsCAwEAAaM2MDQwDwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4E +CgQIQj0rJKbBRc4wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQBG +yxFjUA2bPkXUSC2SfJ29tmrbiLKal+g6a9M8Xwd+Ejo+oYkNP6F4GfeDtAXpm7xb +9Ly8lhdbHcpRhzCUQHJ1tBCiGdLgmhSx7TXjhhanKOdDgkdsC1T+++piuuYL72TD +gUy2Sb1GHlJ1Nc6rvB4fpxSDAOHqGpUq9LWsc3tFkXqRqmQVtqtR77npKIFBioc6 +2jTBwDMPX3hDJDR1DSPc6BnZliaNw2IHdiMQ0mBoYeRnFdq+TyDKsjmJOOQPLzzL +/saaw6F891+gBjLFEFquDyR73lAPJS279R3csi8WWk4ZYUC/1V8H3Ktip/J6ac8e +qhLCbmJ81Lo92JGHz/ot +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ +RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD +VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX +DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y +ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy +VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr +mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr +IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK +mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu +XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy +dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye +jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1 +BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3 +DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92 +9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx +jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0 +Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz +ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS +R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0 +Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW +KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl +cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0MloXDTI2MTEyNzIw +NTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkw +NwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSBy +ZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNV +BAMTJEVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFo +Nu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf4 +4LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9 +KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGI +rb68j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi +94DkZfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOB +sDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAi +gA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSMEGDAWgBRo +kORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DHhmak8fdLQ/uE +vW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA +A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9t +O1KzKtvn1ISMY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6Zua +AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP +9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/ +eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m +0vdXcDazv/wor3ElhVsT/h5/WrQ8 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICpzCCAi2gAwIBAgIQTHm1miicdjFk9YlE0JEC3jAKBggqhkjOPQQDAzCBlDEL +MAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYD +VQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBD +bGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0g +RzQwHhcNMTIxMDE4MDAwMDAwWhcNMzcxMjAxMjM1OTU5WjCBlDELMAkGA1UEBhMC +VVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZTeW1h +bnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBDbGFzcyAzIFB1 +YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAARXz+qzOU0/oSHgbi84csaHl/OFC0fnD1HI0fSZm8pZ +Zf9M+eoLtyXV0vbsMS0yYhLXdoan+jjJZdT+c+KEOfhMSWIT3brViKBfPchPsD+P +oVAR5JNGrcNfy/GkapVW6MCjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E +BTADAQH/MB0GA1UdDgQWBBQknbzScfcdwiW+IvGJpSwVOzQeXjAKBggqhkjOPQQD +AwNoADBlAjEAuWZoZdsF0Dh9DvPIdWG40CjEsUozUVj78jwQyK5HeHbKZiQXhj5Q +Vm6lLZmIuL0kAjAD6qfnqDzqnWLGX1TamPR3vU+PGJyRXEdrQE0QHbPhicoLIsga +xcX+i93B3294n5E= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j +ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL +MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 +LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug +RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm ++9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW +PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM +xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB +Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3 +hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg +EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA +FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec +nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z +eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF +hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 +Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe +vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep ++OkuE6N36B9K +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIGHDCCBASgAwIBAgIES45gAzANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJE +SzESMBAGA1UEChMJVFJVU1QyNDA4MSIwIAYDVQQDExlUUlVTVDI0MDggT0NFUyBQ +cmltYXJ5IENBMB4XDTEwMDMwMzEyNDEzNFoXDTM3MTIwMzEzMTEzNFowRTELMAkG +A1UEBhMCREsxEjAQBgNVBAoTCVRSVVNUMjQwODEiMCAGA1UEAxMZVFJVU1QyNDA4 +IE9DRVMgUHJpbWFyeSBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB +AJlJodr3U1Fa+v8HnyACHV81/wLevLS0KUk58VIABl6Wfs3LLNoj5soVAZv4LBi5 +gs7E8CZ9w0F2CopW8vzM8i5HLKE4eedPdnaFqHiBZ0q5aaaQArW+qKJx1rT/AaXt +alMB63/yvJcYlXS2lpexk5H/zDBUXeEQyvfmK+slAySWT6wKxIPDwVapauFY9QaG ++VBhCa5jBstWS7A5gQfEvYqn6csZ3jW472kW6OFNz6ftBcTwufomGJBMkonf4ZLr +6t0AdRi9jflBPz3MNNRGxyjIuAmFqGocYFA/OODBRjvSHB2DygqQ8k+9tlpvzMRr +kU7jq3RKL+83G1dJ3/LTjCLz4ryEMIC/OJ/gNZfE0qXddpPtzflIPtUFVffXdbFV +1t6XZFhJ+wBHQCpJobq/BjqLWUA86upsDbfwnePtmIPRCemeXkY0qabC+2Qmd2Fe +xyZphwTyMnbqy6FG1tB65dYf3mOqStmLa3RcHn9+2dwNfUkh0tjO2FXD7drWcU0O +I9DW8oAypiPhm/QCjMU6j6t+0pzqJ/S0tdAo+BeiXK5hwk6aR+sRb608QfBbRAs3 +U/q8jSPByenggac2BtTN6cl+AA1Mfcgl8iXWNFVGegzd/VS9vINClJCe3FNVoUnR +YCKkj+x0fqxvBLopOkJkmuZw/yhgMxljUi2qYYGn90OzAgMBAAGjggESMIIBDjAP +BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjARBgNVHSAECjAIMAYGBFUd +IAAwgZcGA1UdHwSBjzCBjDAsoCqgKIYmaHR0cDovL2NybC5vY2VzLnRydXN0MjQw +OC5jb20vb2Nlcy5jcmwwXKBaoFikVjBUMQswCQYDVQQGEwJESzESMBAGA1UEChMJ +VFJVU1QyNDA4MSIwIAYDVQQDExlUUlVTVDI0MDggT0NFUyBQcmltYXJ5IENBMQ0w +CwYDVQQDEwRDUkwxMB8GA1UdIwQYMBaAFPZt+LFIs0FDAduGROUYBbdezAY3MB0G +A1UdDgQWBBT2bfixSLNBQwHbhkTlGAW3XswGNzANBgkqhkiG9w0BAQsFAAOCAgEA +VPAQGrT7dIjD3/sIbQW86f9CBPu0c7JKN6oUoRUtKqgJ2KCdcB5ANhCoyznHpu3m +/dUfVUI5hc31CaPgZyY37hch1q4/c9INcELGZVE/FWfehkH+acpdNr7j8UoRZlkN +15b/0UUBfGeiiJG/ugo4llfoPrp8bUmXEGggK3wyqIPcJatPtHwlb6ympfC2b/Ld +v/0IdIOzIOm+A89Q0utx+1cOBq72OHy8gpGb6MfncVFMoL2fjP652Ypgtr8qN9Ka +/XOazktiIf+2Pzp7hLi92hRc9QMYexrV/nnFSQoWdU8TqULFUoZ3zTEC3F/g2yj+ +FhbrgXHGo5/A4O74X+lpbY2XV47aSuw+DzcPt/EhMj2of7SA55WSgbjPMbmNX0rb +oenSIte2HRFW5Tr2W+qqkc/StixgkKdyzGLoFx/xeTWdJkZKwyjqge2wJqws2upY +EiThhC497+/mTiSuXd69eVUwKyqYp9SD2rTtNmF6TCghRM/dNsJOl+osxDVGcwvt +WIVFF/Onlu5fu1NHXdqNEfzldKDUvCfii3L2iATTZyHwU9CALE+2eIA+PIaLgnM1 +1oCfUnYBkQurTrihvzz9PryCVkLxiqRmBVvUz+D4N5G/wvvKDS6t6cPCS+hqM482 +cbBsn0R9fFLO4El62S9eH1tqOzO20OAOK65yJIsOpSE= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEY +MBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21t +dW5pY2F0aW9uIFJvb3RDQTEwHhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5 +WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYD +VQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw8yl8 +9f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJ +DKaVv0uMDPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9 +Ms+k2Y7CI9eNqPPYJayX5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/N +QV3Is00qVUarH9oe4kA92819uZKAnDfdDJZkndwi92SL32HeFZRSFaB9UslLqCHJ +xrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2JChzAgMBAAGjPzA9MB0G +A1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYwDwYDVR0T +AQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vG +kl3g0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfr +Uj94nK9NrvjVT8+amCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5 +Bw+SUEmK3TGXX8npN6o7WWWXlDLJs58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJU +JRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ6rBK+1YWc26sTfcioU+tHXot +RSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAiFL39vmwLAw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJVUzEc +MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1aWZheCBT +ZWN1cmUgR2xvYmFsIGVCdXNpbmVzcyBDQS0xMB4XDTk5MDYyMTA0MDAwMFoXDTIw +MDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0VxdWlmYXggU2Vj +dXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJlIEdsb2JhbCBlQnVzaW5l +c3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuucXkAJlsTRVPEnC +UdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQytd4zjTov2/KaelpzmKNc6fuKcxtc +58O/gGzNqfTWK8D3+ZmqY6KxRwIP1ORROhI8bIpaVIRw28HFkM9yRcuoWcDNM50/ +o5brhTMhHD4ePmBudpxnhcXIw2ECAwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAH +MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUvqigdHJQa0S3ySPY+6j/s1dr +aGwwHQYDVR0OBBYEFL6ooHRyUGtEt8kj2Puo/7NXa2hsMA0GCSqGSIb3DQEBBAUA +A4GBADDiAVGqx+pf2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okENI7SS+RkA +Z70Br83gcfxaz2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv +8qIYNMR1pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIF5zCCA8+gAwIBAgIITK9zQhyOdAIwDQYJKoZIhvcNAQEFBQAwgYAxODA2BgNV +BAMML0VCRyBFbGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sx +c8SxMTcwNQYDVQQKDC5FQkcgQmlsacWfaW0gVGVrbm9sb2ppbGVyaSB2ZSBIaXpt +ZXRsZXJpIEEuxZ4uMQswCQYDVQQGEwJUUjAeFw0wNjA4MTcwMDIxMDlaFw0xNjA4 +MTQwMDMxMDlaMIGAMTgwNgYDVQQDDC9FQkcgRWxla3Ryb25payBTZXJ0aWZpa2Eg +SGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTE3MDUGA1UECgwuRUJHIEJpbGnFn2ltIFRl +a25vbG9qaWxlcmkgdmUgSGl6bWV0bGVyaSBBLsWeLjELMAkGA1UEBhMCVFIwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDuoIRh0DpqZhAy2DE4f6en5f2h +4fuXd7hxlugTlkaDT7byX3JWbhNgpQGR4lvFzVcfd2NR/y8927k/qqk153nQ9dAk +tiHq6yOU/im/+4mRDGSaBUorzAzu8T2bgmmkTPiab+ci2hC6X5L8GCcKqKpE+i4s +tPtGmggDg3KriORqcsnlZR9uKg+ds+g75AxuetpX/dfreYteIAbTdgtsApWjluTL +dlHRKJ2hGvxEok3MenaoDT2/F08iiFD9rrbskFBKW5+VQarKD7JK/oCZTqNGFav4 +c0JqwmZ2sQomFd2TkuzbqV9UIlKRcF0T6kjsbgNs2d1s/OsNA/+mgxKb8amTD8Um +TDGyY5lhcucqZJnSuOl14nypqZoaqsNW2xCaPINStnuWt6yHd6i58mcLlEOzrz5z ++kI2sSXFCjEmN1ZnuqMLfdb3ic1nobc6HmZP9qBVFCVMLDMNpkGMvQQxahByCp0O +Lna9XvNRiYuoP1Vzv9s6xiQFlpJIqkuNKgPlV5EQ9GooFW5Hd4RcUXSfGenmHmMW +OeMRFeNYGkS9y8RsZteEBt8w9DeiQyJ50hBs37vmExH8nYQKE3vwO9D8owrXieqW +fo1IhR5kX9tUoqzVegJ5a9KK8GfaZXINFHDk6Y54jzJ0fFfy1tb0Nokb+Clsi7n2 +l9GkLqq+CxnCRelwXQIDAJ3Zo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB +/wQEAwIBBjAdBgNVHQ4EFgQU587GT/wWZ5b6SqMHwQSny2re2kcwHwYDVR0jBBgw +FoAU587GT/wWZ5b6SqMHwQSny2re2kcwDQYJKoZIhvcNAQEFBQADggIBAJuYml2+ +8ygjdsZs93/mQJ7ANtyVDR2tFcU22NU57/IeIl6zgrRdu0waypIN30ckHrMk2pGI +6YNw3ZPX6bqz3xZaPt7gyPvT/Wwp+BVGoGgmzJNSroIBk5DKd8pNSe/iWtkqvTDO +TLKBtjDOWU/aWR1qeqRFsIImgYZ29fUQALjuswnoT4cCB64kXPBfrAowzIpAoHME +wfuJJPaaHFy3PApnNgUIMbOv2AFoKuB4j3TeuFGkjGwgPaL7s9QJ/XvCgKqTbCmY +Iai7FvOpEl90tYeY8pUm3zTvilORiF0alKM/fCL414i6poyWqD1SNGKfAB5UVUJn +xk1Gj7sURT0KlhaOEKGXmdXTMIXM3rRyt7yKPBgpaP3ccQfuJDlq+u2lrDgv+R4Q +DgZxGhBM/nV+/x5XOULK1+EVoVZVWRvRo68R2E7DpSvvkL/A7IITW43WciyTTo9q +Kd+FPNMN4KIYEsxVL0e3p5sC/kH2iExt2qkBR4NkJ2IQgtYSe14DHzSpyZH+r11t +hie3I6p1GMog57AP14kOpmciY/SDQSsGS7tY1dHXt7kQY9iJSrSq3RZj9W6+YKH4 +7ejWkE8axsWgKdOnIaj1Wjz3x0miIZpKlVIglnKaZsv30oZDfCK+lvm9AahH3eU7 +QPl1K5srRmSGjR70j/sHd9DqSaIcjVIUpgqT +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFFzCCA/+gAwIBAgIBETANBgkqhkiG9w0BAQUFADCCASsxCzAJBgNVBAYTAlRS +MRgwFgYDVQQHDA9HZWJ6ZSAtIEtvY2FlbGkxRzBFBgNVBAoMPlTDvHJraXllIEJp +bGltc2VsIHZlIFRla25vbG9qaWsgQXJhxZ90xLFybWEgS3VydW11IC0gVMOcQsSw +VEFLMUgwRgYDVQQLDD9VbHVzYWwgRWxla3Ryb25payB2ZSBLcmlwdG9sb2ppIEFy +YcWfdMSxcm1hIEVuc3RpdMO8c8O8IC0gVUVLQUUxIzAhBgNVBAsMGkthbXUgU2Vy +dGlmaWthc3lvbiBNZXJrZXppMUowSAYDVQQDDEFUw5xCxLBUQUsgVUVLQUUgS8O2 +ayBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsSAtIFPDvHLDvG0gMzAe +Fw0wNzA4MjQxMTM3MDdaFw0xNzA4MjExMTM3MDdaMIIBKzELMAkGA1UEBhMCVFIx +GDAWBgNVBAcMD0dlYnplIC0gS29jYWVsaTFHMEUGA1UECgw+VMO8cmtpeWUgQmls +aW1zZWwgdmUgVGVrbm9sb2ppayBBcmHFn3TEsXJtYSBLdXJ1bXUgLSBUw5xCxLBU +QUsxSDBGBgNVBAsMP1VsdXNhbCBFbGVrdHJvbmlrIHZlIEtyaXB0b2xvamkgQXJh +xZ90xLFybWEgRW5zdGl0w7xzw7wgLSBVRUtBRTEjMCEGA1UECwwaS2FtdSBTZXJ0 +aWZpa2FzeW9uIE1lcmtlemkxSjBIBgNVBAMMQVTDnELEsFRBSyBVRUtBRSBLw7Zr +IFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIC0gU8O8csO8bSAzMIIB +IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAim1L/xCIOsP2fpTo6iBkcK4h +gb46ezzb8R1Sf1n68yJMlaCQvEhOEav7t7WNeoMojCZG2E6VQIdhn8WebYGHV2yK +O7Rm6sxA/OOqbLLLAdsyv9Lrhc+hDVXDWzhXcLh1xnnRFDDtG1hba+818qEhTsXO +fJlfbLm4IpNQp81McGq+agV/E5wrHur+R84EpW+sky58K5+eeROR6Oqeyjh1jmKw +lZMq5d/pXpduIF9fhHpEORlAHLpVK/swsoHvhOPc7Jg4OQOFCKlUAwUp8MmPi+oL +hmUZEdPpCSPeaJMDyTYcIW7OjGbxmTDY17PDHfiBLqi9ggtm/oLL4eAagsNAgQID +AQABo0IwQDAdBgNVHQ4EFgQUvYiHyY/2pAoLquvF/pEjnatKijIwDgYDVR0PAQH/ +BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAB18+kmP +NOm3JpIWmgV050vQbTlswyb2zrgxvMTfvCr4N5EY3ATIZJkrGG2AA1nJrvhY0D7t +wyOfaTyGOBye79oneNGEN3GKPEs5z35FBtYt2IpNeBLWrcLTy9LQQfMmNkqblWwM +7uXRQydmwYj3erMgbOqwaSvHIOgMA8RBBZniP+Rr+KCGgceExh/VS4ESshYhLBOh +gLJeDEoTniDYYkCrkOpkSi+sDQESeUWoL4cZaMjihccwsnX5OD+ywJO0a+IDRM5n +oN+J1q2MdqMTw5RhK2vZbMEHCiIHhWyFJEapvj+LeISCfiQMnf2BN+MlqO02TpUs +yZyQ2uypQjyttgI= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEPTCCAyWgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvzE/MD0GA1UEAww2VMOc +UktUUlVTVCBFbGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sx +c8SxMQswCQYDVQQGEwJUUjEPMA0GA1UEBwwGQW5rYXJhMV4wXAYDVQQKDFVUw5xS +S1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kg +SGl6bWV0bGVyaSBBLsWeLiAoYykgQXJhbMSxayAyMDA3MB4XDTA3MTIyNTE4Mzcx +OVoXDTE3MTIyMjE4MzcxOVowgb8xPzA9BgNVBAMMNlTDnFJLVFJVU1QgRWxla3Ry +b25payBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTELMAkGA1UEBhMC +VFIxDzANBgNVBAcMBkFua2FyYTFeMFwGA1UECgxVVMOcUktUUlVTVCBCaWxnaSDE +sGxldGnFn2ltIHZlIEJpbGnFn2ltIEfDvHZlbmxpxJ9pIEhpem1ldGxlcmkgQS7F +ni4gKGMpIEFyYWzEsWsgMjAwNzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAKu3PgqMyKVYFeaK7yc9SrToJdPNM8Ig3BnuiD9NYvDdE3ePYakqtdTyuTFY +KTsvP2qcb3N2Je40IIDu6rfwxArNK4aUyeNgsURSsloptJGXg9i3phQvKUmi8wUG ++7RP2qFsmmaf8EMJyupyj+sA1zU511YXRxcw9L6/P8JorzZAwan0qafoEGsIiveG +HtyaKhUG9qPw9ODHFNRRf8+0222vR5YXm3dx2KdxnSQM9pQ/hTEST7ruToK4uT6P +IzdezKKqdfcYbwnTrqdUKDT74eA7YH2gvnmJhsifLfkKS8RQouf9eRbHegsYz85M +733WB2+Y8a+xwXrXgTW4qhe04MsCAwEAAaNCMEAwHQYDVR0OBBYEFCnFkKslrxHk +Yb+j/4hhkeYO/pyBMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0G +CSqGSIb3DQEBBQUAA4IBAQAQDdr4Ouwo0RSVgrESLFF6QSU2TJ/sPx+EnWVUXKgW +AkD6bho3hO9ynYYKVZ1WKKxmLNA6VpM0ByWtCLCPyA8JWcqdmBzlVPi5RX9ql2+I +aE1KBiY3iAIOtsbWcpnOa3faYjGkVh+uX4132l32iPwa2Z61gfAyuOOI0JzzaqC5 +mxRZNTZPz/OOXl0XrRWV2N2y1RVuAE6zS89mlOTgzbUF2mNXi+WzqtvALhyQRNsa +XRik7r4EW5nVcV9VZWRi1aKbBFmGyGJ353yCRWo9F7/snXUMrqNvWtMvmDb08PUZ +qxFdyKbjKlhqQgnDvZImZjINXQhVdP+MmNAKpoRq0Tl9 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEYDCCA0igAwIBAgICATAwDQYJKoZIhvcNAQELBQAwWTELMAkGA1UEBhMCVVMx +GDAWBgNVBAoTD1UuUy4gR292ZXJubWVudDENMAsGA1UECxMERlBLSTEhMB8GA1UE +AxMYRmVkZXJhbCBDb21tb24gUG9saWN5IENBMB4XDTEwMTIwMTE2NDUyN1oXDTMw +MTIwMTE2NDUyN1owWTELMAkGA1UEBhMCVVMxGDAWBgNVBAoTD1UuUy4gR292ZXJu +bWVudDENMAsGA1UECxMERlBLSTEhMB8GA1UEAxMYRmVkZXJhbCBDb21tb24gUG9s +aWN5IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2HX7NRY0WkG/ +Wq9cMAQUHK14RLXqJup1YcfNNnn4fNi9KVFmWSHjeavUeL6wLbCh1bI1FiPQzB6+ +Duir3MPJ1hLXp3JoGDG4FyKyPn66CG3G/dFYLGmgA/Aqo/Y/ISU937cyxY4nsyOl +4FKzXZbpsLjFxZ+7xaBugkC7xScFNknWJidpDDSPzyd6KgqjQV+NHQOGgxXgVcHF +mCye7Bpy3EjBPvmE0oSCwRvDdDa3ucc2Mnr4MrbQNq4iGDGMUHMhnv6DOzCIJOPp +wX7e7ZjHH5IQip9bYi+dpLzVhW86/clTpyBLqtsgqyFOHQ1O5piF5asRR12dP8Qj +wOMUBm7+nQIDAQABo4IBMDCCASwwDwYDVR0TAQH/BAUwAwEB/zCB6QYIKwYBBQUH +AQsEgdwwgdkwPwYIKwYBBQUHMAWGM2h0dHA6Ly9odHRwLmZwa2kuZ292L2ZjcGNh +L2NhQ2VydHNJc3N1ZWRCeWZjcGNhLnA3YzCBlQYIKwYBBQUHMAWGgYhsZGFwOi8v +bGRhcC5mcGtpLmdvdi9jbj1GZWRlcmFsJTIwQ29tbW9uJTIwUG9saWN5JTIwQ0Es +b3U9RlBLSSxvPVUuUy4lMjBHb3Zlcm5tZW50LGM9VVM/Y0FDZXJ0aWZpY2F0ZTti +aW5hcnksY3Jvc3NDZXJ0aWZpY2F0ZVBhaXI7YmluYXJ5MA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQUrQx6dVzl85jEeZgOrCj9l/TnAvwwDQYJKoZIhvcNAQELBQAD +ggEBAI9z2uF/gLGH9uwsz9GEYx728Yi3mvIRte9UrYpuGDco71wb5O9Qt2wmGCMi +TR0mRyDpCZzicGJxqxHPkYnos/UqoEfAFMtOQsHdDA4b8Idb7OV316rgVNdF9IU+ +7LQd3nyKf1tNnJaK0KIyn9psMQz4pO9+c+iR3Ah6cFqgr2KBWfgAdKLI3VTKQVZH +venAT+0g3eOlCd+uKML80cgX2BLHb94u6b2akfI8WpQukSKAiaGMWMyDeiYZdQKl +Dn0KJnNR6obLB6jI/WNaNZvSr79PMUjBhHDbNXuaGQ/lj/RqDG8z2esccKIN47lQ +A2EC/0rskqTcLe4qNJMHtyznGI8= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjEL +MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW +ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2ln +biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp +U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y +aXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjELMAkG +A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJp +U2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwg +SW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2ln +biBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8Utpkmw4tXNherJI9/gHm +GUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGzrl0Bp3ve +fLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJ +aW1hZ2UvZ2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYj +aHR0cDovL2xvZ28udmVyaXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMW +kf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMDA2gAMGUCMGYhDBgmYFo4e1ZC +4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIxAJw9SDkjOVga +FRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIID4TCCAsmgAwIBAgIOYyUAAQACFI0zFQLkbPQwDQYJKoZIhvcNAQEFBQAwezEL +MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNV +BAsTG1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQTEoMCYGA1UEAxMfVEMgVHJ1 +c3RDZW50ZXIgVW5pdmVyc2FsIENBIElJSTAeFw0wOTA5MDkwODE1MjdaFw0yOTEy +MzEyMzU5NTlaMHsxCzAJBgNVBAYTAkRFMRwwGgYDVQQKExNUQyBUcnVzdENlbnRl +ciBHbWJIMSQwIgYDVQQLExtUQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0ExKDAm +BgNVBAMTH1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQSBJSUkwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDC2pxisLlxErALyBpXsq6DFJmzNEubkKLF +5+cvAqBNLaT6hdqbJYUtQCggbergvbFIgyIpRJ9Og+41URNzdNW88jBmlFPAQDYv +DIRlzg9uwliT6CwLOunBjvvya8o84pxOjuT5fdMnnxvVZ3iHLX8LR7PH6MlIfK8v +zArZQe+f/prhsq75U7Xl6UafYOPfjdN/+5Z+s7Vy+EutCHnNaYlAJ/Uqwa1D7KRT +yGG299J5KmcYdkhtWyUB0SbFt1dpIxVbYYqt8Bst2a9c8SaQaanVDED1M4BDj5yj +dipFtK+/fz6HP3bFzSreIMUWWMv5G/UPyw0RUmS40nZid4PxWJ//AgMBAAGjYzBh +MB8GA1UdIwQYMBaAFFbn4VslQ4Dg9ozhcbyO5YAvxEjiMA8GA1UdEwEB/wQFMAMB +Af8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRW5+FbJUOA4PaM4XG8juWAL8RI +4jANBgkqhkiG9w0BAQUFAAOCAQEAg8ev6n9NCjw5sWi+e22JLumzCecYV42Fmhfz +dkJQEw/HkG8zrcVJYCtsSVgZ1OK+t7+rSbyUyKu+KGwWaODIl0YgoGhnYIg5IFHY +aAERzqf2EQf27OysGh+yZm5WZ2B6dF7AbZc2rrUNXWZzwCUyRdhKBgePxLcHsU0G +DeGl6/R1yrqc0L2z0zIkTO5+4nYES0lT2PLpVDP85XEfPRRclkvxOvIAu2y0+pZV +CIgJwcyRGSmwIC3/yzikQOEXvnlhgP8HA4ZMTnsGnxGGjYnuJ8Tb4rwZjgvDwxPH +LQNjO9Po5KIqwoIIlBZU8O8fJ5AluA0OKBtHd0e9HKgl8ZS0Zg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDcTCCAlmgAwIBAgIVAOYJ/nrqAGiM4CS07SAbH+9StETRMA0GCSqGSIb3DQEB +BQUAMFAxCzAJBgNVBAYTAlBMMSgwJgYDVQQKDB9LcmFqb3dhIEl6YmEgUm96bGlj +emVuaW93YSBTLkEuMRcwFQYDVQQDDA5TWkFGSVIgUk9PVCBDQTAeFw0xMTEyMDYx +MTEwNTdaFw0zMTEyMDYxMTEwNTdaMFAxCzAJBgNVBAYTAlBMMSgwJgYDVQQKDB9L +cmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRcwFQYDVQQDDA5TWkFGSVIg +Uk9PVCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKxHL49ZMTml +6g3wpYwrvQKkvc0Kc6oJ5sxfgmp1qZfluwbv88BdocHSiXlY8NzrVYzuWBp7J/9K +ULMAoWoTIzOQ6C9TNm4YbA9A1jdX1wYNL5Akylf8W5L/I4BXhT9KnlI6x+a7BVAm +nr/Ttl+utT/Asms2fRfEsF2vZPMxH4UFqOAhFjxTkmJWf2Cu4nvRQJHcttB+cEAo +ag/hERt/+tzo4URz6x6r19toYmxx4FjjBkUhWQw1X21re//Hof2+0YgiwYT84zLb +eqDqCOMOXxvH480yGDkh/QoazWX3U75HQExT/iJlwnu7I1V6HXztKIwCBjsxffbH +3jOshCJtywcCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwHQYDVR0OBBYEFFOSo33/gnbwM9TrkmdHYTMbaDsqMA0GCSqGSIb3DQEBBQUA +A4IBAQA5UFWd5EL/pBviIMm1zD2JLUCpp0mJG7JkwznIOzawhGmFFaxGoxAhQBEg +haP+E0KR66oAwVC6xe32QUVSHfWqWndzbODzLB8yj7WAR0cDM45ZngSBPBuFE3Wu +GLJX9g100ETfIX+4YBR/4NR/uvTnpnd9ete7Whl0ZfY94yuu4xQqB5QFv+P7IXXV +lTOjkjuGXEcyQAjQzbFaT9vIABSbeCXWBbjvOXukJy6WgAiclzGNSYprre8Ryydd +fmjW9HIGwsIO03EldivvqEYL1Hv1w/Pur+6FUEOaL68PEIUovfgwIB2BAw+vZDuw +cH0mX548PojGyg434cDjkSXa3mHF +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEPDCCAySgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvjE/MD0GA1UEAww2VMOc +UktUUlVTVCBFbGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sx +c8SxMQswCQYDVQQGEwJUUjEPMA0GA1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xS +S1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kg +SGl6bWV0bGVyaSBBLsWeLiAoYykgS2FzxLFtIDIwMDUwHhcNMDUxMTA3MTAwNzU3 +WhcNMTUwOTE2MTAwNzU3WjCBvjE/MD0GA1UEAww2VMOcUktUUlVTVCBFbGVrdHJv +bmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJU +UjEPMA0GA1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSw +bGV0acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWe +LiAoYykgS2FzxLFtIDIwMDUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +AQCpNn7DkUNMwxmYCMjHWHtPFoylzkkBH3MOrHUTpvqeLCDe2JAOCtFp0if7qnef +J1Il4std2NiDUBd9irWCPwSOtNXwSadktx4uXyCcUHVPr+G1QRT0mJKIx+XlZEdh +R3n9wFHxwZnn3M5q+6+1ATDcRhzviuyV79z/rxAc653YsKpqhRgNF8k+v/Gb0AmJ +Qv2gQrSdiVFVKc8bcLyEVK3BEx+Y9C52YItdP5qtygy/p1Zbj3e41Z55SZI/4PGX +JHpsmxcPbe9TmJEr5A++WXkHeLuXlfSfadRYhwqp48y2WBmfJiGxxFmNskF1wK1p +zpwACPI2/z7woQ8arBT9pmAPAgMBAAGjQzBBMB0GA1UdDgQWBBTZN7NOBf3Zz58S +Fq62iS/rJTqIHDAPBgNVHQ8BAf8EBQMDBwYAMA8GA1UdEwEB/wQFMAMBAf8wDQYJ +KoZIhvcNAQEFBQADggEBAHJglrfJ3NgpXiOFX7KzLXb7iNcX/nttRbj2hWyfIvwq +ECLsqrkw9qtY1jkQMZkpAL2JZkH7dN6RwRgLn7Vhy506vvWolKMiVW4XSf/SKfE4 +Jl3vpao6+XF75tpYHdN0wgH6PmlYX63LaL4ULptswLbcoCb6dxriJNoaN+BnrdFz +gw2lGh1uEpJ+hGIAF728JRhX8tepb1mIvDS3LoV4nZbcFMMsilKbloxSZj2GFotH +uFEJjOp9zYhys2AzsfAKRO8P9Qk3iCQOLGsgOqL6EfJANZxEaGM7rDNvY7wsu/LS +y3Z9fYjYHcgFHW68lKlmjHdxx/qR+i9Rnuk5UrbnBEI= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDfTCCAmWgAwIBAgIBADANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJKUDEl +MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEqMCgGA1UECxMh +U2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBFViBSb290Q0ExMB4XDTA3MDYwNjAyMTIz +MloXDTM3MDYwNjAyMTIzMlowYDELMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09N +IFRydXN0IFN5c3RlbXMgQ08uLExURC4xKjAoBgNVBAsTIVNlY3VyaXR5IENvbW11 +bmljYXRpb24gRVYgUm9vdENBMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBALx/7FebJOD+nLpCeamIivqA4PUHKUPqjgo0No0c+qe1OXj/l3X3L+SqawSE +RMqm4miO/VVQYg+kcQ7OBzgtQoVQrTyWb4vVog7P3kmJPdZkLjjlHmy1V4qe70gO +zXppFodEtZDkBp2uoQSXWHnvIEqCa4wiv+wfD+mEce3xDuS4GBPMVjZd0ZoeUWs5 +bmB2iDQL87PRsJ3KYeJkHcFGB7hj3R4zZbOOCVVSPbW9/wfrrWFVGCypaZhKqkDF +MxRldAD5kd6vA0jFQFTcD4SQaCDFkpbcLuUCRarAX1T4bepJz11sS6/vmsJWXMY1 +VkJqMF/Cq/biPT+zyRGPMUzXn0kCAwEAAaNCMEAwHQYDVR0OBBYEFDVK9U2vP9eC +OKyrcWUXdYydVZPmMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0G +CSqGSIb3DQEBBQUAA4IBAQCoh+ns+EBnXcPBZsdAS5f8hxOQWsTvoMpfi7ent/HW +tWS3irO4G8za+6xmiEHO6Pzk2x6Ipu0nUBsCMCRGef4Eh3CXQHPRwMFXGZpppSeZ +q51ihPZRwSzJIxXYKLerJRO1RuGGAv8mjMSIkh1W/hln8lXkgKNrnKt34VFxDSDb +EJrbvXZ5B3eZKK2aXtqxT0QsNY6llsf9g/BYxnnWmHyojf6GPgcWkuF75x3sM3Z+ +Qi5KhfmRiWiEA4Glm5q+4zfFVKtWOxgtQaQM+ELbmaDgcm+7XeEWT1MKZPlO9L9O +VL14bIjqv5wTJMJwaaJ/D8g8rQjJsJhAoyrniIPtd490 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICqDCCAi2gAwIBAgIQNBdlEkA7t1aALYDLeVWmHjAKBggqhkjOPQQDAzCBlDEL +MAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYD +VQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBD +bGFzcyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0g +RzQwHhcNMTExMDA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBlDELMAkGA1UEBhMC +VVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZTeW1h +bnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBDbGFzcyAyIFB1 +YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAATR2UqOTA2ESlG6fO/TzPo6mrWnYxM9AeBJPvrBR8mS +szrX/m+c95o6D/UOCgrDP8jnEhSO1dVtmCyzcTIK6yq99tdqIAtnRZzSsr9TImYJ +XdsR8/EFM1ij4rjPfM2Cm72jQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E +BTADAQH/MB0GA1UdDgQWBBQ9MvM6qQyQhPmijGkGYVQvh3L+BTAKBggqhkjOPQQD +AwNpADBmAjEAyKapr0F/tckRQhZoaUxcuCcYtpjxwH+QbYfTjEYX8D5P/OqwCMR6 +S7wIL8fip29lAjEA1lnehs5fDspU1cbQFQ78i5Ry1I4AWFPPfrFLDeVQhuuea9// +KabYR9mglhjb8kWz +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd +MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg +Q2xhc3MgMyBSb290IENBMB4XDTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFow +TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw +HgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB +BQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRHsJ8Y +ZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3E +N3coTRiR5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9 +tznDDgFHmV0ST9tD+leh7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX +0DJq1l1sDPGzbjniazEuOQAnFN44wOwZZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c +/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH2xc519woe2v1n/MuwU8X +KhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV/afmiSTY +zIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvS +O1UQRwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D +34xFMFbG02SrZvPAXpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgP +K9Dx2hzLabjKSWJtyNBjYt1gD1iqj6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3 +AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFEe4zf/lb+74suwv +Tg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAACAj +QTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV +cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXS +IGrs/CIBKM+GuIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2 +HJLw5QY33KbmkJs4j1xrG0aGQ0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsa +O5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8ZORK15FTAaggiG6cX0S5y2CBNOxv +033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2KSb12tjE8nVhz36u +dmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz6MkE +kbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg41 +3OEMXbugUZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvD +u79leNKGef9JOxqDDPDeeOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq +4/g7u9xN12TyUb7mqqta6THuBrxzvxNiCp/HuZc= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIF9jCCA96gAwIBAgIQZWNxhdNvRcaPfzH5CYeSgjANBgkqhkiG9w0BAQwFADCB +lDELMAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8w +HQYDVQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRl +YyBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +IC0gRzYwHhcNMTIxMDE4MDAwMDAwWhcNMzcxMjAxMjM1OTU5WjCBlDELMAkGA1UE +BhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZT +eW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBDbGFzcyAz +IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzYwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC3DrL6TbyachX7d1vb/UMPywv3 +YC6zK34Mu1PyzE5l8xm7/zUd99Opu0Attd141Kb5N+qFBXttt+YTSwZ8+3ZjjyAd +LTgrBIXy6LDRX01KIclq2JTqHgJQpqqQB6BHIepm+QSg5oPwxPVeluInTWHDs8GM +IrZmoQDRVin77cF/JMo9+lqUsITDx7pDHP1kDvEo+0dZ8ibhMblE+avd+76+LDfj +rAsY0/wBovGkCjWCR0yrvYpe3xOF/CDMSFmvr0FvyyPNypOn3dVfyGQ7/wEDoApP +LW49hL6vyDKyUymQFfewBZoKPPa5BpDJpeFdoDuw/qi2v/WJKFckOiGGceTciotB +VeweMCRZ0cBZuHivqlp03iWAMJjtMERvIXAc2xJTDtamKGaTLB/MTzwbgcW59nhv +0DI6CHLbaw5GF4WU87zvvPekXo7p6bVk5bdLRRIsTDe3YEMKTXEGAJQmNXQfu3o5 +XE475rgD4seTi4QsJUlF3X8jlGAfy+nN9quX92Hn+39igcjcCjBcGHzmzu/Hbh6H +fLPpysh7avRo/IOlDFa0urKNSgrHl5fFiDAVPRAIVBVycmczM/R8t84AJ1NlziTx +WmTnNi/yLgLCl99y6AIeoPc9tftoYAP6M6nmEm0G4amoXU48/tnnAGWsthlNe4N/ +NEfq4RhtsYsceavnnQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQUOXEIAD7eyIbnkP/k/SEPziQZFvYwDQYJKoZIhvcN +AQEMBQADggIBAFBriE1gSM5a4yLOZ3yEp80c/ekMA4w2rwqHDmquV64B0Da78v25 +c8FftaiuTKL6ScsHRhY2vePIVzh+OOS/JTNgxtw3nGO7XpgeGrKC8K6mdxGAREeh +KcXwszrOmPC47NMOgAZ3IzBM/3lkYyJbd5NDS3Wz2ztuO0rd8ciutTeKlYg6EGhw +OLlbcH7VQ8n8X0/l5ns27vAg7UdXEyYQXhQGDXt2B8LGLRb0rqdsD7yID08sAraj +1yLmmUc12I2lT4ESOhF9s8wLdfMecKMbA+r6mujmLjY5zJnOOj8Mt674Q5mwk25v +qtkPajGRu5zTtCj7g0x6c4JQZ9IOrO1gxbJdNZjPh34eWR0kvFa62qRa2MzmvB4Q +jxuMjvPB27e+1LBbZY8WaPNWxSoZFk0PuGWHbSSDuGLc4EdhGoh7zk5//dzGDVqa +pPO1TPbdMaboHREhMzAEYX0c4D5PjT+1ixIAWn2poQDUg+twuxj4pNIcgS23CBHI +Jnu21OUPA0Zy1CVAHr5JXW2T8VyyO3VUaTqg7kwiuqya4gitRWMFSlI1dsQ09V4H +Mq3cfCbRW4+t5OaqG3Wf61206MCpFXxOSgdy30bJ1JGSdVaw4e43NmUoxRXIK3bM +bW8Zg/T92hXiQeczeUaDV/nxpbZt07zXU+fucW14qZen7iCcGRVyFT0E +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQsw +CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu +ZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3Qg +RzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu +Y29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJf +Zn4f5dwbRXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17Q +RSAPWXYQ1qAk8C3eNvJsKTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ +BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgFUaFNN6KDec6NHSrkhDAKBggqhkjOPQQD +AwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5FyYZ5eEJJZVrmDxxDnOOlY +JjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy1vUhZscv +6pZjamVFkpUBtA== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEUzCCAzugAwIBAgIDAOJDMA0GCSqGSIb3DQEBBQUAMIHPMQswCQYDVQQGEwJB +VDGBizCBiAYDVQQKHoGAAEEALQBUAHIAdQBzAHQAIABHAGUAcwAuACAAZgD8AHIA +IABTAGkAYwBoAGUAcgBoAGUAaQB0AHMAcwB5AHMAdABlAG0AZQAgAGkAbQAgAGUA +bABlAGsAdAByAC4AIABEAGEAdABlAG4AdgBlAHIAawBlAGgAcgAgAEcAbQBiAEgx +GDAWBgNVBAsTD0EtVHJ1c3QtUXVhbC0wMTEYMBYGA1UEAxMPQS1UcnVzdC1RdWFs +LTAxMB4XDTA0MTEzMDIzMDAwMFoXDTE0MTEzMDIzMDAwMFowgc8xCzAJBgNVBAYT +AkFUMYGLMIGIBgNVBAoegYAAQQAtAFQAcgB1AHMAdAAgAEcAZQBzAC4AIABmAPwA +cgAgAFMAaQBjAGgAZQByAGgAZQBpAHQAcwBzAHkAcwB0AGUAbQBlACAAaQBtACAA +ZQBsAGUAawB0AHIALgAgAEQAYQB0AGUAbgB2AGUAcgBrAGUAaAByACAARwBtAGIA +SDEYMBYGA1UECxMPQS1UcnVzdC1RdWFsLTAxMRgwFgYDVQQDEw9BLVRydXN0LVF1 +YWwtMDEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCmhgdxIbxTGEOH +fXGiewI3NFldAWKFWfLofO+5I1UbvA5avt7IgsGXz/tI/f5HGUbascI0i7xG0tqV +lA5ctQgLRqxgxHtgTkMcqsAEYdsz3LZsCdXO1QrvEBGLTSABdxiL/gSWJ6z77CSw +x7Xg02HwxPV82cjGkSF3ENGJntuIAAnRDWn/ORHjFatNRymoMbHaOEZXSGhf7Y5F +rrHEqGyi9E6sv784De/T1aTvskn8cWeUmDzv//omiG/a/V9KQex/61XN8OthUQVn +X+u/liL2NKx74I2C/GgHX5B0WkPNqsSOgmlvJ/cKuT0PveUgVFDAA0oYBgcE1KDM +lBbN0kmPAgMBAAGjNjA0MA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0OBAoECEs8jB2F +6W+tMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAIUusmJzMJRiQ +8TAHrJAOelfuWoTGcqdIv7Tys/fNl2yF2fjvHT8J01aKialFVpbVeQ2XKb1O2bHO +QYAKgsdZ2jZ/sdL2UVFRTHmidLu6PdgWCBRhJYQELQophO9QVvfhAA0TwbESYqTz ++nlI5Gr7CZe8f6HEmhJmCtUQsdQCufGglRh4T+tIGiNGcnyVEHZ93mSVepFr1VA2 +9CTRPteuGjA81jeAz9peYiFE1CXvxK9cJiv0BcALFLWmADCoRLzIRZhA+sAwYUmw +M1rqVCPA3kBQvIC95tyQvNy2dG0Vs+O6PwLaNX/suSlElQ06X2l1VwMaYb4vZKFq +N0bOhBXEVg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIJmzCCB4OgAwIBAgIBATANBgkqhkiG9w0BAQwFADCCAR4xPjA8BgNVBAMTNUF1 +dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIFJhaXogZGVsIEVzdGFkbyBWZW5lem9s +YW5vMQswCQYDVQQGEwJWRTEQMA4GA1UEBxMHQ2FyYWNhczEZMBcGA1UECBMQRGlz +dHJpdG8gQ2FwaXRhbDE2MDQGA1UEChMtU2lzdGVtYSBOYWNpb25hbCBkZSBDZXJ0 +aWZpY2FjaW9uIEVsZWN0cm9uaWNhMUMwQQYDVQQLEzpTdXBlcmludGVuZGVuY2lh +IGRlIFNlcnZpY2lvcyBkZSBDZXJ0aWZpY2FjaW9uIEVsZWN0cm9uaWNhMSUwIwYJ +KoZIhvcNAQkBFhZhY3JhaXpAc3VzY2VydGUuZ29iLnZlMB4XDTEwMTIyMjE4MDgy +MVoXDTMwMTIxNzIzNTk1OVowggEeMT4wPAYDVQQDEzVBdXRvcmlkYWQgZGUgQ2Vy +dGlmaWNhY2lvbiBSYWl6IGRlbCBFc3RhZG8gVmVuZXpvbGFubzELMAkGA1UEBhMC +VkUxEDAOBgNVBAcTB0NhcmFjYXMxGTAXBgNVBAgTEERpc3RyaXRvIENhcGl0YWwx +NjA0BgNVBAoTLVNpc3RlbWEgTmFjaW9uYWwgZGUgQ2VydGlmaWNhY2lvbiBFbGVj +dHJvbmljYTFDMEEGA1UECxM6U3VwZXJpbnRlbmRlbmNpYSBkZSBTZXJ2aWNpb3Mg +ZGUgQ2VydGlmaWNhY2lvbiBFbGVjdHJvbmljYTElMCMGCSqGSIb3DQEJARYWYWNy +YWl6QHN1c2NlcnRlLmdvYi52ZTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC +ggIBAME77xNS8ZlW47RsBeEaaRZhJoZ4rw785UAFCuPZOAVMqNS1wMYqzy95q6Gk +UO81ER/ugiQX/KMcq/4HBn83fwdYWxPZfwBfK7BP2p/JsFgzYeFP0BXOLmvoJIzl +Jb6FW+1MPwGBjuaZGFImWZsSmGUclb51mRYMZETh9/J5CLThR1exStxHQptwSzra +zNFpkQY/zmj7+YZNA9yDoroVFv6sybYOZ7OxNDo7zkSLo45I7gMwtxqWZ8VkJZkC +8+p0dX6mkhUT0QAV64Zc9HsZiH/oLhEkXjhrgZ28cF73MXIqLx1fyM4kPH1yOJi/ +R72nMwL7D+Sd6mZgI035TxuHXc2/uOwXfKrrTjaJDz8Jp6DdessOkxIgkKXRjP+F +K3ze3n4NUIRGhGRtyvEjK95/2g02t6PeYiYVGur6ruS49n0RAaSS0/LJb6XzaAAe +0mmO2evnEqxIKwy2mZRNPfAVW1l3wCnWiUwryBU6OsbFcFFrQm+00wOicXvOTHBM +aiCVAVZTb9RSLyi+LJ1llzJZO3pq3IRiiBj38Nooo+2ZNbMEciSgmig7YXaUcmud +SVQvLSL+Yw+SqawyezwZuASbp7d/0rutQ59d81zlbMt3J7yB567rT2IqIydQ8qBW +k+fmXzghX+/FidYsh/aK+zZ7Wy68kKHuzEw1Vqkat5DGs+VzAgMBAAGjggLeMIIC +2jASBgNVHRMBAf8ECDAGAQH/AgECMDcGA1UdEgQwMC6CD3N1c2NlcnRlLmdvYi52 +ZaAbBgVghl4CAqASDBBSSUYtRy0yMDAwNDAzNi0wMB0GA1UdDgQWBBStuyIdxuDS +Aaj9dlBSk+2YwU2u0zCCAVAGA1UdIwSCAUcwggFDgBStuyIdxuDSAaj9dlBSk+2Y +wU2u06GCASakggEiMIIBHjE+MDwGA1UEAxM1QXV0b3JpZGFkIGRlIENlcnRpZmlj +YWNpb24gUmFpeiBkZWwgRXN0YWRvIFZlbmV6b2xhbm8xCzAJBgNVBAYTAlZFMRAw +DgYDVQQHEwdDYXJhY2FzMRkwFwYDVQQIExBEaXN0cml0byBDYXBpdGFsMTYwNAYD +VQQKEy1TaXN0ZW1hIE5hY2lvbmFsIGRlIENlcnRpZmljYWNpb24gRWxlY3Ryb25p +Y2ExQzBBBgNVBAsTOlN1cGVyaW50ZW5kZW5jaWEgZGUgU2VydmljaW9zIGRlIENl +cnRpZmljYWNpb24gRWxlY3Ryb25pY2ExJTAjBgkqhkiG9w0BCQEWFmFjcmFpekBz +dXNjZXJ0ZS5nb2IudmWCAQEwDgYDVR0PAQH/BAQDAgEGMDcGA1UdEQQwMC6CD3N1 +c2NlcnRlLmdvYi52ZaAbBgVghl4CAqASDBBSSUYtRy0yMDAwNDAzNi0wMFQGA1Ud +HwRNMEswJKAioCCGHmhodHA6Ly93d3cuc3VzY2VydGUuZ29iLnZlL2xjcjAjoCGg +H4YdbGRhcDovL2FjcmFpei5zdXNjZXJ0ZS5nb2IudmUwNwYIKwYBBQUHAQEEKzAp +MCcGCCsGAQUFBzABhhtoaHRwOi8vb2NzcC5zdXNjZXJ0ZS5nb2IudmUwQAYDVR0g +BDkwNzA1BgVghl4BAjAsMCoGCCsGAQUFBwIBFh5odHRwOi8vd3d3LnN1c2NlcnRl +LmdvYi52ZS9kcGMwDQYJKoZIhvcNAQEMBQADggIBAK4qy/zmZ9zBwfW3yOYtLcBT +Oy4szJyPz7/RhNH3bPVH7HbDTGpi6JZ4YXdXMBeJE5qBF4a590Kgj8Rlnltt+Rbo +OFQOU1UDqKuTdBsA//Zry5899fmn8jBUkg4nh09jhHHbLlaUScdz704Zz2+UVg7i +s/r3Legxap60KzmdrmTAE9VKte1TQRgavQwVX5/2mO/J+SCas//UngI+h8SyOucq +mjudYEgBrZaodUsagUfn/+AzFNrGLy+al+5nZeHb8JnCfLHWS0M9ZyhgoeO/czyn +99+5G93VWNv4zfc4KiavHZKrkn8F9pg0ycIZh+OwPT/RE2zq4gTazBMlP3ACIe/p +olkNaOEa8KvgzW96sjBZpMW49zFmyINYkcj+uaNCJrVGsXgdBmkuRGJNWFZ9r0cG +woIaxViFBypsz045r1ESfYPlfDOavBhZ/giR/Xocm9CHkPRY2BApMMR0DUCyGETg +Ql+L3kfdTKzuDjUp2DM9FqysQmaM81YDZufWkMhlZPfHwC7KbNougoLroa5Umeos +bqAXWmk46SwIdWRPLLqbUpDTKooynZKpSYIkkotdgJoVZUUCY+RCO8jsVPEU6ece +SxztNUm5UOta1OJPMwSAKRHOo3ilVb9c6lAixDdvV8MeNbqe6asM1mpCHWbJ/0rg +5Ls9Cxx8hracyp0ev7b0 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIGATCCA+mgAwIBAgIRAI9hcRW6eVgXjH0ROqzW264wDQYJKoZIhvcNAQELBQAw +RTEfMB0GA1UEAxMWQ29tU2lnbiBHbG9iYWwgUm9vdCBDQTEVMBMGA1UEChMMQ29t +U2lnbiBMdGQuMQswCQYDVQQGEwJJTDAeFw0xMTA3MTgxMDI0NTRaFw0zNjA3MTYx +MDI0NTVaMEUxHzAdBgNVBAMTFkNvbVNpZ24gR2xvYmFsIFJvb3QgQ0ExFTATBgNV +BAoTDENvbVNpZ24gTHRkLjELMAkGA1UEBhMCSUwwggIiMA0GCSqGSIb3DQEBAQUA +A4ICDwAwggIKAoICAQCyKClzKh3rm6n1nvigmV/VU1D4hSwYW2ro3VqpzpPo0Ph3 +3LguqjXd5juDwN4mpxTpD99d7Xu5X6KGTlMVtfN+bTbA4t3x7DU0Zqn0BE5XuOgs +3GLH41Vmr5wox1bShVpM+IsjcN4E/hMnDtt/Bkb5s33xCG+ohz5dlq0gA9qfr/g4 +O9lkHZXTCeYrmVzd/il4x79CqNvGkdL3um+OKYl8rg1dPtD8UsytMaDgBAopKR+W +igc16QJzCbvcinlETlrzP/Ny76BWPnAQgaYBULax/Q5thVU+N3sEOKp6uviTdD+X +O6i96gARU4H0xxPFI75PK/YdHrHjfjQevXl4J37FJfPMSHAbgPBhHC+qn/014DOx +46fEGXcdw2BFeIIIwbj2GH70VyJWmuk/xLMCHHpJ/nIF8w25BQtkPpkwESL6esaU +b1CyB4Vgjyf16/0nRiCAKAyC/DY/Yh+rDWtXK8c6QkXD2XamrVJo43DVNFqGZzbf +5bsUXqiVDOz71AxqqK+p4ek9374xPNMJ2rB5MLPAPycwI0bUuLHhLy6nAIFHLhut +TNI+6Y/soYpi5JSaEjcY7pxI8WIkUAzr2r+6UoT0vAdyOt7nt1y8844a7szo/aKf +woziHl2O1w6ZXUC30K+ptXVaOiW79pBDcbLZ9ZdbONhS7Ea3iH4HJNwktrBJLQID +AQABo4HrMIHoMA8GA1UdEwEB/wQFMAMBAf8wgYQGA1UdHwR9MHswPKA6oDiGNmh0 +dHA6Ly9mZWRpci5jb21zaWduLmNvLmlsL2NybC9jb21zaWduZ2xvYmFscm9vdGNh +LmNybDA7oDmgN4Y1aHR0cDovL2NybDEuY29tc2lnbi5jby5pbC9jcmwvY29tc2ln +bmdsb2JhbHJvb3RjYS5jcmwwDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBQCRZPY +DUhirGm6rgZbPvuqJpFQsTAfBgNVHSMEGDAWgBQCRZPYDUhirGm6rgZbPvuqJpFQ +sTANBgkqhkiG9w0BAQsFAAOCAgEAk1V5V9701xsfy4mfX+tP9Ln5e9h3N+QMwUfj +kr+k3e8iXOqADjTpUHeBkEee5tJq09ZLp/43F5tZ2eHdYq2ZEX7iWHCnOQet6Yw9 +SU1TahsrGDA6JJD9sdPFnNZooGsU1520e0zNB0dNWwxrWAmu4RsBxvEpWCJbvzQL +dOfyX85RWwli81OiVMBc5XvJ1mxsIIqli45oRynKtsWP7E+b0ISJ1n+XFLdQo/Nm +WA/5sDfT0F5YPzWdZymudMbXitimxC+n4oQE4mbQ4Zm718Iwg3pP9gMMcSc7Qc1J +kJHPH9O7gVubkKHuSYj9T3Ym6c6egL1pb4pz/uT7cT26Fiopc/jdqbe2EAfoJZkv +hlp/zdzOoXTWjiKNA5zmgWnZn943FuE9KMRyKtyi/ezJXCh8ypnqLIKxeFfZl69C +BwJsPXUTuqj8Fic0s3aZmmr7C4jXycP+Q8V+akMEIoHAxcd960b4wVWKqOcI/kZS +Q0cYqWOY1LNjznRt9lweWEfwDBL3FhrHOmD4++1N3FkkM4W+Q1b2WOL24clDMj+i +2n9Iw0lc1llHMSMvA5D0vpsXZpOgcCVahfXczQKi9wQ3oZyonJeWx4/rXdMtagAB +VBYGFuMEUEQtybI+eIbnp5peO2WAAblQI4eTy/jMVowe5tfMEXovV3sz9ULgmGb3 +DscLP1I= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICmDCCAgGgAwIBAgIBDjANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJVUzEY +MBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNFQ0ExFDASBgNVBAMT +C0VDQSBSb290IENBMB4XDTA0MDYxNDEwMjAwOVoXDTQwMDYxNDEwMjAwOVowSzEL +MAkGA1UEBhMCVVMxGDAWBgNVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMD +RUNBMRQwEgYDVQQDEwtFQ0EgUm9vdCBDQTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw +gYkCgYEArkr2eXIS6oAKIpDkOlcQZdMGdncoygCEIU+ktqY3of5SVVXU7/it7kJ1 +EUzR4ii2vthQtbww9aAnpQxcEmXZk8eEyiGEPy+cCQMllBY+efOtKgjbQNDZ3lB9 +19qzUJwBl2BMxslU1XsJQw9SK10lPbQm4asa8E8e5zTUknZBWnECAwEAAaOBizCB +iDAfBgNVHSMEGDAWgBT2uAQnDlYW2blj2f2hVGVBoAhILzAdBgNVHQ4EFgQU9rgE +Jw5WFtm5Y9n9oVRlQaAISC8wDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMB +Af8wJQYDVR0gBB4wHDAMBgpghkgBZQMCAQwBMAwGCmCGSAFlAwIBDAIwDQYJKoZI +hvcNAQEFBQADgYEAHh0EQY2cZ209aBb5q0wW1ER0dc4OGzsLyqjHfaQ4TEaMmUwL +AJRta/c4KVWLiwbODsvgJk+CaWmSL03gRW/ciVb/qDV7qh9Pyd1cOlanZTAnPog2 +i82yL3i2fK9DCC84uoxEQbgqK2jx9bIjFTwlAqITk9fGAm5mdT84IEwq1Gw= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH +MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI +2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx +1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ +q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz +tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ +vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP +BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV +5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY +1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4 +NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG +Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91 +8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe +pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl +MrY= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFSzCCAzOgAwIBAgIRALZLiAfiI+7IXBKtpg4GofIwDQYJKoZIhvcNAQELBQAw +PzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dvdmVybm1lbnQgUm9vdCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eTAeFw0xMjA5MjgwODU4NTFaFw0zNzEyMzExNTU5NTla +MD8xCzAJBgNVBAYTAlRXMTAwLgYDVQQKDCdHb3Zlcm5tZW50IFJvb3QgQ2VydGlm +aWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC +AQC2/5c8gb4BWCQnr44BK9ZykjAyG1+bfNTUf+ihYHMwVxAA+lCWJP5Q5ow6ldFX +eYTVZ1MMKoI+GFy4MCYa1l7GLbIEUQ7v3wxjR+vEEghRK5lxXtVpe+FdyXcdIOxW +juVhYC386RyA3/pqg7sFtR4jEpyCygrzFB0g5AaPQySZn7YKk1pzGxY5vgW28Yyl +ZJKPBeRcdvc5w88tvQ7Yy6gOMZvJRg9nU0MEj8iyyIOAX7ryD6uBNaIgIZfOD4k0 +eA/PH07p+4woPN405+2f0mb1xcoxeNLOUNFggmOd4Ez3B66DNJ1JSUPUfr0t4urH +cWWACOQ2nnlwCjyHKenkkpTqBpIpJ3jmrdc96QoLXvTg1oadLXLLi2RW5vSueKWg +OTNYPNyoj420ai39iHPplVBzBN8RiD5C1gJ0+yzEb7xs1uCAb9GGpTJXA9ZN9E4K +mSJ2fkpAgvjJ5E7LUy3Hsbbi08J1J265DnGyNPy/HE7CPfg26QrMWJqhGIZO4uGq +s3NZbl6dtMIIr69c/aQCb/+4DbvVq9dunxpPkUDwH0ZVbaCSw4nNt7H/HLPLo5wK +4/7NqrwB7N1UypHdTxOHpPaY7/1J1lcqPKZc9mA3v9g+fk5oKiMyOr5u5CI9ByTP +isubXVGzMNJxbc5Gim18SjNE2hIvNkvy6fFRCW3bapcOFwIDAQABo0IwQDAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBTVZx3gnHosnMvFmOcdByYqhux0zTAOBgNV +HQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggIBAJA75cJTQijq9TFOjj2Rnk0J +89ixUuZPrAwxIbvx6pnMg/y2KOTshAcOD06Xu29oRo8OURWV+Do7H1+CDgxxDryR +T64zLiNB9CZrTxOH+nj2LsIPkQWXqmrBap+8hJ4IKifd2ocXhuGzyl3tOKkpboTe +Rmv8JxlQpRJ6jH1i/NrnzLyfSa8GuCcn8on3Fj0Y5r3e9YwSkZ/jBI3+BxQaWqw5 +ghvxOBnhY+OvbLamURfr+kvriyL2l/4QOl+UoEtTcT9a4RD4co+WgN2NApgAYT2N +vC2xR8zaXeEgp4wxXPHj2rkKhkfIoT0Hozymc26Uke1uJDr5yTDRB6iBfSZ9fYTf +hsmL5a4NHr6JSFEVg5iWL0rrczTXdM3Jb9DCuiv2mv6Z3WAUjhv5nDk8f0OJU+jl +wqu+Iq0nOJt3KLejY2OngeepaUXrjnhWzAWEx/uttjB8YwWfLYwkf0uLkvw4Hp+g +pVezbp3YZLhwmmBScMip0P/GnO0QYV7Ngw5u6E0CQUridgR51lQ/ipgyFKDdLZzn +uoJxo4ZVKZnSKdt1OvfbQ/+2W/u3fjWAjg1srnm3Ni2XUqGwB5wH5Ss2zQOXlL0t +DjQG/MAWifw3VOTWzz0TBPKR2ck2Lj7FWtClTILD/y58Jnb38/1FoqVuVa4uzM8s +iTTa9g3nkagQ6hed8vbs +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMC +VVMxFDASBgNVBAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQ +cmVtaXVtIEVDQzAeFw0xMDAxMjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJ +BgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1UcnVzdDEgMB4GA1UEAwwXQWZmaXJt +VHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNMF4bFZ0D +0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQN8O9 +ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0G +A1UdDgQWBBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4G +A1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/Vs +aobgxCd05DhT1wV/GzTjxi+zygk8N53X57hG8f2h4nECMEJZh0PUUd+60wkyWs6I +flc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKMeQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd +MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg +Q2xhc3MgMiBSb290IENBMB4XDTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1ow +TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw +HgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB +BQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1g1Lr +6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPV +L4O2fuPn9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC91 +1K2GScuVr1QGbNgGE41b/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHx +MlAQTn/0hpPshNOOvEu/XAFOBz3cFIqUCqTqc/sLUegTBxj6DvEr0VQVfTzh97QZ +QmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeffawrbD02TTqigzXsu8lkB +arcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgIzRFo1clr +Us3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLi +FRhnBkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRS +P/TizPJhk9H9Z2vXUq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN +9SG9dKpN6nIDSdvHXx1iY8f93ZHsM+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxP +AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMmAd+BikoL1Rpzz +uvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAU18h +9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s +A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3t +OluwlN5E40EIosHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo ++fsicdl9sz1Gv7SEr5AcD48Saq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7 +KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYdDnkM/crqJIByw5c/8nerQyIKx+u2 +DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWDLfJ6v9r9jv6ly0Us +H8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0oyLQ +I+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK7 +5t98biGCwWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h +3PFaTWwyI0PurKju7koSCTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPz +Y11aWOIv4x3kqdbQCtCev9eBCfHJxyYNrJgWVqA= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFaTCCA1GgAwIBAgIJAMMDmu5QkG4oMA0GCSqGSIb3DQEBBQUAMFIxCzAJBgNV +BAYTAlNLMRMwEQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMu +MRkwFwYDVQQDExBDQSBEaXNpZyBSb290IFIxMB4XDTEyMDcxOTA5MDY1NloXDTQy +MDcxOTA5MDY1NlowUjELMAkGA1UEBhMCU0sxEzARBgNVBAcTCkJyYXRpc2xhdmEx +EzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERpc2lnIFJvb3QgUjEw +ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCqw3j33Jijp1pedxiy3QRk +D2P9m5YJgNXoqqXinCaUOuiZc4yd39ffg/N4T0Dhf9Kn0uXKE5Pn7cZ3Xza1lK/o +OI7bm+V8u8yN63Vz4STN5qctGS7Y1oprFOsIYgrY3LMATcMjfF9DCCMyEtztDK3A +fQ+lekLZWnDZv6fXARz2m6uOt0qGeKAeVjGu74IKgEH3G8muqzIm1Cxr7X1r5OJe +IgpFy4QxTaz+29FHuvlglzmxZcfe+5nkCiKxLU3lSCZpq+Kq8/v8kiky6bM+TR8n +oc2OuRf7JT7JbvN32g0S9l3HuzYQ1VTW8+DiR0jm3hTaYVKvJrT1cU/J19IG32PK +/yHoWQbgCNWEFVP3Q+V8xaCJmGtzxmjOZd69fwX3se72V6FglcXM6pM6vpmumwKj +rckWtc7dXpl4fho5frLABaTAgqWjR56M6ly2vGfb5ipN0gTco65F97yLnByn1tUD +3AjLLhbKXEAz6GfDLuemROoRRRw1ZS0eRWEkG4IupZ0zXWX4Qfkuy5Q/H6MMMSRE +7cderVC6xkGbrPAXZcD4XW9boAo0PO7X6oifmPmvTiT6l7Jkdtqr9O3jw2Dv1fkC +yC2fg69naQanMVXVz0tv/wQFx1isXxYb5dKj6zHbHzMVTdDypVP1y+E9Tmgt2BLd +qvLmTZtJ5cUoobqwWsagtQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud +DwEB/wQEAwIBBjAdBgNVHQ4EFgQUiQq0OJMa5qvum5EY+fU8PjXQ04IwDQYJKoZI +hvcNAQEFBQADggIBADKL9p1Kyb4U5YysOMo6CdQbzoaz3evUuii+Eq5FLAR0rBNR +xVgYZk2C2tXck8An4b58n1KeElb21Zyp9HWc+jcSjxyT7Ff+Bw+r1RL3D65hXlaA +SfX8MPWbTx9BLxyE04nH4toCdu0Jz2zBuByDHBb6lM19oMgY0sidbvW9adRtPTXo +HqJPYNcHKfyyo6SdbhWSVhlMCrDpfNIZTUJG7L399ldb3Zh+pE3McgODWF3vkzpB +emOqfDqo9ayk0d2iLbYq/J8BjuIQscTK5GfbVSUZP/3oNn6z4eGBrxEWi1CXYBmC +AMBrTXO40RMHPuq2MU/wQppt4hF05ZSsjYSVPCGvxdpHyN85YmLLW1AL14FABZyb +7bq2ix4Eb5YgOe2kfSnbSM6C3NQCjR0EMVrHS/BsYVLXtFHCgWzN4funodKSds+x +DzdYpPJScWc/DIh4gInByLUfkmO+p3qKViwaqKactV2zY9ATIKHrkWzQjX2v3wvk +F7mGnjixlAxYjOBVqjtjbZqJYLhkKpLGN/R+Q0O3c+gB53+XD9fyexn9GtePyfqF +a3qdnom2piiZk4hA9z7NUaPK6u95RyG1/jLix8NRb76AdPCkwzryT+lf3xkK8jsT +Q6wxpLPn6/wY1gGp8yqPNg7rtLG8t0zJa7+h89n07eLw4+1knj0vllJPgFOL +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIID9jCCAt6gAwIBAgIQJDJ18h0v0gkz97RqytDzmDANBgkqhkiG9w0BAQsFADCB +lDELMAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8w +HQYDVQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRl +YyBDbGFzcyAxIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +IC0gRzYwHhcNMTExMDE4MDAwMDAwWhcNMzcxMjAxMjM1OTU5WjCBlDELMAkGA1UE +BhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZT +eW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBDbGFzcyAx +IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzYwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDHOddJZKmZgiJM6kXZBxbje/SD +6Jlz+muxNuCad6BAwoGNAcfMjL2Pffd543pMA03Z+/2HOCgs3ZqLVAjbZ/sbjP4o +ki++t7JIp4Gh2F6Iw8w5QEFa0dzl2hCfL9oBTf0uRnz5LicKaTfukaMbasxEvxvH +w9QRslBglwm9LiL1QYRmn81ApqkAgMEflZKf3vNI79sdd2H8f9/ulqRy0LY+/3gn +r8uSFWkI22MQ4uaXrG7crPaizh5HmbmJtxLmodTNWRFnw2+F2EJOKL5ZVVkElauP +N4C/DfD8HzpkMViBeNfiNfYgPym4jxZuPkjctUwH4fIa6n4KedaovetdhitNAgMB +AAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW +BBQzQejIORIVk0jyljIuWvXalF9TYDANBgkqhkiG9w0BAQsFAAOCAQEAFeNzV7EX +tl9JaUSm9l56Z6zS3nVJq/4lVcc6yUQVEG6/MWvL2QeTfxyFYwDjMhLgzMv7OWyP +4lPiPEAz2aSMR+atWPuJr+PehilWNCxFuBL6RIluLRQlKCQBZdbqUqwFblYSCT3Q +dPTXvQbKqDqNVkL6jXI+dPEDct+HG14OelWWLDi3mIXNTTNEyZSPWjEwN0ujOhKz +5zbRIWhLLTjmU64cJVYIVgNnhJ3Gw84kYsdMNs+wBkS39V8C3dlU6S+QTnrIToNA +DJqXPDe/v+z28LSFdyjBC8hnghAXOKK3Buqbvzr46SMHv3TgmDgVVXjucgBcGaP0 +0jPg/73RVDkpDw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNV +BAYTAlNLMRMwEQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMu +MRkwFwYDVQQDExBDQSBEaXNpZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQy +MDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sxEzARBgNVBAcTCkJyYXRpc2xhdmEx +EzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERpc2lnIFJvb3QgUjIw +ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbCw3Oe +NcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNH +PWSb6WiaxswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3I +x2ymrdMxp7zo5eFm1tL7A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbe +QTg06ov80egEFGEtQX6sx3dOy1FU+16SGBsEWmjGycT6txOgmLcRK7fWV8x8nhfR +yyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqVg8NTEQxzHQuyRpDRQjrO +QG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa5Beny912 +H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJ +QfYEkoopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUD +i/ZnWejBBhG93c+AAk9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORs +nLMOPReisjQS1n6yqEm70XooQL6iFh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1 +rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud +DwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5uQu0wDQYJKoZI +hvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM +tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqf +GopTpti72TVVsRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkb +lvdhuDvEK7Z4bLQjb/D907JedR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka ++elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W81k/BfDxujRNt+3vrMNDcTa/F1bal +TFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjxmHHEt38OFdAlab0i +nSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01utI3 +gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18Dr +G5gPcFw0sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3Os +zMOl6W8KjptlwlCFtaOgUxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8x +L4ysEr3vQCj8KWefshNPZiTEUxnpHikV7+ZtsH8tZ/3zbBt1RqPlShfppNcL +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh +MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE +YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3 +MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo +ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg +MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN +ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA +PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w +wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi +EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY +avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+ +YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE +sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h +/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5 +IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD +ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy +OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P +TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ +HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER +dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf +ReYNnyicsbkqWletNw+vHX/bvZ8= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEGjCCAwKgAwIBAgIDAYagMA0GCSqGSIb3DQEBBQUAMIGjMQswCQYDVQQGEwJG +STEQMA4GA1UECBMHRmlubGFuZDEhMB8GA1UEChMYVmFlc3RvcmVraXN0ZXJpa2Vz +a3VzIENBMSkwJwYDVQQLEyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBTZXJ2aWNl +czEZMBcGA1UECxMQVmFybWVubmVwYWx2ZWx1dDEZMBcGA1UEAxMQVlJLIEdvdi4g +Um9vdCBDQTAeFw0wMjEyMTgxMzUzMDBaFw0yMzEyMTgxMzUxMDhaMIGjMQswCQYD +VQQGEwJGSTEQMA4GA1UECBMHRmlubGFuZDEhMB8GA1UEChMYVmFlc3RvcmVraXN0 +ZXJpa2Vza3VzIENBMSkwJwYDVQQLEyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBT +ZXJ2aWNlczEZMBcGA1UECxMQVmFybWVubmVwYWx2ZWx1dDEZMBcGA1UEAxMQVlJL +IEdvdi4gUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALCF +FdrIAzfQo0Y3bBseljDCWoUSZyPyu5/nioFgJ/gTqTy894aqqvTzJSm0/nWuHoGG +igWyHWWyOOi0zCia+xc28ZPVec7Bg4shT8MNrUHfeJ1I4x9CRPw8bSEga60ihCRC +jxdNwlAfZM0tOSJWiP2yY51U2kJpwMhP1xjiPshphJQ9LIDGfM6911Mf64i5psu7 +hVfvV3ZdDIvTXhJBnyHAOfQmbQj6OLOhd7HuFtjQaNq0mKWgZUZKa41+qk1guPjI +DfxxPu45h4G02fhukO4/DmHXHSto5i7hQkQmeCxY8n0Wf2HASSQqiYe2XS8pGfim +545SnkFLWg6quMJmQlMCAwEAAaNVMFMwDwYDVR0TAQH/BAUwAwEB/zARBglghkgB +hvhCAQEEBAMCAAcwDgYDVR0PAQH/BAQDAgHGMB0GA1UdDgQWBBTb6eGb0tEkC/yr +46Bn6q6cS3f0sDANBgkqhkiG9w0BAQUFAAOCAQEArX1ID1QRnljurw2bEi8hpM2b +uoRH5sklVSPj3xhYKizbXvfNVPVRJHtiZ+GxH0mvNNDrsczZog1Sf0JLiGCXzyVy +t08pLWKfT6HAVVdWDsRol5EfnGTCKTIB6dTI2riBmCguGMcs/OubUpbf9MiQGS0j +8/G7cdqehSO9Gu8u5Hp5t8OdhkktY7ktdM9lDzJmid87Ie4pbzlj2RXBbvbfgD5Q +eBmK3QOjFKU3p7UsfLYRh+cF8ry23tT/l4EohP7+bEaFEEGfTXWMB9SZZ291im/k +UJL2mdUQuMSpe/cXjUu/15WfCdxEDx4yw8DP03kN5Mc7h/CQNIghYkmSBAQfvA== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDujCCAqKgAwIBAgIEAJiWijANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJO +TDEeMBwGA1UEChMVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSYwJAYDVQQDEx1TdGFh +dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQTAeFw0wMjEyMTcwOTIzNDlaFw0xNTEy +MTYwOTE1MzhaMFUxCzAJBgNVBAYTAk5MMR4wHAYDVQQKExVTdGFhdCBkZXIgTmVk +ZXJsYW5kZW4xJjAkBgNVBAMTHVN0YWF0IGRlciBOZWRlcmxhbmRlbiBSb290IENB +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmNK1URF6gaYUmHFtvszn +ExvWJw56s2oYHLZhWtVhCb/ekBPHZ+7d89rFDBKeNVU+LCeIQGv33N0iYfXCxw71 +9tV2U02PjLwYdjeFnejKScfST5gTCaI+Ioicf9byEGW07l8Y1Rfj+MX94p2i71MO +hXeiD+EwR+4A5zN9RGcaC1Hoi6CeUJhoNFIfLm0B8mBF8jHrqTFoKbt6QZ7GGX+U +tFE5A3+y3qcym7RHjm+0Sq7lr7HcsBthvJly3uSJt3omXdozSVtSnA71iq3DuD3o +BmrC1SoLbHuEvVYFy4ZlkuxEK7COudxwC0barbxjiDn622r+I/q85Ej0ZytqERAh +SQIDAQABo4GRMIGOMAwGA1UdEwQFMAMBAf8wTwYDVR0gBEgwRjBEBgRVHSAAMDww +OgYIKwYBBQUHAgEWLmh0dHA6Ly93d3cucGtpb3ZlcmhlaWQubmwvcG9saWNpZXMv +cm9vdC1wb2xpY3kwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSofeu8Y6R0E3QA +7Jbg0zTBLL9s+DANBgkqhkiG9w0BAQUFAAOCAQEABYSHVXQ2YcG70dTGFagTtJ+k +/rvuFbQvBgwp8qiSpGEN/KtcCFtREytNwiphyPgJWPwtArI5fZlmgb9uXJVFIGzm +eafR2Bwp/MIgJ1HI8XxdNGdphREwxgDS1/PTfLbwMVcoEoJz6TMvplW0C5GUR5z6 +u3pCMuiufi3IvKwUv9kP2Vv8wfl6leF9fpb8cbDCTMjfRTTJzg3ynGQI0DvDKcWy +7ZAEwbEpkcUwb8GpcjPM/l0WFywRaed+/sWDCN+83CI6LiBpIzlWYGeQiy52OfsR +iJf2fL1LuCAWZwWN4jvBcj+UlTfHXbme2JOhF4//DGYVwSR8MnwDHTuhWEUykw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDEl +MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMe +U2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoX +DTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRy +dXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3VyaXR5IENvbW11bmlj +YXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANAV +OVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGr +zbl+dp+++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVM +VAX3NuRFg3sUZdbcDE3R3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQ +hNBqyjoGADdH5H5XTz+L62e4iKrFvlNVspHEfbmwhRkGeC7bYRr6hfVKkaHnFtWO +ojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1KEOtOghY6rCcMU/Gt1SSw +awNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8QIH4D5cs +OPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3 +DQEBCwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpF +coJxDjrSzG+ntKEju/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXc +okgfGT+Ok+vx+hfuzU7jBBJV1uXk3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8 +t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6qtnRGEmyR7jTV7JqR50S+kDFy +1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29mvVXIwAHIRc/ +SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJTRTEU +MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3 +b3JrMSMwIQYDVQQDExpBZGRUcnVzdCBRdWFsaWZpZWQgQ0EgUm9vdDAeFw0wMDA1 +MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcxCzAJBgNVBAYTAlNFMRQwEgYDVQQK +EwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5ldHdvcmsxIzAh +BgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBSb290MIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoekn0e+EV+vhDTbYjx5eLfpMLXsDBwq +xBb/4Oxx64r1EW7tTw2R0hIYLUkVAcKkIhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G +87B4pfYOQnrjfxvM0PC3KP0q6p6zsLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i +2O+tCBGaKZnhqkRFmhJePp1tUvznoD1oL/BLcHwTOK28FSXx1s6rosAx1i+f4P8U +WfyEk9mHfExUE+uf0S0R+Bg6Ot4l2ffTQO2kBhLEO+GRwVY18BTcZTYJbqukB8c1 +0cIDMzZbdSZtQvESa0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HUMIHRMB0G +A1UdDgQWBBQ5lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0T +AQH/BAUwAwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6Fr +pGkwZzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQL +ExRBZGRUcnVzdCBUVFAgTmV0d29yazEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVhbGlm +aWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBABmrder4i2VhlRO6aQTv +hsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxGGuoYQ992zPlm +hpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx95dr6h+sNNVJn0J6X +dgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKFYqa0p9m9N5xotS1WfbC3 +P6CxB9bpT9zeRXEwMn8bLgn5v1Kh7sKAPgZcLlVAwRv1cEWw3F369nJad9Jjzc9Y +iQBCYz95OdBEsIJuQRno3eDBiFrRHnGTHyQwdOUeqN48Jzd/g66ed8/wMLH/S5no +xqE= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEXDCCA0SgAwIBAgIEOGO5ZjANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML +RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp +bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5 +IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0xOTEy +MjQxODIwNTFaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3 +LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp +YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG +A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq +K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe +sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX +MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT +XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/ +HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH +4QIDAQABo3QwcjARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUVeSB0RGA +vtiJuQijMfmhJAkWuXAwHQYDVR0OBBYEFFXkgdERgL7YibkIozH5oSQJFrlwMB0G +CSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEA +WUesIYSKF8mciVMeuoCFGsY8Tj6xnLZ8xpJdGGQC49MGCBFhfGPjK50xA3B20qMo +oPS7mmNz7W3lKtvtFKkrxjYR0CvrB4ul2p5cGZ1WEvVUKcgF7bISKo30Axv/55IQ +h7A6tcOdBTcSo8f0FbnVpDkWm1M6I5HxqIKiaohowXkCIryqptau37AUX7iH0N18 +f3v/rxzP5tsHrV7bhZ3QKw0z2wTR5klAEyt2+z7pnIkPFc4YsIV4IU9rTw76NmfN +B/L/CNDi3tm/Kq+4h4YhPATKt5Rof8886ZjXOP/swNlQ8C5LWK5Gb9Auw2DaclVy +vUxFnmG6v4SBkgPR0ml8xQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFkjCCA3qgAwIBAgIIAeDltYNno+AwDQYJKoZIhvcNAQEMBQAwZzEbMBkGA1UE +AwwSQXBwbGUgUm9vdCBDQSAtIEcyMSYwJAYDVQQLDB1BcHBsZSBDZXJ0aWZpY2F0 +aW9uIEF1dGhvcml0eTETMBEGA1UECgwKQXBwbGUgSW5jLjELMAkGA1UEBhMCVVMw +HhcNMTQwNDMwMTgxMDA5WhcNMzkwNDMwMTgxMDA5WjBnMRswGQYDVQQDDBJBcHBs +ZSBSb290IENBIC0gRzIxJjAkBgNVBAsMHUFwcGxlIENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MRMwEQYDVQQKDApBcHBsZSBJbmMuMQswCQYDVQQGEwJVUzCCAiIwDQYJ +KoZIhvcNAQEBBQADggIPADCCAgoCggIBANgREkhI2imKScUcx+xuM23+TfvgHN6s +XuI2pyT5f1BrTM65MFQn5bPW7SXmMLYFN14UIhHF6Kob0vuy0gmVOKTvKkmMXT5x +ZgM4+xb1hYjkWpIMBDLyyED7Ul+f9sDx47pFoFDVEovy3d6RhiPw9bZyLgHaC/Yu +OQhfGaFjQQscp5TBhsRTL3b2CtcM0YM/GlMZ81fVJ3/8E7j4ko380yhDPLVoACVd +J2LT3VXdRCCQgzWTxb+4Gftr49wIQuavbfqeQMpOhYV4SbHXw8EwOTKrfl+q04tv +ny0aIWhwZ7Oj8ZhBbZF8+NfbqOdfIRqMM78xdLe40fTgIvS/cjTf94FNcX1RoeKz +8NMoFnNvzcytN31O661A4T+B/fc9Cj6i8b0xlilZ3MIZgIxbdMYs0xBTJh0UT8TU +gWY8h2czJxQI6bR3hDRSj4n4aJgXv8O7qhOTH11UL6jHfPsNFL4VPSQ08prcdUFm +IrQB1guvkJ4M6mL4m1k8COKWNORj3rw31OsMiANDC1CvoDTdUE0V+1ok2Az6DGOe +HwOx4e7hqkP0ZmUoNwIx7wHHHtHMn23KVDpA287PT0aLSmWaasZobNfMmRtHsHLD +d4/E92GcdB/O/WuhwpyUgquUoue9G7q5cDmVF8Up8zlYNPXEpMZ7YLlmQ1A/bmH8 +DvmGqmAMQ0uVAgMBAAGjQjBAMB0GA1UdDgQWBBTEmRNsGAPCe8CjoA1/coB6HHcm +jTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQwF +AAOCAgEAUabz4vS4PZO/Lc4Pu1vhVRROTtHlznldgX/+tvCHM/jvlOV+3Gp5pxy+ +8JS3ptEwnMgNCnWefZKVfhidfsJxaXwU6s+DDuQUQp50DhDNqxq6EWGBeNjxtUVA +eKuowM77fWM3aPbn+6/Gw0vsHzYmE1SGlHKy6gLti23kDKaQwFd1z4xCfVzmMX3z +ybKSaUYOiPjjLUKyOKimGY3xn83uamW8GrAlvacp/fQ+onVJv57byfenHmOZ4VxG +/5IFjPoeIPmGlFYl5bRXOJ3riGQUIUkhOb9iZqmxospvPyFgxYnURTbImHy99v6Z +SYA7LNKmp4gDBDEZt7Y6YUX6yfIjyGNzv1aJMbDZfGKnexWoiIqrOEDCzBL/FePw +N983csvMmOa/orz6JopxVtfnJBtIRD6e/J/JzBrsQzwBvDR4yGn1xuZW7AYJNpDr +FEobXsmII9oDMJELuDY++ee1KG++P+w8j2Ud5cAeh6Squpj9kuNsJnfdBrRkBof0 +Tta6SqoWqPQFZ2aWuuJVecMsXUmPgEkrihLHdoBR37q9ZV0+N0djMenl9MU/S60E +inpxLK8JQzcPqOMyT/RFtm2XNuyE9QoB6he7hY1Ck3DDUOUUi78/w0EP3SIEIwiK +um1xRKtzCTrJ+VKACd+66eYWyi4uTLLT3OUEVLLUNIAytbwPF+E= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDtDCCApygAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJKUDEc +MBoGA1UEChMTSmFwYW5lc2UgR292ZXJubWVudDEOMAwGA1UECxMFTVBIUFQxJjAk +BgNVBAsTHU1QSFBUIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTAyMDMxNDA3 +NTAyNloXDTEyMDMxMzE0NTk1OVowYzELMAkGA1UEBhMCSlAxHDAaBgNVBAoTE0ph +cGFuZXNlIEdvdmVybm1lbnQxDjAMBgNVBAsTBU1QSFBUMSYwJAYDVQQLEx1NUEhQ +VCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAI3GUWlK9G9FVm8DhpKu5t37oxZbj6lZcFvEZY07YrYojWO657ub +z56WE7q/PI/6Sm7i7qYE+Vp80r6thJvfmn7SS3BENrRqiapSenhooYD12jIe3iZQ +2SXqx7WgYwyBGdQwGaYTijzbRFpgc0K8o4a99fIoHhz9J8AKqXasddMCqfJRaH30 +YJ7HnOvRYGL6HBrGhJ7X4Rzijyk9a9+3VOBsYcnIlx9iODoiYhA6r0ojuIu8/JA1 +oTTZrS0MyU/SLdFdJze2O1wnqTULXQybzJz3ad6oC/F5a69c0m92akYd9nGBrPxj +EhucaQynC/QoCLs3aciLgioAnEJqy7i3EgUCAwEAAaNzMHEwHwYDVR0jBBgwFoAU +YML3pLoA0h93Yngl8Gb/UgAh73owHQYDVR0OBBYEFGDC96S6ANIfd2J4JfBm/1IA +Ie96MAwGA1UdEwQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQE +AwIABTANBgkqhkiG9w0BAQUFAAOCAQEANPR8DN66iWZBs/lSm1vOzhqRkXDLT6xL +LvJtjPLqmE469szGyFSKzsof6y+/8YgZlOoeX1inF4ox/SH1ATnwdIIsPbXuRLjt +axboXvBh5y2ffC3hmzJVvJ87tb6mVWQeL9VFUhNhAI0ib+9OIZVEYI/64MFkDk4e +iWG5ts6oqIJH1V7dVZg6pQ1Tc0Ckhn6N1m1hD30S0/zoPn/20Wq6OCF3he8VJrRG +dcW9BD/Bkesko1HKhMBDjHVrJ8cFwbnDSoo+Ki47eJWaz/cOzaSsaMVUsR5POava +/abhhgHn/eOJdXiVslyK0DYscjsdB3aBUfwZlomxYOzG6CgjQPhJdw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIID9zCCAt+gAwIBAgILMTI1MzcyODI4MjgwDQYJKoZIhvcNAQELBQAwWDELMAkG +A1UEBhMCSlAxHDAaBgNVBAoTE0phcGFuZXNlIEdvdmVybm1lbnQxDTALBgNVBAsT +BEdQS0kxHDAaBgNVBAMTE0FwcGxpY2F0aW9uQ0EyIFJvb3QwHhcNMTMwMzEyMTUw +MDAwWhcNMzMwMzEyMTUwMDAwWjBYMQswCQYDVQQGEwJKUDEcMBoGA1UEChMTSmFw +YW5lc2UgR292ZXJubWVudDENMAsGA1UECxMER1BLSTEcMBoGA1UEAxMTQXBwbGlj +YXRpb25DQTIgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKaq +rSVl1gAR1uh6dqr05rRL88zDUrSNrKZPtZJxb0a11a2LEiIXJc5F6BR6hZrkIxCo ++rFnUOVtR+BqiRPjrq418fRCxQX3TZd+PCj8sCaRHoweOBqW3FhEl2LjMsjRFUFN +dZh4vqtoqV7tR76kuo6hApfek3SZbWe0BSXulMjtqqS6MmxCEeu+yxcGkOGThchk +KM4fR8fAXWDudjbcMztR63vPctgPeKgZggiQPhqYjY60zxU2pm7dt+JNQCBT2XYq +0HisifBPizJtROouurCp64ndt295D6uBbrjmiykLWa+2SQ1RLKn9nShjZrhwlXOa +2Po7M7xCQhsyrLEy+z0CAwEAAaOBwTCBvjAdBgNVHQ4EFgQUVqesqgIdsqw9kA6g +by5Bxnbne9owDgYDVR0PAQH/BAQDAgEGMHwGA1UdEQR1MHOkcTBvMQswCQYDVQQG +EwJKUDEYMBYGA1UECgwP5pel5pys5Zu95pS/5bqcMRswGQYDVQQLDBLmlL/lupzo +qo3oqLzln7rnm6QxKTAnBgNVBAMMIOOCouODl+ODquOCseODvOOCt+ODp+ODs0NB +MiBSb290MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAH+aCXWs +B9FydC53VzDCBJzUgKaD56WgG5/+q/OAvdVKo6GPtkxgEefK4WCB10jBIFmlYTKL +nZ6X02aD2mUuWD7b5S+lzYxzplG+WCigeVxpL0PfY7KJR8q73rk0EWOgDiUX5Yf0 +HbCwpc9BqHTG6FPVQvSCLVMJEWgmcZR1E02qdog8dLHW40xPYsNJTE5t8XB+w3+m +Bcx4m+mB26jIx1ye/JKSLaaX8ji1bnOVDMA/zqaUMLX6BbfeniCq/BNkyYq6ZO/i +Y+TYmK5rtT6mVbgzPixy+ywRAPtbFi+E0hOe+gXFwctyTiLdhMpLvNIthhoEdlkf +SUJiOxMfFui61/0= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV +UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy +dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1 +MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx +dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B +AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f +BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A +cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC +AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ +MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm +aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw +ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj +IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF +MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA +A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y +7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh +1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4 +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDEL +MAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChj +KSAyMDA3IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2 +MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 +eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1OVowgZgxCzAJBgNV +BAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykgMjAw +NyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNV +BAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBH +MjB2MBAGByqGSM49AgEGBSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcL +So17VDs6bl8VAsBQps8lL33KSLjHUGMcKiEIfJo22Av+0SbFWDEwKCXzXV2juLal +tJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO +BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+EVXVMAoG +CCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGT +qQ7mndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBucz +rD6ogRLQy7rQkgu2npaqBA+K +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIFcDCCA1igAwIBAgIEAJiWjTANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJO +TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSkwJwYDVQQDDCBTdGFh +dCBkZXIgTmVkZXJsYW5kZW4gRVYgUm9vdCBDQTAeFw0xMDEyMDgxMTE5MjlaFw0y +MjEyMDgxMTEwMjhaMFgxCzAJBgNVBAYTAk5MMR4wHAYDVQQKDBVTdGFhdCBkZXIg +TmVkZXJsYW5kZW4xKTAnBgNVBAMMIFN0YWF0IGRlciBOZWRlcmxhbmRlbiBFViBS +b290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA48d+ifkkSzrS +M4M1LGns3Amk41GoJSt5uAg94JG6hIXGhaTK5skuU6TJJB79VWZxXSzFYGgEt9nC +UiY4iKTWO0Cmws0/zZiTs1QUWJZV1VD+hq2kY39ch/aO5ieSZxeSAgMs3NZmdO3d +Z//BYY1jTw+bbRcwJu+r0h8QoPnFfxZpgQNH7R5ojXKhTbImxrpsX23Wr9GxE46p +rfNeaXUmGD5BKyF/7otdBwadQ8QpCiv8Kj6GyzyDOvnJDdrFmeK8eEEzduG/L13l +pJhQDBXd4Pqcfzho0LKmeqfRMb1+ilgnQ7O6M5HTp5gVXJrm0w912fxBmJc+qiXb +j5IusHsMX/FjqTf5m3VpTCgmJdrV8hJwRVXj33NeN/UhbJCONVrJ0yPr08C+eKxC +KFhmpUZtcALXEPlLVPxdhkqHz3/KRawRWrUgUY0viEeXOcDPusBCAUCZSCELa6fS +/ZbV0b5GnUngC6agIk440ME8MLxwjyx1zNDFjFE7PZQIZCZhfbnDZY8UnCHQqv0X +cgOPvZuM5l5Tnrmd74K74bzickFbIZTTRTeU0d8JOV3nI6qaHcptqAqGhYqCvkIH +1vI4gnPah1vlPNOePqc7nvQDs/nxfRN0Av+7oeX6AHkcpmZBiFxgV6YuCcS6/ZrP +px9Aw7vMWgpVSzs4dlG4Y4uElBbmVvMCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB +/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFP6rAJCYniT8qcwaivsnuL8wbqg7 +MA0GCSqGSIb3DQEBCwUAA4ICAQDPdyxuVr5Os7aEAJSrR8kN0nbHhp8dB9O2tLsI +eK9p0gtJ3jPFrK3CiAJ9Brc1AsFgyb/E6JTe1NOpEyVa/m6irn0F3H3zbPB+po3u +2dfOWBfoqSmuc0iH55vKbimhZF8ZE/euBhD/UcabTVUlT5OZEAFTdfETzsemQUHS +v4ilf0X8rLiltTMMgsT7B/Zq5SWEXwbKwYY5EdtYzXc7LMJMD16a4/CrPmEbUCTC +wPTxGfARKbalGAKb12NMcIxHowNDXLldRqANb/9Zjr7dn3LDWyvfjFvO5QxGbJKy +CqNMVEIYFRIYvdr8unRu/8G2oGTYqV9Vrp9canaW2HNnh/tNf1zuacpzEPuKqf2e +vTY4SUmH9A4U8OmHuD+nT3pajnnUk+S7aFKErGzp85hwVXIy+TSrK0m1zSBi5Dp6 +Z2Orltxtrpfs/J92VoguZs9btsmksNcFuuEnL5O7Jiqik7Ab846+HUCjuTaPPoIa +Gl6I6lD4WeKDRikL40Rc4ZW2aZCaFG+XroHPaO+Zmr615+F/+PoTRxZMzG0IQOeL +eG9QgkRQP2YGiqtDhFZKDyAthg710tvSeopLzaXoTvFeJiUBWSOgftL2fiFX1ye8 +FVdMpEbB4IMeDExNH08GGeL5qPQ6gqGyeUN51q1veieQA6TqJIc/2b3Z6fJfUEkc +7uzXLg== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDnzCCAoegAwIBAgIBJjANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJERTEc +MBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxlU2Vj +IFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290IENB +IDIwHhcNOTkwNzA5MTIxMTAwWhcNMTkwNzA5MjM1OTAwWjBxMQswCQYDVQQGEwJE +RTEcMBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxl +U2VjIFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290 +IENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrC6M14IspFLEU +ha88EOQ5bzVdSq7d6mGNlUn0b2SjGmBmpKlAIoTZ1KXleJMOaAGtuU1cOs7TuKhC +QN/Po7qCWWqSG6wcmtoIKyUn+WkjR/Hg6yx6m/UTAtB+NHzCnjwAWav12gz1Mjwr +rFDa1sPeg5TKqAyZMg4ISFZbavva4VhYAUlfckE8FQYBjl2tqriTtM2e66foai1S +NNs671x1Udrb8zH57nGYMsRUFUQM+ZtV7a3fGAigo4aKSe5TBY8ZTNXeWHmb0moc +QqvF1afPaA+W5OFhmHZhyJF81j4A4pFQh+GdCuatl9Idxjp9y7zaAzTVjlsB9WoH +txa2bkp/AgMBAAGjQjBAMB0GA1UdDgQWBBQxw3kbuvVT1xfgiXotF2wKsyudMzAP +BgNVHRMECDAGAQH/AgEFMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOC +AQEAlGRZrTlk5ynrE/5aw4sTV8gEJPB0d8Bg42f76Ymmg7+Wgnxu1MM9756Abrsp +tJh6sTtU6zkXR34ajgv8HzFZMQSyzhfzLMdiNlXiItiJVbSYSKpk+tYcNthEeFpa +IzpXl/V6ME+un2pMSyuOoAPjPuCp1NJ70rOo4nI8rZ7/gFnkm0W09juwzTkZmDLl +6iFhkOQxIY40sfcvNUqFENrnijchvllj4PKFiDFT1FQUhXB59C4Gdyd1Lx+4ivn+ +xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU +Cm26OWMohpLzGITY+9HPBVZkVw== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIGSzCCBDOgAwIBAgIIamg+nFGby1MwDQYJKoZIhvcNAQELBQAwgbIxCzAJBgNV +BAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExQDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBC +aWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhpem1ldGxlcmkgQS7Fni4xJjAkBgNV +BAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBNZXJrZXppMSgwJgYDVQQDDB9FLVR1 +Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTEzMDMwNTEyMDk0OFoXDTIz +MDMwMzEyMDk0OFowgbIxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExQDA+ +BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhp +em1ldGxlcmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBN +ZXJrZXppMSgwJgYDVQQDDB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA4vU/kwVRHoViVF56C/UY +B4Oufq9899SKa6VjQzm5S/fDxmSJPZQuVIBSOTkHS0vdhQd2h8y/L5VMzH2nPbxH +D5hw+IyFHnSOkm0bQNGZDbt1bsipa5rAhDGvykPL6ys06I+XawGb1Q5KCKpbknSF +Q9OArqGIW66z6l7LFpp3RMih9lRozt6Plyu6W0ACDGQXwLWTzeHxE2bODHnv0ZEo +q1+gElIwcxmOj+GMB6LDu0rw6h8VqO4lzKRG+Bsi77MOQ7osJLjFLFzUHPhdZL3D +k14opz8n8Y4e0ypQBaNV2cvnOVPAmJ6MVGKLJrD3fY185MaeZkJVgkfnsliNZvcH +fC425lAcP9tDJMW/hkd5s3kc91r0E+xs+D/iWR+V7kI+ua2oMoVJl0b+SzGPWsut +dEcf6ZG33ygEIqDUD13ieU/qbIWGvaimzuT6w+Gzrt48Ue7LE3wBf4QOXVGUnhMM +ti6lTPk5cDZvlsouDERVxcr6XQKj39ZkjFqzAQqptQpHF//vkUAqjqFGOjGY5RH8 +zLtJVor8udBhmm9lbObDyz51Sf6Pp+KJxWfXnUYTTjF2OySznhFlhqt/7x3U+Lzn +rFpct1pHXFXOVbQicVtbC/DP3KBhZOqp12gKY6fgDT+gr9Oq0n7vUaDmUStVkhUX +U8u3Zg5mTPj5dUyQ5xJwx0UCAwEAAaNjMGEwHQYDVR0OBBYEFC7j27JJ0JxUeVz6 +Jyr+zE7S6E5UMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAULuPbsknQnFR5 +XPonKv7MTtLoTlQwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAF +Nzr0TbdF4kV1JI+2d1LoHNgQk2Xz8lkGpD4eKexd0dCrfOAKkEh47U6YA5n+KGCR +HTAduGN8qOY1tfrTYXbm1gdLymmasoR6d5NFFxWfJNCYExL/u6Au/U5Mh/jOXKqY +GwXgAEZKgoClM4so3O0409/lPun++1ndYYRP0lSWE2ETPo+Aab6TR7U1Q9Jauz1c +77NCR807VRMGsAnb/WP2OogKmW9+4c4bU2pEZiNRCHu8W1Ki/QY3OEBhj0qWuJA3 ++GbHeJAAFS6LrVE1Uweoa2iu+U48BybNCAVwzDk/dr2l02cmAYamU9JgO3xDf1WK +vJUawSg5TB9D0pH0clmKuVb8P7Sd2nCcdlqMQ1DujjByTd//SffGqWfZbawCEeI6 +FiWnWAjLb1NBnEg4R2gz0dfHj9R0IdTDBZB6/86WiLEVKV0jq9BgoRJP3vQXzTLl +yb/IQ639Lo7xr+L0mPoSHyDYwKcMhcWQ9DstliaxLL5Mq+ux0orJ23gTDx4JnW2P +AJ8C2sH6H3p6CcRK5ogql5+Ji/03X186zjhZhkuvcQu02PJwT58yE+Owp1fl2tpD +y4Q08ijE6m30Ku/Ba3ba+367hTzSU8JNvnHhRdH9I2cNE3X7z2VnIp2usAnRCf8d +NL/+I5c30jn6PQ0GC7TbO6Orb1wdtn7os4I07QZcJA== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDtTCCAp2gAwIBAgIIBhDCeat3PfIwDQYJKoZIhvcNAQEFBQAwdjELMAkGA1UE +BhMCQ0gxEjAQBgNVBAoTCVN3aXNzU2lnbjEyMDAGA1UEAxMpU3dpc3NTaWduIENB +IChSU0EgSUsgTWF5IDYgMTk5OSAxODowMDo1OCkxHzAdBgkqhkiG9w0BCQEWEGNh +QFN3aXNzU2lnbi5jb20wHhcNMDAxMTI2MjMyNzQxWhcNMzExMTI2MjMyNzQxWjB2 +MQswCQYDVQQGEwJDSDESMBAGA1UEChMJU3dpc3NTaWduMTIwMAYDVQQDEylTd2lz +c1NpZ24gQ0EgKFJTQSBJSyBNYXkgNiAxOTk5IDE4OjAwOjU4KTEfMB0GCSqGSIb3 +DQEJARYQY2FAU3dpc3NTaWduLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC +AQoCggEBAKw5fjnmNneLQlUCQG8jQLwwfbrOZoUwNX8cbNqhxK03/xUloFVgAt+S +Te2RxNXaCAXLBPn5ZST35TLV57aLmbHCtifv3YZqaaQGvjedltIBMJihJhZ+h3LY +SKsUb+xEJ3x5ZUf8jP+Q1g57y1s8SnBFWN/ni5NkF1Y1y31VwOi9wiOf/VISL+uu +SC4i1CP1Kbz3BDs6Hht1GpRYCbJ/K0bc9oJSpWpT5PGONsGIawqMbJuyoDghsXQ1 +pbn2e8K64BSscGZVZTNooSGgNiHmACNJBYXiWVWrwXPF4l6SddmC3Rj0aKXjgECc +FkHLDQcsM5JsK2ZLryTDUsQFbxVP2ikCAwEAAaNHMEUwCwYDVR0PBAQDAgEGMAwG +A1UdEwQFMAMBAf8wHQYDVR0OBBYEFJbXcc05KtT8iLGKq1N4ae+PR34WMAkGA1Ud +IwQCMAAwDQYJKoZIhvcNAQEFBQADggEBAKMy6W8HvZdS1fBpEUzl6Lvw50bgE1Xc +HU1JypSBG9mhdcXZo5AlPB4sCvx9Dmfwhyrdsshc0TP2V3Vh6eQqnEF5qB4lVziT +Bko9mW6Ot+pPnwsy4SHpx3rw6jCYnOqfUcZjWqqqRrq/3P1waz+Mn4cLMVEg3Xaz +qYov/khvSqS0JniwjRlo2H6f/1oVUKZvP+dUhpQepfZrOqMAWZW4otp6FolyQyeU +NN6UCRNiUKl5vTijbKwUUwfER/1Vci3M1/O1QCfttQ4vRN4Buc0xqYtGL3cd5WiO +vWzyhlTzAI6VUdNkQhhHJSAyTpj6dmXDRzrryoFGa2PjgESxz7XBaSI= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDZzCCAk+gAwIBAgIQGx+ttiD5JNM2a/fH8YygWTANBgkqhkiG9w0BAQUFADBF +MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPVHJ1c3RpcyBMaW1pdGVkMRwwGgYDVQQL +ExNUcnVzdGlzIEZQUyBSb290IENBMB4XDTAzMTIyMzEyMTQwNloXDTI0MDEyMTEx +MzY1NFowRTELMAkGA1UEBhMCR0IxGDAWBgNVBAoTD1RydXN0aXMgTGltaXRlZDEc +MBoGA1UECxMTVHJ1c3RpcyBGUFMgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAMVQe547NdDfxIzNjpvto8A2mfRC6qc+gIMPpqdZh8mQRUN+ +AOqGeSoDvT03mYlmt+WKVoaTnGhLaASMk5MCPjDSNzoiYYkchU59j9WvezX2fihH +iTHcDnlkH5nSW7r+f2C/revnPDgpai/lkQtV/+xvWNUtyd5MZnGPDNcE2gfmHhjj +vSkCqPoc4Vu5g6hBSLwacY3nYuUtsuvffM/bq1rKMfFMIvMFE/eC+XN5DL7XSxzA +0RU8k0Fk0ea+IxciAIleH2ulrG6nS4zto3Lmr2NNL4XSFDWaLk6M6jKYKIahkQlB +OrTh4/L68MkKokHdqeMDx4gVOxzUGpTXn2RZEm0CAwEAAaNTMFEwDwYDVR0TAQH/ +BAUwAwEB/zAfBgNVHSMEGDAWgBS6+nEleYtXQSUhhgtx67JkDoshZzAdBgNVHQ4E +FgQUuvpxJXmLV0ElIYYLceuyZA6LIWcwDQYJKoZIhvcNAQEFBQADggEBAH5Y//01 +GX2cGE+esCu8jowU/yyg2kdbw++BLa8F6nRIW/M+TgfHbcWzk88iNVy2P3UnXwmW +zaD+vkAMXBJV+JOCyinpXj9WV4s4NvdFGkwozZ5BuO1WTISkQMi4sKUraXAEasP4 +1BIy+Q7DsdwyhEQsb8tGD+pmQQ9P8Vilpg0ND2HepZ5dfWWhPBfnqFVO76DH7cZE +f1T1o+CP8HxVIo8ptoGj4W1OLBuAZ+ytIJ8MYmHVl/9D7S3B2l0pKoU/rGXuhg8F +jZBf3+6f9L/uHfuY5H+QK4R4EA5sSVPvFVtlRkpdr7r7OnIdzfYliB6XzCGcKQEN +ZetX2fNXlrtIzYE= +-----END CERTIFICATE----- +` diff --git a/libgo/go/crypto/x509/root_linux.go b/libgo/go/crypto/x509/root_linux.go new file mode 100644 index 00000000000..cfeca6958ca --- /dev/null +++ b/libgo/go/crypto/x509/root_linux.go @@ -0,0 +1,13 @@ +// Copyright 2015 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 + +// Possible certificate files; stop after finding one. +var certFiles = []string{ + "/etc/ssl/certs/ca-certificates.crt", // Debian/Ubuntu/Gentoo etc. + "/etc/pki/tls/certs/ca-bundle.crt", // Fedora/RHEL + "/etc/ssl/ca-bundle.pem", // OpenSUSE + "/etc/pki/tls/cacert.pem", // OpenELEC +} diff --git a/libgo/go/crypto/x509/root_nacl.go b/libgo/go/crypto/x509/root_nacl.go new file mode 100644 index 00000000000..4413f64738a --- /dev/null +++ b/libgo/go/crypto/x509/root_nacl.go @@ -0,0 +1,8 @@ +// Copyright 2015 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 + +// Possible certificate files; stop after finding one. +var certFiles = []string{} diff --git a/libgo/go/crypto/x509/root_solaris.go b/libgo/go/crypto/x509/root_solaris.go new file mode 100644 index 00000000000..e6d4e613994 --- /dev/null +++ b/libgo/go/crypto/x509/root_solaris.go @@ -0,0 +1,12 @@ +// Copyright 2015 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 + +// Possible certificate files; stop after finding one. +var certFiles = []string{ + "/etc/certs/ca-certificates.crt", // Solaris 11.2+ + "/etc/ssl/certs/ca-certificates.crt", // Joyent SmartOS + "/etc/ssl/cacert.pem", // OmniOS +} diff --git a/libgo/go/crypto/x509/root_unix.go b/libgo/go/crypto/x509/root_unix.go index f77d6c0c57f..8d3b2fbb233 100644 --- a/libgo/go/crypto/x509/root_unix.go +++ b/libgo/go/crypto/x509/root_unix.go @@ -8,22 +8,10 @@ package x509 import "io/ioutil" -// Possible certificate files; stop after finding one. -var certFiles = []string{ - "/etc/ssl/certs/ca-certificates.crt", // Debian/Ubuntu/Gentoo etc. - "/etc/pki/tls/certs/ca-bundle.crt", // Fedora/RHEL - "/etc/ssl/ca-bundle.pem", // OpenSUSE - "/etc/ssl/cert.pem", // OpenBSD - "/usr/local/share/certs/ca-root-nss.crt", // FreeBSD/DragonFly - "/etc/pki/tls/cacert.pem", // OpenELEC - "/etc/certs/ca-certificates.crt", // Solaris 11.2+ -} - // Possible directories with certificate files; stop after successfully // reading at least one file from a directory. var certDirectories = []string{ "/system/etc/security/cacerts", // Android - } func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) { diff --git a/libgo/go/crypto/x509/sec1.go b/libgo/go/crypto/x509/sec1.go index 7de66754eeb..c4d7ab68f7d 100644 --- a/libgo/go/crypto/x509/sec1.go +++ b/libgo/go/crypto/x509/sec1.go @@ -18,7 +18,7 @@ const ecPrivKeyVersion = 1 // ecPrivateKey reflects an ASN.1 Elliptic Curve Private Key Structure. // References: // RFC5915 -// SEC1 - http://www.secg.org/download/aid-780/sec1-v2.pdf +// SEC1 - http://www.secg.org/sec1-v2.pdf // Per RFC5915 the NamedCurveOID is marked as ASN.1 OPTIONAL, however in // most cases it is not. type ecPrivateKey struct { diff --git a/libgo/go/crypto/x509/sha2_windows_test.go b/libgo/go/crypto/x509/sha2_windows_test.go new file mode 100644 index 00000000000..79dc685c5b5 --- /dev/null +++ b/libgo/go/crypto/x509/sha2_windows_test.go @@ -0,0 +1,19 @@ +// Copyright 2015 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 "syscall" + +func init() { + v, err := syscall.GetVersion() + if err != nil { + return + } + if major := byte(v); major < 6 { + // Windows XP SP2 and Windows 2003 do not support SHA2. + // http://blogs.technet.com/b/pki/archive/2010/09/30/sha2-and-windows.aspx + supportSHA2 = false + } +} diff --git a/libgo/go/crypto/x509/verify.go b/libgo/go/crypto/x509/verify.go index ec1981423db..21b870c1712 100644 --- a/libgo/go/crypto/x509/verify.go +++ b/libgo/go/crypto/x509/verify.go @@ -215,6 +215,10 @@ func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err e return c.systemVerify(&opts) } + if len(c.UnhandledCriticalExtensions) > 0 { + return nil, UnhandledCriticalExtension{} + } + if opts.Roots == nil { opts.Roots = systemRootsPool() if opts.Roots == nil { @@ -323,6 +327,9 @@ nextIntermediate: } func matchHostnames(pattern, host string) bool { + host = strings.TrimSuffix(host, ".") + pattern = strings.TrimSuffix(pattern, ".") + if len(pattern) == 0 || len(host) == 0 { return false } @@ -335,7 +342,7 @@ func matchHostnames(pattern, host string) bool { } for i, patternPart := range patternParts { - if patternPart == "*" { + if i == 0 && patternPart == "*" { continue } if patternPart != hostParts[i] { diff --git a/libgo/go/crypto/x509/verify_test.go b/libgo/go/crypto/x509/verify_test.go index 96b9d9b420b..694c14023b8 100644 --- a/libgo/go/crypto/x509/verify_test.go +++ b/libgo/go/crypto/x509/verify_test.go @@ -14,6 +14,8 @@ import ( "time" ) +var supportSHA2 = true + type verifyTest struct { leaf string intermediates []string @@ -23,6 +25,7 @@ type verifyTest struct { systemSkip bool keyUsages []ExtKeyUsage testSystemRootsError bool + sha2 bool errorCallback func(*testing.T, int, error) bool expectedChains [][]string @@ -218,6 +221,11 @@ var verifyTests = []verifyTest{ currentTime: 1397502195, dnsName: "api.moip.com.br", + // CryptoAPI can find alternative validation paths so we don't + // perform this test with system validation. + systemSkip: true, + + sha2: true, expectedChains: [][]string{ { "api.moip.com.br", @@ -297,6 +305,9 @@ func testVerify(t *testing.T, useSystemRoots bool) { if runtime.GOOS == "windows" && test.testSystemRootsError { continue } + if useSystemRoots && !supportSHA2 && test.sha2 { + continue + } opts := VerifyOptions{ Intermediates: NewCertPool(), diff --git a/libgo/go/crypto/x509/x509.go b/libgo/go/crypto/x509/x509.go index 7a37b98e317..be6c013464b 100644 --- a/libgo/go/crypto/x509/x509.go +++ b/libgo/go/crypto/x509/x509.go @@ -12,7 +12,7 @@ import ( "crypto/ecdsa" "crypto/elliptic" "crypto/rsa" - "crypto/sha1" + _ "crypto/sha1" _ "crypto/sha256" _ "crypto/sha512" "crypto/x509/pkix" @@ -37,8 +37,10 @@ type pkixPublicKey struct { // typically found in PEM blocks with "BEGIN PUBLIC KEY". func ParsePKIXPublicKey(derBytes []byte) (pub interface{}, err error) { var pki publicKeyInfo - if _, err = asn1.Unmarshal(derBytes, &pki); err != nil { - return + if rest, err := asn1.Unmarshal(derBytes, &pki); err != nil { + return nil, err + } else if len(rest) != 0 { + return nil, errors.New("x509: trailing data after ASN.1 of public-key") } algo := getPublicKeyAlgorithmFromOID(pki.Algorithm.Algorithm) if algo == UnknownPublicKeyAlgorithm { @@ -488,6 +490,16 @@ type Certificate struct { // field is not populated when parsing certificates, see Extensions. ExtraExtensions []pkix.Extension + // UnhandledCriticalExtensions contains a list of extension IDs that + // were not (fully) processed when parsing. Verify will fail if this + // slice is non-empty, unless verification is delegated to an OS + // library which understands all the critical extensions. + // + // Users can access these extensions using Extensions and can remove + // elements from this slice if they believe that they have been + // handled. + UnhandledCriticalExtensions []asn1.ObjectIdentifier + ExtKeyUsage []ExtKeyUsage // Sequence of extended key usages. UnknownExtKeyUsage []asn1.ObjectIdentifier // Encountered extended key usages unknown to this package. @@ -619,6 +631,12 @@ func (c *Certificate) CheckSignatureFrom(parent *Certificate) (err error) { // CheckSignature verifies that signature is a valid signature over signed from // c's public key. func (c *Certificate) CheckSignature(algo SignatureAlgorithm, signed, signature []byte) (err error) { + return checkSignature(algo, signed, signature, c.PublicKey) +} + +// CheckSignature verifies that signature is a valid signature over signed from +// a crypto.PublicKey. +func checkSignature(algo SignatureAlgorithm, signed, signature []byte, publicKey crypto.PublicKey) (err error) { var hashType crypto.Hash switch algo { @@ -642,13 +660,15 @@ func (c *Certificate) CheckSignature(algo SignatureAlgorithm, signed, signature h.Write(signed) digest := h.Sum(nil) - switch pub := c.PublicKey.(type) { + switch pub := publicKey.(type) { case *rsa.PublicKey: return rsa.VerifyPKCS1v15(pub, hashType, digest, signature) case *dsa.PublicKey: dsaSig := new(dsaSignature) - if _, err := asn1.Unmarshal(signature, dsaSig); err != nil { + if rest, err := asn1.Unmarshal(signature, dsaSig); err != nil { return err + } else if len(rest) != 0 { + return errors.New("x509: trailing data after DSA signature") } if dsaSig.R.Sign() <= 0 || dsaSig.S.Sign() <= 0 { return errors.New("x509: DSA signature contained zero or negative values") @@ -659,8 +679,10 @@ func (c *Certificate) CheckSignature(algo SignatureAlgorithm, signed, signature return case *ecdsa.PublicKey: ecdsaSig := new(ecdsaSignature) - if _, err := asn1.Unmarshal(signature, ecdsaSig); err != nil { + if rest, err := asn1.Unmarshal(signature, ecdsaSig); err != nil { return err + } else if len(rest) != 0 { + return errors.New("x509: trailing data after ECDSA signature") } if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 { return errors.New("x509: ECDSA signature contained zero or negative values") @@ -729,10 +751,13 @@ func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{ switch algo { case RSA: p := new(rsaPublicKey) - _, err := asn1.Unmarshal(asn1Data, p) + rest, err := asn1.Unmarshal(asn1Data, p) if err != nil { return nil, err } + if len(rest) != 0 { + return nil, errors.New("x509: trailing data after RSA public key") + } if p.N.Sign() <= 0 { return nil, errors.New("x509: RSA modulus is not a positive number") @@ -748,16 +773,22 @@ func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{ return pub, nil case DSA: var p *big.Int - _, err := asn1.Unmarshal(asn1Data, &p) + rest, err := asn1.Unmarshal(asn1Data, &p) if err != nil { return nil, err } + if len(rest) != 0 { + return nil, errors.New("x509: trailing data after DSA public key") + } paramsData := keyData.Algorithm.Parameters.FullBytes params := new(dsaAlgorithmParameters) - _, err = asn1.Unmarshal(paramsData, params) + rest, err = asn1.Unmarshal(paramsData, params) if err != nil { return nil, err } + if len(rest) != 0 { + return nil, errors.New("x509: trailing data after DSA parameters") + } if p.Sign() <= 0 || params.P.Sign() <= 0 || params.Q.Sign() <= 0 || params.G.Sign() <= 0 { return nil, errors.New("x509: zero or negative DSA parameter") } @@ -773,10 +804,13 @@ func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{ case ECDSA: paramsData := keyData.Algorithm.Parameters.FullBytes namedCurveOID := new(asn1.ObjectIdentifier) - _, err := asn1.Unmarshal(paramsData, namedCurveOID) + rest, err := asn1.Unmarshal(paramsData, namedCurveOID) if err != nil { return nil, err } + if len(rest) != 0 { + return nil, errors.New("x509: trailing data after ECDSA parameters") + } namedCurve := namedCurveFromOID(*namedCurveOID) if namedCurve == nil { return nil, errors.New("x509: unsupported elliptic curve") @@ -814,7 +848,11 @@ func parseSANExtension(value []byte) (dnsNames, emailAddresses []string, ipAddre // iPAddress [7] OCTET STRING, // registeredID [8] OBJECT IDENTIFIER } var seq asn1.RawValue - if _, err = asn1.Unmarshal(value, &seq); err != nil { + var rest []byte + if rest, err = asn1.Unmarshal(value, &seq); err != nil { + return + } else if len(rest) != 0 { + err = errors.New("x509: trailing data after X.509 extension") return } if !seq.IsCompound || seq.Tag != 16 || seq.Class != 0 { @@ -822,7 +860,7 @@ func parseSANExtension(value []byte) (dnsNames, emailAddresses []string, ipAddre return } - rest := seq.Bytes + rest = seq.Bytes for len(rest) > 0 { var v asn1.RawValue rest, err = asn1.Unmarshal(rest, &v) @@ -876,11 +914,15 @@ func parseCertificate(in *certificate) (*Certificate, error) { out.SerialNumber = in.TBSCertificate.SerialNumber var issuer, subject pkix.RDNSequence - if _, err := asn1.Unmarshal(in.TBSCertificate.Subject.FullBytes, &subject); err != nil { + if rest, err := asn1.Unmarshal(in.TBSCertificate.Subject.FullBytes, &subject); err != nil { return nil, err + } else if len(rest) != 0 { + return nil, errors.New("x509: trailing data after X.509 subject") } - if _, err := asn1.Unmarshal(in.TBSCertificate.Issuer.FullBytes, &issuer); err != nil { + if rest, err := asn1.Unmarshal(in.TBSCertificate.Issuer.FullBytes, &issuer); err != nil { return nil, err + } else if len(rest) != 0 { + return nil, errors.New("x509: trailing data after X.509 subject") } out.Issuer.FillFromRDNSequence(&issuer) @@ -891,47 +933,51 @@ func parseCertificate(in *certificate) (*Certificate, error) { for _, e := range in.TBSCertificate.Extensions { out.Extensions = append(out.Extensions, e) + unhandled := false if len(e.Id) == 4 && e.Id[0] == 2 && e.Id[1] == 5 && e.Id[2] == 29 { switch e.Id[3] { case 15: // RFC 5280, 4.2.1.3 var usageBits asn1.BitString - _, err := asn1.Unmarshal(e.Value, &usageBits) + if rest, err := asn1.Unmarshal(e.Value, &usageBits); err != nil { + return nil, err + } else if len(rest) != 0 { + return nil, errors.New("x509: trailing data after X.509 KeyUsage") + } - if err == nil { - var usage int - for i := 0; i < 9; i++ { - if usageBits.At(i) != 0 { - usage |= 1 << uint(i) - } + var usage int + for i := 0; i < 9; i++ { + if usageBits.At(i) != 0 { + usage |= 1 << uint(i) } - out.KeyUsage = KeyUsage(usage) - continue } + out.KeyUsage = KeyUsage(usage) + case 19: // RFC 5280, 4.2.1.9 var constraints basicConstraints - _, err := asn1.Unmarshal(e.Value, &constraints) - - if err == nil { - out.BasicConstraintsValid = true - out.IsCA = constraints.IsCA - out.MaxPathLen = constraints.MaxPathLen - out.MaxPathLenZero = out.MaxPathLen == 0 - continue + if rest, err := asn1.Unmarshal(e.Value, &constraints); err != nil { + return nil, err + } else if len(rest) != 0 { + return nil, errors.New("x509: trailing data after X.509 BasicConstraints") } + + out.BasicConstraintsValid = true + out.IsCA = constraints.IsCA + out.MaxPathLen = constraints.MaxPathLen + out.MaxPathLenZero = out.MaxPathLen == 0 + case 17: out.DNSNames, out.EmailAddresses, out.IPAddresses, err = parseSANExtension(e.Value) if err != nil { return nil, err } - if len(out.DNSNames) > 0 || len(out.EmailAddresses) > 0 || len(out.IPAddresses) > 0 { - continue + if len(out.DNSNames) == 0 && len(out.EmailAddresses) == 0 && len(out.IPAddresses) == 0 { + // If we didn't parse anything then we do the critical check, below. + unhandled = true } - // If we didn't parse any of the names then we - // fall through to the critical check below. case 30: // RFC 5280, 4.2.1.10 @@ -950,9 +996,10 @@ func parseCertificate(in *certificate) (*Certificate, error) { // BaseDistance ::= INTEGER (0..MAX) var constraints nameConstraints - _, err := asn1.Unmarshal(e.Value, &constraints) - if err != nil { + if rest, err := asn1.Unmarshal(e.Value, &constraints); err != nil { return nil, err + } else if len(rest) != 0 { + return nil, errors.New("x509: trailing data after X.509 NameConstraints") } if len(constraints.Excluded) > 0 && e.Critical { @@ -968,7 +1015,6 @@ func parseCertificate(in *certificate) (*Certificate, error) { } out.PermittedDNSDomains = append(out.PermittedDNSDomains, subtree.Name) } - continue case 31: // RFC 5280, 4.2.1.14 @@ -985,33 +1031,35 @@ func parseCertificate(in *certificate) (*Certificate, error) { // nameRelativeToCRLIssuer [1] RelativeDistinguishedName } var cdp []distributionPoint - _, err := asn1.Unmarshal(e.Value, &cdp) - if err != nil { + if rest, err := asn1.Unmarshal(e.Value, &cdp); err != nil { return nil, err + } else if len(rest) != 0 { + return nil, errors.New("x509: trailing data after X.509 CRL distribution point") } for _, dp := range cdp { var n asn1.RawValue - _, err = asn1.Unmarshal(dp.DistributionPoint.FullName.Bytes, &n) - if err != nil { + if _, err := asn1.Unmarshal(dp.DistributionPoint.FullName.Bytes, &n); err != nil { return nil, err } + // Trailing data after the fullName is + // allowed because other elements of + // the SEQUENCE can appear. if n.Tag == 6 { out.CRLDistributionPoints = append(out.CRLDistributionPoints, string(n.Bytes)) } } - continue case 35: // RFC 5280, 4.2.1.1 var a authKeyId - _, err = asn1.Unmarshal(e.Value, &a) - if err != nil { + if rest, err := asn1.Unmarshal(e.Value, &a); err != nil { return nil, err + } else if len(rest) != 0 { + return nil, errors.New("x509: trailing data after X.509 authority key-id") } out.AuthorityKeyId = a.Id - continue case 37: // RFC 5280, 4.2.1.12. Extended Key Usage @@ -1023,9 +1071,10 @@ func parseCertificate(in *certificate) (*Certificate, error) { // KeyPurposeId ::= OBJECT IDENTIFIER var keyUsage []asn1.ObjectIdentifier - _, err = asn1.Unmarshal(e.Value, &keyUsage) - if err != nil { + if rest, err := asn1.Unmarshal(e.Value, &keyUsage); err != nil { return nil, err + } else if len(rest) != 0 { + return nil, errors.New("x509: trailing data after X.509 ExtendedKeyUsage") } for _, u := range keyUsage { @@ -1036,34 +1085,40 @@ func parseCertificate(in *certificate) (*Certificate, error) { } } - continue - case 14: // RFC 5280, 4.2.1.2 var keyid []byte - _, err = asn1.Unmarshal(e.Value, &keyid) - if err != nil { + if rest, err := asn1.Unmarshal(e.Value, &keyid); err != nil { return nil, err + } else if len(rest) != 0 { + return nil, errors.New("x509: trailing data after X.509 authority key-id") } out.SubjectKeyId = keyid - continue case 32: // RFC 5280 4.2.1.4: Certificate Policies var policies []policyInformation - if _, err = asn1.Unmarshal(e.Value, &policies); err != nil { + if rest, err := asn1.Unmarshal(e.Value, &policies); err != nil { return nil, err + } else if len(rest) != 0 { + return nil, errors.New("x509: trailing data after X.509 certificate policies") } out.PolicyIdentifiers = make([]asn1.ObjectIdentifier, len(policies)) for i, policy := range policies { out.PolicyIdentifiers[i] = policy.Policy } + + default: + // Unknown extensions are recorded if critical. + unhandled = true } } else if e.Id.Equal(oidExtensionAuthorityInfoAccess) { // RFC 5280 4.2.2.1: Authority Information Access var aia []authorityInfoAccess - if _, err = asn1.Unmarshal(e.Value, &aia); err != nil { + if rest, err := asn1.Unmarshal(e.Value, &aia); err != nil { return nil, err + } else if len(rest) != 0 { + return nil, errors.New("x509: trailing data after X.509 authority information") } for _, v := range aia { @@ -1077,10 +1132,13 @@ func parseCertificate(in *certificate) (*Certificate, error) { out.IssuingCertificateURL = append(out.IssuingCertificateURL, string(v.Location.Bytes)) } } + } else { + // Unknown extensions are recorded if critical. + unhandled = true } - if e.Critical { - return out, UnhandledCriticalExtension{} + if e.Critical && unhandled { + out.UnhandledCriticalExtensions = append(out.UnhandledCriticalExtensions, e.Id) } } @@ -1135,6 +1193,26 @@ func reverseBitsInAByte(in byte) byte { return b3 } +// asn1BitLength returns the bit-length of bitString by considering the +// most-significant bit in a byte to be the "first" bit. This convention +// matches ASN.1, but differs from almost everything else. +func asn1BitLength(bitString []byte) int { + bitLen := len(bitString) * 8 + + for i := range bitString { + b := bitString[len(bitString)-i-1] + + for bit := uint(0); bit < 8; bit++ { + if (b>>bit)&1 == 1 { + return bitLen + } + bitLen-- + } + } + + return 0 +} + var ( oidExtensionSubjectKeyId = []int{2, 5, 29, 14} oidExtensionKeyUsage = []int{2, 5, 29, 15} @@ -1203,7 +1281,8 @@ func buildExtensions(template *Certificate) (ret []pkix.Extension, err error) { l = 2 } - ret[n].Value, err = asn1.Marshal(asn1.BitString{Bytes: a[0:l], BitLength: l * 8}) + bitString := a[:l] + ret[n].Value, err = asn1.Marshal(asn1.BitString{Bytes: bitString, BitLength: asn1BitLength(bitString)}) if err != nil { return } @@ -1368,22 +1447,25 @@ func subjectBytes(cert *Certificate) ([]byte, error) { return asn1.Marshal(cert.Subject.ToRDNSequence()) } -// signingParamsForPrivateKey returns the parameters to use for signing with +// signingParamsForPublicKey returns the parameters to use for signing with // priv. If requestedSigAlgo is not zero then it overrides the default // signature algorithm. -func signingParamsForPrivateKey(priv interface{}, requestedSigAlgo SignatureAlgorithm) (hashFunc crypto.Hash, sigAlgo pkix.AlgorithmIdentifier, err error) { +func signingParamsForPublicKey(pub interface{}, requestedSigAlgo SignatureAlgorithm) (hashFunc crypto.Hash, sigAlgo pkix.AlgorithmIdentifier, err error) { var pubType PublicKeyAlgorithm - switch priv := priv.(type) { - case *rsa.PrivateKey: + switch pub := pub.(type) { + case *rsa.PublicKey: pubType = RSA - sigAlgo.Algorithm = oidSignatureSHA256WithRSA hashFunc = crypto.SHA256 + sigAlgo.Algorithm = oidSignatureSHA256WithRSA + sigAlgo.Parameters = asn1.RawValue{ + Tag: 5, + } - case *ecdsa.PrivateKey: + case *ecdsa.PublicKey: pubType = ECDSA - switch priv.Curve { + switch pub.Curve { case elliptic.P224(), elliptic.P256(): hashFunc = crypto.SHA256 sigAlgo.Algorithm = oidSignatureECDSAWithSHA256 @@ -1398,7 +1480,7 @@ func signingParamsForPrivateKey(priv interface{}, requestedSigAlgo SignatureAlgo } default: - err = errors.New("x509: only RSA and ECDSA private keys supported") + err = errors.New("x509: only RSA and ECDSA keys supported") } if err != nil { @@ -1445,21 +1527,22 @@ func signingParamsForPrivateKey(priv interface{}, requestedSigAlgo SignatureAlgo // // The returned slice is the certificate in DER encoding. // -// The only supported key types are RSA and ECDSA (*rsa.PublicKey or -// *ecdsa.PublicKey for pub, *rsa.PrivateKey or *ecdsa.PrivateKey for priv). -func CreateCertificate(rand io.Reader, template, parent *Certificate, pub interface{}, priv interface{}) (cert []byte, err error) { - hashFunc, signatureAlgorithm, err := signingParamsForPrivateKey(priv, template.SignatureAlgorithm) - if err != nil { - return nil, err +// All keys types that are implemented via crypto.Signer are supported (This +// includes *rsa.PublicKey and *ecdsa.PublicKey.) +func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv interface{}) (cert []byte, err error) { + key, ok := priv.(crypto.Signer) + if !ok { + return nil, errors.New("x509: certificate private key does not implement crypto.Signer") } - publicKeyBytes, publicKeyAlgorithm, err := marshalPublicKey(pub) + hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(key.Public(), template.SignatureAlgorithm) if err != nil { return nil, err } + publicKeyBytes, publicKeyAlgorithm, err := marshalPublicKey(pub) if err != nil { - return + return nil, err } if len(parent.SubjectKeyId) > 0 { @@ -1505,30 +1588,17 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub interf digest := h.Sum(nil) var signature []byte - - switch priv := priv.(type) { - case *rsa.PrivateKey: - signature, err = rsa.SignPKCS1v15(rand, priv, hashFunc, digest) - case *ecdsa.PrivateKey: - var r, s *big.Int - if r, s, err = ecdsa.Sign(rand, priv, digest); err == nil { - signature, err = asn1.Marshal(ecdsaSignature{r, s}) - } - default: - panic("internal error") - } - + signature, err = key.Sign(rand, digest, hashFunc) if err != nil { return } - cert, err = asn1.Marshal(certificate{ + return asn1.Marshal(certificate{ nil, c, signatureAlgorithm, asn1.BitString{Bytes: signature, BitLength: len(signature) * 8}, }) - return } // pemCRLPrefix is the magic string that indicates that we have a PEM encoded @@ -1555,53 +1625,66 @@ func ParseCRL(crlBytes []byte) (certList *pkix.CertificateList, err error) { // ParseDERCRL parses a DER encoded CRL from the given bytes. func ParseDERCRL(derBytes []byte) (certList *pkix.CertificateList, err error) { certList = new(pkix.CertificateList) - _, err = asn1.Unmarshal(derBytes, certList) - if err != nil { - certList = nil + if rest, err := asn1.Unmarshal(derBytes, certList); err != nil { + return nil, err + } else if len(rest) != 0 { + return nil, errors.New("x509: trailing data after CRL") } - return + return certList, nil } // CreateCRL returns a DER encoded CRL, signed by this Certificate, that // contains the given list of revoked certificates. -// -// The only supported key type is RSA (*rsa.PrivateKey for priv). func (c *Certificate) CreateCRL(rand io.Reader, priv interface{}, revokedCerts []pkix.RevokedCertificate, now, expiry time.Time) (crlBytes []byte, err error) { - rsaPriv, ok := priv.(*rsa.PrivateKey) + key, ok := priv.(crypto.Signer) if !ok { - return nil, errors.New("x509: non-RSA private keys not supported") + return nil, errors.New("x509: certificate private key does not implement crypto.Signer") } + + hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(key.Public(), 0) + if err != nil { + return nil, err + } + tbsCertList := pkix.TBSCertificateList{ - Version: 2, - Signature: pkix.AlgorithmIdentifier{ - Algorithm: oidSignatureSHA1WithRSA, - }, + Version: 1, + Signature: signatureAlgorithm, Issuer: c.Subject.ToRDNSequence(), ThisUpdate: now.UTC(), NextUpdate: expiry.UTC(), RevokedCertificates: revokedCerts, } + // Authority Key Id + if len(c.SubjectKeyId) > 0 { + var aki pkix.Extension + aki.Id = oidExtensionAuthorityKeyId + aki.Value, err = asn1.Marshal(authKeyId{Id: c.SubjectKeyId}) + if err != nil { + return + } + tbsCertList.Extensions = append(tbsCertList.Extensions, aki) + } + tbsCertListContents, err := asn1.Marshal(tbsCertList) if err != nil { return } - h := sha1.New() + h := hashFunc.New() h.Write(tbsCertListContents) digest := h.Sum(nil) - signature, err := rsa.SignPKCS1v15(rand, rsaPriv, crypto.SHA1, digest) + var signature []byte + signature, err = key.Sign(rand, digest, hashFunc) if err != nil { return } return asn1.Marshal(pkix.CertificateList{ - TBSCertList: tbsCertList, - SignatureAlgorithm: pkix.AlgorithmIdentifier{ - Algorithm: oidSignatureSHA1WithRSA, - }, - SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8}, + TBSCertList: tbsCertList, + SignatureAlgorithm: signatureAlgorithm, + SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8}, }) } @@ -1650,11 +1733,11 @@ type CertificateRequest struct { // signature requests (see RFC 2986): type tbsCertificateRequest struct { - Raw asn1.RawContent - Version int - Subject asn1.RawValue - PublicKey publicKeyInfo - Attributes []pkix.AttributeTypeAndValueSET `asn1:"tag:0"` + Raw asn1.RawContent + Version int + Subject asn1.RawValue + PublicKey publicKeyInfo + RawAttributes []asn1.RawValue `asn1:"tag:0"` } type certificateRequest struct { @@ -1668,6 +1751,36 @@ type certificateRequest struct { // extensions in a CSR. var oidExtensionRequest = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 14} +// newRawAttributes converts AttributeTypeAndValueSETs from a template +// CertificateRequest's Attributes into tbsCertificateRequest RawAttributes. +func newRawAttributes(attributes []pkix.AttributeTypeAndValueSET) ([]asn1.RawValue, error) { + var rawAttributes []asn1.RawValue + b, err := asn1.Marshal(attributes) + rest, err := asn1.Unmarshal(b, &rawAttributes) + if err != nil { + return nil, err + } + if len(rest) != 0 { + return nil, errors.New("x509: failed to unmarshall raw CSR Attributes") + } + return rawAttributes, nil +} + +// parseRawAttributes Unmarshals RawAttributes intos AttributeTypeAndValueSETs. +func parseRawAttributes(rawAttributes []asn1.RawValue) []pkix.AttributeTypeAndValueSET { + var attributes []pkix.AttributeTypeAndValueSET + for _, rawAttr := range rawAttributes { + var attr pkix.AttributeTypeAndValueSET + rest, err := asn1.Unmarshal(rawAttr.FullBytes, &attr) + // Ignore attributes that don't parse into pkix.AttributeTypeAndValueSET + // (i.e.: challengePassword or unstructuredName). + if err == nil && len(rest) == 0 { + attributes = append(attributes, attr) + } + } + return attributes +} + // CreateCertificateRequest creates a new certificate based on a template. The // following members of template are used: Subject, Attributes, // SignatureAlgorithm, Extensions, DNSNames, EmailAddresses, and IPAddresses. @@ -1675,26 +1788,24 @@ var oidExtensionRequest = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 14} // // The returned slice is the certificate request in DER encoding. // -// The only supported key types are RSA (*rsa.PrivateKey) and ECDSA -// (*ecdsa.PrivateKey). +// All keys types that are implemented via crypto.Signer are supported (This +// includes *rsa.PublicKey and *ecdsa.PublicKey.) func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv interface{}) (csr []byte, err error) { - hashFunc, sigAlgo, err := signingParamsForPrivateKey(priv, template.SignatureAlgorithm) + key, ok := priv.(crypto.Signer) + if !ok { + return nil, errors.New("x509: certificate private key does not implement crypto.Signer") + } + + var hashFunc crypto.Hash + var sigAlgo pkix.AlgorithmIdentifier + hashFunc, sigAlgo, err = signingParamsForPublicKey(key.Public(), template.SignatureAlgorithm) if err != nil { return nil, err } var publicKeyBytes []byte var publicKeyAlgorithm pkix.AlgorithmIdentifier - - switch priv := priv.(type) { - case *rsa.PrivateKey: - publicKeyBytes, publicKeyAlgorithm, err = marshalPublicKey(&priv.PublicKey) - case *ecdsa.PrivateKey: - publicKeyBytes, publicKeyAlgorithm, err = marshalPublicKey(&priv.PublicKey) - default: - panic("internal error") - } - + publicKeyBytes, publicKeyAlgorithm, err = marshalPublicKey(key.Public()) if err != nil { return nil, err } @@ -1782,6 +1893,11 @@ func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv } } + rawAttributes, err := newRawAttributes(attributes) + if err != nil { + return + } + tbsCSR := tbsCertificateRequest{ Version: 0, // PKCS #10, RFC 2986 Subject: asn1.RawValue{FullBytes: asn1Subject}, @@ -1792,7 +1908,7 @@ func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv BitLength: len(publicKeyBytes) * 8, }, }, - Attributes: attributes, + RawAttributes: rawAttributes, } tbsCSRContents, err := asn1.Marshal(tbsCSR) @@ -1806,18 +1922,7 @@ func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv digest := h.Sum(nil) var signature []byte - switch priv := priv.(type) { - case *rsa.PrivateKey: - signature, err = rsa.SignPKCS1v15(rand, priv, hashFunc, digest) - case *ecdsa.PrivateKey: - var r, s *big.Int - if r, s, err = ecdsa.Sign(rand, priv, digest); err == nil { - signature, err = asn1.Marshal(ecdsaSignature{r, s}) - } - default: - panic("internal error") - } - + signature, err = key.Sign(rand, digest, hashFunc) if err != nil { return } @@ -1860,7 +1965,7 @@ func parseCertificateRequest(in *certificateRequest) (*CertificateRequest, error PublicKeyAlgorithm: getPublicKeyAlgorithmFromOID(in.TBSCSR.PublicKey.Algorithm.Algorithm), Version: in.TBSCSR.Version, - Attributes: in.TBSCSR.Attributes, + Attributes: parseRawAttributes(in.TBSCSR.RawAttributes), } var err error @@ -1870,15 +1975,17 @@ func parseCertificateRequest(in *certificateRequest) (*CertificateRequest, error } var subject pkix.RDNSequence - if _, err := asn1.Unmarshal(in.TBSCSR.Subject.FullBytes, &subject); err != nil { + if rest, err := asn1.Unmarshal(in.TBSCSR.Subject.FullBytes, &subject); err != nil { return nil, err + } else if len(rest) != 0 { + return nil, errors.New("x509: trailing data after X.509 Subject") } out.Subject.FillFromRDNSequence(&subject) var extensions []pkix.AttributeTypeAndValue - for _, atvSet := range in.TBSCSR.Attributes { + for _, atvSet := range out.Attributes { if !atvSet.Type.Equal(oidExtensionRequest) { continue } @@ -1914,3 +2021,8 @@ func parseCertificateRequest(in *certificateRequest) (*CertificateRequest, error return out, nil } + +// CheckSignature verifies that the signature on c is a valid signature +func (c *CertificateRequest) CheckSignature() (err error) { + return checkSignature(c.SignatureAlgorithm, c.RawTBSCertificateRequest, c.Signature, c.PublicKey) +} diff --git a/libgo/go/crypto/x509/x509_test.go b/libgo/go/crypto/x509/x509_test.go index 4f1f0c2cc69..f4f9fa2f7f9 100644 --- a/libgo/go/crypto/x509/x509_test.go +++ b/libgo/go/crypto/x509/x509_test.go @@ -18,11 +18,11 @@ import ( "encoding/base64" "encoding/hex" "encoding/pem" + "internal/testenv" "math/big" "net" "os/exec" "reflect" - "runtime" "testing" "time" ) @@ -41,6 +41,13 @@ func TestParsePKCS1PrivateKey(t *testing.T) { priv.Primes[1].Cmp(rsaPrivateKey.Primes[1]) != 0 { t.Errorf("got:%+v want:%+v", priv, rsaPrivateKey) } + + // This private key includes an invalid prime that + // rsa.PrivateKey.Validate should reject. + data := []byte("0\x16\x02\x00\x02\x02\u007f\x00\x02\x0200\x02\x0200\x02\x02\x00\x01\x02\x02\u007f\x00") + if _, err := ParsePKCS1PrivateKey(data); err == nil { + t.Errorf("parsing invalid private key did not result in an error") + } } func TestParsePKIXPublicKey(t *testing.T) { @@ -162,17 +169,31 @@ var matchHostnamesTests = []matchHostnamesTest{ {"a.b.c", "", false}, {"example.com", "example.com", true}, {"example.com", "www.example.com", false}, + {"*.example.com", "example.com", false}, {"*.example.com", "www.example.com", true}, + {"*.example.com", "www.example.com.", true}, {"*.example.com", "xyz.www.example.com", false}, - {"*.*.example.com", "xyz.www.example.com", true}, - {"*.www.*.com", "xyz.www.example.com", true}, + {"*.*.example.com", "xyz.www.example.com", false}, + {"*.www.*.com", "xyz.www.example.com", false}, + {"*bar.example.com", "foobar.example.com", false}, + {"f*.example.com", "foobar.example.com", false}, + {"", ".", false}, + {".", "", false}, + {".", ".", false}, + {"example.com", "example.com.", true}, + {"example.com.", "example.com", true}, + {"example.com.", "example.com.", true}, + {"*.com.", "example.com.", true}, + {"*.com.", "example.com", true}, + {"*.com", "example.com", true}, + {"*.com", "example.com.", true}, } func TestMatchHostnames(t *testing.T) { for i, test := range matchHostnamesTests { r := matchHostnames(test.pattern, test.host) if r != test.ok { - t.Errorf("#%d mismatch got: %t want: %t", i, r, test.ok) + t.Errorf("#%d mismatch got: %t want: %t when matching '%s' against '%s'", i, r, test.ok, test.host, test.pattern) } } } @@ -326,6 +347,18 @@ func TestCreateSelfSignedCertificate(t *testing.T) { Subject: pkix.Name{ CommonName: commonName, Organization: []string{"Σ Acme Co"}, + Country: []string{"US"}, + ExtraNames: []pkix.AttributeTypeAndValue{ + { + Type: []int{2, 5, 4, 42}, + Value: "Gopher", + }, + // This should override the Country, above. + { + Type: []int{2, 5, 4, 6}, + Value: "NL", + }, + }, }, NotBefore: time.Unix(1000, 0), NotAfter: time.Unix(100000, 0), @@ -391,6 +424,21 @@ func TestCreateSelfSignedCertificate(t *testing.T) { t.Errorf("%s: subject wasn't correctly copied from the template. Got %s, want %s", test.name, cert.Subject.CommonName, commonName) } + if len(cert.Subject.Country) != 1 || cert.Subject.Country[0] != "NL" { + t.Errorf("%s: ExtraNames didn't override Country", test.name) + } + + found := false + for _, atv := range cert.Subject.Names { + if atv.Type.Equal([]int{2, 5, 4, 42}) { + found = true + break + } + } + if !found { + t.Errorf("%s: Names didn't contain oid 2.5.4.42 from ExtraNames", test.name) + } + if cert.Issuer.CommonName != commonName { t.Errorf("%s: issuer wasn't correctly copied from the template. Got %s, want %s", test.name, cert.Issuer.CommonName, commonName) } @@ -448,6 +496,74 @@ func TestCreateSelfSignedCertificate(t *testing.T) { } } +func TestUnknownCriticalExtension(t *testing.T) { + priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + if err != nil { + t.Fatalf("Failed to generate ECDSA key: %s", err) + } + + oids := []asn1.ObjectIdentifier{ + // This OID is in the PKIX arc, but unknown. + asn1.ObjectIdentifier{2, 5, 29, 999999}, + // This is a nonsense, unassigned OID. + asn1.ObjectIdentifier{1, 2, 3, 4}, + } + + for _, oid := range oids { + template := Certificate{ + SerialNumber: big.NewInt(1), + Subject: pkix.Name{ + CommonName: "foo", + }, + NotBefore: time.Unix(1000, 0), + NotAfter: time.Now().AddDate(1, 0, 0), + + BasicConstraintsValid: true, + IsCA: true, + + KeyUsage: KeyUsageCertSign, + ExtKeyUsage: []ExtKeyUsage{ExtKeyUsageServerAuth}, + + ExtraExtensions: []pkix.Extension{ + { + Id: oid, + Critical: true, + Value: nil, + }, + }, + } + + derBytes, err := CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv) + if err != nil { + t.Fatalf("failed to create certificate: %s", err) + } + + cert, err := ParseCertificate(derBytes) + if err != nil { + t.Fatalf("Certificate with unknown critical extension was not parsed: %s", err) + } + + roots := NewCertPool() + roots.AddCert(cert) + + // Setting Roots ensures that Verify won't delegate to the OS + // library and thus the correct error should always be + // returned. + _, err = cert.Verify(VerifyOptions{Roots: roots}) + if err == nil { + t.Fatal("Certificate with unknown critical extension was verified without error") + } + if _, ok := err.(UnhandledCriticalExtension); !ok { + t.Fatalf("Error was %#v, but wanted one of type UnhandledCriticalExtension", err) + } + + cert.UnhandledCriticalExtensions = nil + if _, err = cert.Verify(VerifyOptions{Roots: roots}); err != nil { + t.Errorf("Certificate failed to verify after unhandled critical extensions were cleared: %s", err) + } + } +} + // Self-signed certificate using ECDSA with SHA1 & secp256r1 var ecdsaSHA1CertPem = ` -----BEGIN CERTIFICATE----- @@ -739,11 +855,7 @@ func TestParsePEMCRL(t *testing.T) { } func TestImports(t *testing.T) { - t.Skip("gccgo does not have a go command") - switch runtime.GOOS { - case "android", "nacl": - t.Skipf("skipping on %s", runtime.GOOS) - } + testenv.MustHaveGoRun(t) if err := exec.Command("go", "run", "x509_test_import.go").Run(); err != nil { t.Errorf("failed to run x509_test_import.go: %s", err) @@ -813,6 +925,12 @@ func TestCreateCertificateRequest(t *testing.T) { continue } + err = out.CheckSignature() + if err != nil { + t.Errorf("%s: failed to check certificate request signature: %s", test.name, err) + continue + } + if out.Subject.CommonName != template.Subject.CommonName { t.Errorf("%s: output subject common name and template subject common name don't match", test.name) } else if len(out.Subject.Organization) != len(template.Subject.Organization) { @@ -924,33 +1042,35 @@ func TestCertificateRequestOverrides(t *testing.T) { } func TestParseCertificateRequest(t *testing.T) { - csrBytes := fromBase64(csrBase64) - csr, err := ParseCertificateRequest(csrBytes) - if err != nil { - t.Fatalf("failed to parse CSR: %s", err) - } + for _, csrBase64 := range csrBase64Array { + csrBytes := fromBase64(csrBase64) + csr, err := ParseCertificateRequest(csrBytes) + if err != nil { + t.Fatalf("failed to parse CSR: %s", err) + } - if len(csr.EmailAddresses) != 1 || csr.EmailAddresses[0] != "gopher@golang.org" { - t.Errorf("incorrect email addresses found: %v", csr.EmailAddresses) - } + if len(csr.EmailAddresses) != 1 || csr.EmailAddresses[0] != "gopher@golang.org" { + t.Errorf("incorrect email addresses found: %v", csr.EmailAddresses) + } - if len(csr.DNSNames) != 1 || csr.DNSNames[0] != "test.example.com" { - t.Errorf("incorrect DNS names found: %v", csr.DNSNames) - } + if len(csr.DNSNames) != 1 || csr.DNSNames[0] != "test.example.com" { + t.Errorf("incorrect DNS names found: %v", csr.DNSNames) + } - if len(csr.Subject.Country) != 1 || csr.Subject.Country[0] != "AU" { - t.Errorf("incorrect Subject name: %v", csr.Subject) - } + if len(csr.Subject.Country) != 1 || csr.Subject.Country[0] != "AU" { + t.Errorf("incorrect Subject name: %v", csr.Subject) + } - found := false - for _, e := range csr.Extensions { - if e.Id.Equal(oidExtensionBasicConstraints) { - found = true - break + found := false + for _, e := range csr.Extensions { + if e.Id.Equal(oidExtensionBasicConstraints) { + found = true + break + } + } + if !found { + t.Errorf("basic constraints extension not found in CSR") } - } - if !found { - t.Errorf("basic constraints extension not found in CSR") } } @@ -1017,12 +1137,42 @@ func TestMaxPathLen(t *testing.T) { } } -// This CSR was generated with OpenSSL: -// openssl req -out CSR.csr -new -newkey rsa:2048 -nodes -keyout privateKey.key -config openssl.cnf +func TestASN1BitLength(t *testing.T) { + tests := []struct { + bytes []byte + bitLen int + }{ + {nil, 0}, + {[]byte{0x00}, 0}, + {[]byte{0x00, 0x00}, 0}, + {[]byte{0xf0}, 4}, + {[]byte{0x88}, 5}, + {[]byte{0xff}, 8}, + {[]byte{0xff, 0x80}, 9}, + {[]byte{0xff, 0x81}, 16}, + } + + for i, test := range tests { + if got := asn1BitLength(test.bytes); got != test.bitLen { + t.Errorf("#%d: calculated bit-length of %d for %x, wanted %d", i, got, test.bytes, test.bitLen) + } + } +} + +// These CSR was generated with OpenSSL: +// openssl req -out CSR.csr -new -sha256 -nodes -keyout privateKey.key -config openssl.cnf // -// The openssl.cnf needs to include this section: +// With openssl.cnf containing the following sections: // [ v3_req ] // basicConstraints = CA:FALSE // keyUsage = nonRepudiation, digitalSignature, keyEncipherment // subjectAltName = email:gopher@golang.org,DNS:test.example.com -const csrBase64 = "MIIC4zCCAcsCAQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOY+MVedRg2JEnyeLcSzcsMv2VcsTfkB5+Etd6hihAh6MrGezNyASMMKuQN6YhCX1icQDiQtGsDLTtheNnSXK06tAhHjAP/hGlszRJp+5+rP2M58fDBAkUBEhskbCUWwpY14jFtVuGNJ8vF8h8IeczdolvQhX9lVai9G0EUXJMliMKdjA899H0mRs9PzHyidyrXFNiZlQXfD8Kg7gETn2Ny965iyI6ujAIYSCvam6TnxRHYH2MBKyVGvsYGbPYUQJCsgdgyajEg6ekihvQY3SzO1HSAlZAd7d1QYO4VeWJ2mY6Wu3Jpmh+AmG19S9CcHqGjd0bhuAX9cpPOKgnEmqn0CAwEAAaBZMFcGCSqGSIb3DQEJDjFKMEgwCQYDVR0TBAIwADALBgNVHQ8EBAMCBeAwLgYDVR0RBCcwJYERZ29waGVyQGdvbGFuZy5vcmeCEHRlc3QuZXhhbXBsZS5jb20wDQYJKoZIhvcNAQEFBQADggEBAC9+QpKfdabxwCWwf4IEe1cKjdXLS1ScSuw27a3kZzQiPV78WJMa6dB8dqhdH5BRwGZ/qsgLrO6ZHlNeIv2Ib41Ccq71ecHW/nXc94A1BzJ/bVdI9LZcmTUvR1/m1jCpN7UqQ0ml1u9VihK7Pe762hEYxuWDQzYEU0l15S/bXmqeq3eF1A59XT/2jwe5+NV0Wwf4UQlkTXsAQMsJ+KzrQafd8Qv2A49o048uRvmjeJDrXLawGVianZ7D5A6Fpd1rZh6XcjqBpmgLw41DRQWENOdzhy+HyphKRv1MlY8OLkNqpGMhu8DdgJVGoT16DGiickoEa7Z3UCPVNgdTkT9jq7U=" +// [ req_attributes ] +// challengePassword = ignored challenge +// unstructuredName = ignored unstructured name +var csrBase64Array = [...]string{ + // Just [ v3_req ] + "MIIDHDCCAgQCAQAwfjELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEUMBIGA1UEAwwLQ29tbW9uIE5hbWUxITAfBgkqhkiG9w0BCQEWEnRlc3RAZW1haWwuYWRkcmVzczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK1GY4YFx2ujlZEOJxQVYmsjUnLsd5nFVnNpLE4cV+77sgv9NPNlB8uhn3MXt5leD34rm/2BisCHOifPucYlSrszo2beuKhvwn4+2FxDmWtBEMu/QA16L5IvoOfYZm/gJTsPwKDqvaR0tTU67a9OtxwNTBMI56YKtmwd/o8d3hYv9cg+9ZGAZ/gKONcg/OWYx/XRh6bd0g8DMbCikpWgXKDsvvK1Nk+VtkDO1JxuBaj4Lz/p/MifTfnHoqHxWOWl4EaTs4Ychxsv34/rSj1KD1tJqorIv5Xv2aqv4sjxfbrYzX4kvS5SC1goIovLnhj5UjmQ3Qy8u65eow/LLWw+YFcCAwEAAaBZMFcGCSqGSIb3DQEJDjFKMEgwCQYDVR0TBAIwADALBgNVHQ8EBAMCBeAwLgYDVR0RBCcwJYERZ29waGVyQGdvbGFuZy5vcmeCEHRlc3QuZXhhbXBsZS5jb20wDQYJKoZIhvcNAQELBQADggEBAB6VPMRrchvNW61Tokyq3ZvO6/NoGIbuwUn54q6l5VZW0Ep5Nq8juhegSSnaJ0jrovmUgKDN9vEo2KxuAtwG6udS6Ami3zP+hRd4k9Q8djJPb78nrjzWiindLK5Fps9U5mMoi1ER8ViveyAOTfnZt/jsKUaRsscY2FzE9t9/o5moE6LTcHUS4Ap1eheR+J72WOnQYn3cifYaemsA9MJuLko+kQ6xseqttbh9zjqd9fiCSh/LNkzos9c+mg2yMADitaZinAh+HZi50ooEbjaT3erNq9O6RqwJlgD00g6MQdoz9bTAryCUhCQfkIaepmQ7BxS0pqWNW3MMwfDwx/Snz6g=", + // Both [ v3_req ] and [ req_attributes ] + "MIIDaTCCAlECAQAwfjELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEUMBIGA1UEAwwLQ29tbW9uIE5hbWUxITAfBgkqhkiG9w0BCQEWEnRlc3RAZW1haWwuYWRkcmVzczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK1GY4YFx2ujlZEOJxQVYmsjUnLsd5nFVnNpLE4cV+77sgv9NPNlB8uhn3MXt5leD34rm/2BisCHOifPucYlSrszo2beuKhvwn4+2FxDmWtBEMu/QA16L5IvoOfYZm/gJTsPwKDqvaR0tTU67a9OtxwNTBMI56YKtmwd/o8d3hYv9cg+9ZGAZ/gKONcg/OWYx/XRh6bd0g8DMbCikpWgXKDsvvK1Nk+VtkDO1JxuBaj4Lz/p/MifTfnHoqHxWOWl4EaTs4Ychxsv34/rSj1KD1tJqorIv5Xv2aqv4sjxfbrYzX4kvS5SC1goIovLnhj5UjmQ3Qy8u65eow/LLWw+YFcCAwEAAaCBpTAgBgkqhkiG9w0BCQcxEwwRaWdub3JlZCBjaGFsbGVuZ2UwKAYJKoZIhvcNAQkCMRsMGWlnbm9yZWQgdW5zdHJ1Y3R1cmVkIG5hbWUwVwYJKoZIhvcNAQkOMUowSDAJBgNVHRMEAjAAMAsGA1UdDwQEAwIF4DAuBgNVHREEJzAlgRFnb3BoZXJAZ29sYW5nLm9yZ4IQdGVzdC5leGFtcGxlLmNvbTANBgkqhkiG9w0BAQsFAAOCAQEAgxe2N5O48EMsYE7o0rZBB0wi3Ov5/yYfnmmVI22Y3sP6VXbLDW0+UWIeSccOhzUCcZ/G4qcrfhhx6gTZTeA01nP7TdTJURvWAH5iFqj9sQ0qnLq6nEcVHij3sG6M5+BxAIVClQBk6lTCzgphc835Fjj6qSLuJ20XHdL5UfUbiJxx299CHgyBRL+hBUIPfz8p+ZgamyAuDLfnj54zzcRVyLlrmMLNPZNll1Q70RxoU6uWvLH8wB8vQe3Q/guSGubLyLRTUQVPh+dw1L4t8MKFWfX/48jwRM4gIRHFHPeAAE9D9YAoqdIvj/iFm/eQ++7DP8MDwOZWsXeB6jjwHuLmkQ==", +} diff --git a/libgo/go/database/sql/fakedb_test.go b/libgo/go/database/sql/fakedb_test.go index a993fd46ede..8cbbb29a7c2 100644 --- a/libgo/go/database/sql/fakedb_test.go +++ b/libgo/go/database/sql/fakedb_test.go @@ -89,7 +89,10 @@ type fakeConn struct { stmtsMade int stmtsClosed int numPrepare int - bad bool + + // bad connection tests; see isBad() + bad bool + stickyBad bool } func (c *fakeConn) incrStat(v *int) { @@ -243,13 +246,15 @@ func (db *fakeDB) columnType(table, column string) (typ string, ok bool) { } func (c *fakeConn) isBad() bool { - // if not simulating bad conn, do nothing - if !c.bad { + if c.stickyBad { + return true + } else if c.bad { + // alternate between bad conn and not bad conn + c.db.badConn = !c.db.badConn + return c.db.badConn + } else { return false } - // alternate between bad conn and not bad conn - c.db.badConn = !c.db.badConn - return c.db.badConn } func (c *fakeConn) Begin() (driver.Tx, error) { @@ -466,7 +471,7 @@ func (c *fakeConn) Prepare(query string) (driver.Stmt, error) { panic("nil c.db; conn = " + fmt.Sprintf("%#v", c)) } - if hookPrepareBadConn != nil && hookPrepareBadConn() { + if c.stickyBad || (hookPrepareBadConn != nil && hookPrepareBadConn()) { return nil, driver.ErrBadConn } @@ -529,7 +534,7 @@ func (s *fakeStmt) Exec(args []driver.Value) (driver.Result, error) { return nil, errClosed } - if hookExecBadConn != nil && hookExecBadConn() { + if s.c.stickyBad || (hookExecBadConn != nil && hookExecBadConn()) { return nil, driver.ErrBadConn } @@ -613,7 +618,7 @@ func (s *fakeStmt) Query(args []driver.Value) (driver.Rows, error) { return nil, errClosed } - if hookQueryBadConn != nil && hookQueryBadConn() { + if s.c.stickyBad || (hookQueryBadConn != nil && hookQueryBadConn()) { return nil, driver.ErrBadConn } diff --git a/libgo/go/database/sql/sql.go b/libgo/go/database/sql/sql.go index 6e6f246aeec..aaa4ea28be4 100644 --- a/libgo/go/database/sql/sql.go +++ b/libgo/go/database/sql/sql.go @@ -6,10 +6,10 @@ // databases. // // The sql package must be used in conjunction with a database driver. -// See http://golang.org/s/sqldrivers for a list of drivers. +// See https://golang.org/s/sqldrivers for a list of drivers. // // For more usage examples, see the wiki page at -// http://golang.org/s/sqlwiki. +// https://golang.org/s/sqlwiki. package sql import ( @@ -20,14 +20,20 @@ import ( "runtime" "sort" "sync" + "sync/atomic" ) -var drivers = make(map[string]driver.Driver) +var ( + driversMu sync.Mutex + drivers = make(map[string]driver.Driver) +) // Register makes a database driver available by the provided name. // If Register is called twice with the same name or if driver is nil, // it panics. func Register(name string, driver driver.Driver) { + driversMu.Lock() + defer driversMu.Unlock() if driver == nil { panic("sql: Register driver is nil") } @@ -38,12 +44,16 @@ func Register(name string, driver driver.Driver) { } func unregisterAllDrivers() { + driversMu.Lock() + defer driversMu.Unlock() // For tests. drivers = make(map[string]driver.Driver) } // Drivers returns a sorted list of the names of the registered drivers. func Drivers() []string { + driversMu.Lock() + defer driversMu.Unlock() var list []string for name := range drivers { list = append(list, name) @@ -211,6 +221,10 @@ var ErrNoRows = errors.New("sql: no rows in result set") type DB struct { driver driver.Driver dsn string + // numClosed is an atomic counter which represents a total number of + // closed connections. Stmt.openStmt checks it before cleaning closed + // connections in Stmt.css. + numClosed uint64 mu sync.Mutex // protects following fields freeConn []*driverConn @@ -230,6 +244,18 @@ type DB struct { maxOpen int // <= 0 means unlimited } +// connReuseStrategy determines how (*DB).conn returns database connections. +type connReuseStrategy uint8 + +const ( + // alwaysNewConn forces a new connection to the database. + alwaysNewConn connReuseStrategy = iota + // cachedOrNewConn returns a cached connection, if available, else waits + // for one to become available (if MaxOpenConns has been reached) or + // creates a new database connection. + cachedOrNewConn +) + // driverConn wraps a driver.Conn with a mutex, to // be held during all calls into the Conn. (including any calls onto // interfaces returned via that Conn, such as calls on Tx, Stmt, @@ -246,7 +272,7 @@ type driverConn struct { // guarded by db.mu inUse bool onPut []func() // code (with db.mu held) run when conn is next returned - dbmuClosed bool // same as closed, but guarded by db.mu, for connIfFree + dbmuClosed bool // same as closed, but guarded by db.mu, for removeClosedStmtLocked } func (dc *driverConn) releaseConn(err error) { @@ -329,6 +355,7 @@ func (dc *driverConn) finalClose() error { dc.db.maybeOpenNewConnections() dc.db.mu.Unlock() + atomic.AddUint64(&dc.db.numClosed, 1) return err } @@ -427,7 +454,7 @@ var connectionRequestQueueSize = 1000000 // // Most users will open a database via a driver-specific connection // helper function that returns a *DB. No database drivers are included -// in the Go standard library. See http://golang.org/s/sqldrivers for +// in the Go standard library. See https://golang.org/s/sqldrivers for // a list of third-party drivers. // // Open may just validate its arguments without creating a connection @@ -439,7 +466,9 @@ var connectionRequestQueueSize = 1000000 // function should be called just once. It is rarely necessary to // close a DB. func Open(driverName, dataSourceName string) (*DB, error) { + driversMu.Lock() driveri, ok := drivers[driverName] + driversMu.Unlock() if !ok { return nil, fmt.Errorf("sql: unknown driver %q (forgotten import?)", driverName) } @@ -459,7 +488,7 @@ func (db *DB) Ping() error { // TODO(bradfitz): give drivers an optional hook to implement // this in a more efficient or more reliable way, if they // have one. - dc, err := db.conn() + dc, err := db.conn(cachedOrNewConn) if err != nil { return err } @@ -566,6 +595,22 @@ func (db *DB) SetMaxOpenConns(n int) { } } +// DBStats contains database statistics. +type DBStats struct { + // OpenConnections is the number of open connections to the database. + OpenConnections int +} + +// Stats returns database statistics. +func (db *DB) Stats() DBStats { + db.mu.Lock() + stats := DBStats{ + OpenConnections: db.numOpen, + } + db.mu.Unlock() + return stats +} + // Assumes db.mu is locked. // If there are connRequests and the connection limit hasn't been reached, // then tell the connectionOpener to open new connections. @@ -629,36 +674,37 @@ type connRequest struct { var errDBClosed = errors.New("sql: database is closed") -// conn returns a newly-opened or cached *driverConn -func (db *DB) conn() (*driverConn, error) { +// conn returns a newly-opened or cached *driverConn. +func (db *DB) conn(strategy connReuseStrategy) (*driverConn, error) { db.mu.Lock() if db.closed { db.mu.Unlock() return nil, errDBClosed } - // If db.maxOpen > 0 and the number of open connections is over the limit - // and there are no free connection, make a request and wait. - if db.maxOpen > 0 && db.numOpen >= db.maxOpen && len(db.freeConn) == 0 { + // Prefer a free connection, if possible. + numFree := len(db.freeConn) + if strategy == cachedOrNewConn && numFree > 0 { + conn := db.freeConn[0] + copy(db.freeConn, db.freeConn[1:]) + db.freeConn = db.freeConn[:numFree-1] + conn.inUse = true + db.mu.Unlock() + return conn, nil + } + + // Out of free connections or we were asked not to use one. If we're not + // allowed to open any more connections, make a request and wait. + if db.maxOpen > 0 && db.numOpen >= db.maxOpen { // Make the connRequest channel. It's buffered so that the // connectionOpener doesn't block while waiting for the req to be read. req := make(chan connRequest, 1) db.connRequests = append(db.connRequests, req) - db.maybeOpenNewConnections() db.mu.Unlock() ret := <-req return ret.conn, ret.err } - if c := len(db.freeConn); c > 0 { - conn := db.freeConn[0] - copy(db.freeConn, db.freeConn[1:]) - db.freeConn = db.freeConn[:c-1] - conn.inUse = true - db.mu.Unlock() - return conn, nil - } - db.numOpen++ // optimistically db.mu.Unlock() ci, err := db.driver.Open(db.dsn) @@ -684,42 +730,6 @@ var ( errConnBusy = errors.New("database/sql: internal sentinel error: conn is busy") ) -// connIfFree returns (wanted, nil) if wanted is still a valid conn and -// isn't in use. -// -// The error is errConnClosed if the connection if the requested connection -// is invalid because it's been closed. -// -// The error is errConnBusy if the connection is in use. -func (db *DB) connIfFree(wanted *driverConn) (*driverConn, error) { - db.mu.Lock() - defer db.mu.Unlock() - if wanted.dbmuClosed { - return nil, errConnClosed - } - if wanted.inUse { - return nil, errConnBusy - } - idx := -1 - for ii, v := range db.freeConn { - if v == wanted { - idx = ii - break - } - } - if idx >= 0 { - db.freeConn = append(db.freeConn[:idx], db.freeConn[idx+1:]...) - wanted.inUse = true - return wanted, nil - } - // TODO(bradfitz): shouldn't get here. After Go 1.1, change this to: - // panic("connIfFree call requested a non-closed, non-busy, non-free conn") - // Which passes all the tests, but I'm too paranoid to include this - // late in Go 1.1. - // Instead, treat it like a busy connection: - return nil, errConnBusy -} - // putConnHook is a hook for testing. var putConnHook func(*DB, *driverConn) @@ -797,6 +807,9 @@ func (db *DB) putConn(dc *driverConn, err error) { // If a connRequest was fulfilled or the *driverConn was placed in the // freeConn list, then true is returned, otherwise false is returned. func (db *DB) putConnDBLocked(dc *driverConn, err error) bool { + if db.maxOpen > 0 && db.numOpen > db.maxOpen { + return false + } if c := len(db.connRequests); c > 0 { req := db.connRequests[0] // This copy is O(n) but in practice faster than a linked list. @@ -820,32 +833,38 @@ func (db *DB) putConnDBLocked(dc *driverConn, err error) bool { } // maxBadConnRetries is the number of maximum retries if the driver returns -// driver.ErrBadConn to signal a broken connection. -const maxBadConnRetries = 10 +// driver.ErrBadConn to signal a broken connection before forcing a new +// connection to be opened. +const maxBadConnRetries = 2 // Prepare creates a prepared statement for later queries or executions. // Multiple queries or executions may be run concurrently from the // returned statement. +// The caller must call the statement's Close method +// when the statement is no longer needed. func (db *DB) Prepare(query string) (*Stmt, error) { var stmt *Stmt var err error for i := 0; i < maxBadConnRetries; i++ { - stmt, err = db.prepare(query) + stmt, err = db.prepare(query, cachedOrNewConn) if err != driver.ErrBadConn { break } } + if err == driver.ErrBadConn { + return db.prepare(query, alwaysNewConn) + } return stmt, err } -func (db *DB) prepare(query string) (*Stmt, error) { +func (db *DB) prepare(query string, strategy connReuseStrategy) (*Stmt, 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 // to a connection, and to execute this prepared statement // we either need to use this connection (if it's free), else // get a new connection + re-prepare + execute on that one. - dc, err := db.conn() + dc, err := db.conn(strategy) if err != nil { return nil, err } @@ -857,9 +876,10 @@ func (db *DB) prepare(query string) (*Stmt, error) { return nil, err } stmt := &Stmt{ - db: db, - query: query, - css: []connStmt{{dc, si}}, + db: db, + query: query, + css: []connStmt{{dc, si}}, + lastNumClosed: atomic.LoadUint64(&db.numClosed), } db.addDep(stmt, stmt) db.putConn(dc, nil) @@ -872,16 +892,19 @@ func (db *DB) Exec(query string, args ...interface{}) (Result, error) { var res Result var err error for i := 0; i < maxBadConnRetries; i++ { - res, err = db.exec(query, args) + res, err = db.exec(query, args, cachedOrNewConn) if err != driver.ErrBadConn { break } } + if err == driver.ErrBadConn { + return db.exec(query, args, alwaysNewConn) + } return res, err } -func (db *DB) exec(query string, args []interface{}) (res Result, err error) { - dc, err := db.conn() +func (db *DB) exec(query string, args []interface{}, strategy connReuseStrategy) (res Result, err error) { + dc, err := db.conn(strategy) if err != nil { return nil, err } @@ -921,16 +944,19 @@ func (db *DB) Query(query string, args ...interface{}) (*Rows, error) { var rows *Rows var err error for i := 0; i < maxBadConnRetries; i++ { - rows, err = db.query(query, args) + rows, err = db.query(query, args, cachedOrNewConn) if err != driver.ErrBadConn { break } } + if err == driver.ErrBadConn { + return db.query(query, args, alwaysNewConn) + } return rows, err } -func (db *DB) query(query string, args []interface{}) (*Rows, error) { - ci, err := db.conn() +func (db *DB) query(query string, args []interface{}, strategy connReuseStrategy) (*Rows, error) { + ci, err := db.conn(strategy) if err != nil { return nil, err } @@ -1009,16 +1035,19 @@ func (db *DB) Begin() (*Tx, error) { var tx *Tx var err error for i := 0; i < maxBadConnRetries; i++ { - tx, err = db.begin() + tx, err = db.begin(cachedOrNewConn) if err != driver.ErrBadConn { break } } + if err == driver.ErrBadConn { + return db.begin(alwaysNewConn) + } return tx, err } -func (db *DB) begin() (tx *Tx, err error) { - dc, err := db.conn() +func (db *DB) begin(strategy connReuseStrategy) (tx *Tx, err error) { + dc, err := db.conn(strategy) if err != nil { return nil, err } @@ -1047,6 +1076,10 @@ func (db *DB) Driver() driver.Driver { // // After a call to Commit or Rollback, all operations on the // transaction fail with ErrTxDone. +// +// The statements prepared for a transaction by calling +// the transaction's Prepare or Stmt methods are closed +// by the call to Commit or Rollback. type Tx struct { db *DB @@ -1182,6 +1215,9 @@ func (tx *Tx) Prepare(query string) (*Stmt, error) { // tx, err := db.Begin() // ... // res, err := tx.Stmt(updateMoney).Exec(123.45, 98293203) +// +// The returned statement operates within the transaction and can no longer +// be used once the transaction has been committed or rolled back. func (tx *Tx) Stmt(stmt *Stmt) *Stmt { // TODO(bradfitz): optimize this. Currently this re-prepares // each time. This is fine for now to illustrate the API but @@ -1273,7 +1309,8 @@ type connStmt struct { si driver.Stmt } -// Stmt is a prepared statement. Stmt is safe for concurrent use by multiple goroutines. +// Stmt is a prepared statement. +// A Stmt is safe for concurrent use by multiple goroutines. type Stmt struct { // Immutable: db *DB // where we came from @@ -1294,6 +1331,10 @@ type Stmt struct { // used if tx == nil and one is found that has idle // connections. If tx != nil, txsi is always used. css []connStmt + + // lastNumClosed is copied from db.numClosed when Stmt is created + // without tx and closed connections in css are removed. + lastNumClosed uint64 } // Exec executes a prepared statement with the given arguments and @@ -1347,6 +1388,32 @@ func resultFromStatement(ds driverStmt, args ...interface{}) (Result, error) { return driverResult{ds.Locker, resi}, nil } +// removeClosedStmtLocked removes closed conns in s.css. +// +// To avoid lock contention on DB.mu, we do it only when +// s.db.numClosed - s.lastNum is large enough. +func (s *Stmt) removeClosedStmtLocked() { + t := len(s.css)/2 + 1 + if t > 10 { + t = 10 + } + dbClosed := atomic.LoadUint64(&s.db.numClosed) + if dbClosed-s.lastNumClosed < uint64(t) { + return + } + + s.db.mu.Lock() + for i := 0; i < len(s.css); i++ { + if s.css[i].dc.dbmuClosed { + s.css[i] = s.css[len(s.css)-1] + s.css = s.css[:len(s.css)-1] + i-- + } + } + s.db.mu.Unlock() + s.lastNumClosed = dbClosed +} + // 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. @@ -1373,35 +1440,15 @@ func (s *Stmt) connStmt() (ci *driverConn, releaseConn func(error), si driver.St return ci, releaseConn, s.txsi.si, nil } - for i := 0; i < len(s.css); i++ { - v := s.css[i] - _, err := s.db.connIfFree(v.dc) - if err == nil { - s.mu.Unlock() - return v.dc, v.dc.releaseConn, v.si, nil - } - if err == errConnClosed { - // Lazily remove dead conn from our freelist. - s.css[i] = s.css[len(s.css)-1] - s.css = s.css[:len(s.css)-1] - i-- - } - - } + s.removeClosedStmtLocked() s.mu.Unlock() - // If all connections are busy, either wait for one to become available (if - // we've already hit the maximum number of open connections) or create a - // new one. - // // TODO(bradfitz): or always wait for one? make configurable later? - dc, err := s.db.conn() + dc, err := s.db.conn(cachedOrNewConn) if err != nil { return nil, nil, nil, err } - // Do another pass over the list to see whether this statement has - // already been prepared on the connection assigned to us. s.mu.Lock() for _, v := range s.css { if v.dc == dc { diff --git a/libgo/go/database/sql/sql_test.go b/libgo/go/database/sql/sql_test.go index 34efdf254c6..432a641b855 100644 --- a/libgo/go/database/sql/sql_test.go +++ b/libgo/go/database/sql/sql_test.go @@ -497,7 +497,7 @@ func TestTxStmt(t *testing.T) { } } -// Issue: http://golang.org/issue/2784 +// Issue: https://golang.org/issue/2784 // This test didn't fail before because we got lucky with the fakedb driver. // It was failing, and now not, in github.com/bradfitz/go-sql-test func TestTxQuery(t *testing.T) { @@ -1070,6 +1070,57 @@ func TestMaxOpenConns(t *testing.T) { } } +// Issue 9453: tests that SetMaxOpenConns can be lowered at runtime +// and affects the subsequent release of connections. +func TestMaxOpenConnsOnBusy(t *testing.T) { + defer setHookpostCloseConn(nil) + setHookpostCloseConn(func(_ *fakeConn, err error) { + if err != nil { + t.Errorf("Error closing fakeConn: %v", err) + } + }) + + db := newTestDB(t, "magicquery") + defer closeDB(t, db) + + db.SetMaxOpenConns(3) + + conn0, err := db.conn(cachedOrNewConn) + if err != nil { + t.Fatalf("db open conn fail: %v", err) + } + + conn1, err := db.conn(cachedOrNewConn) + if err != nil { + t.Fatalf("db open conn fail: %v", err) + } + + conn2, err := db.conn(cachedOrNewConn) + if err != nil { + t.Fatalf("db open conn fail: %v", err) + } + + if g, w := db.numOpen, 3; g != w { + t.Errorf("free conns = %d; want %d", g, w) + } + + db.SetMaxOpenConns(2) + if g, w := db.numOpen, 3; g != w { + t.Errorf("free conns = %d; want %d", g, w) + } + + conn0.releaseConn(nil) + conn1.releaseConn(nil) + if g, w := db.numOpen, 2; g != w { + t.Errorf("free conns = %d; want %d", g, w) + } + + conn2.releaseConn(nil) + if g, w := db.numOpen, 2; g != w { + t.Errorf("free conns = %d; want %d", g, w) + } +} + func TestSingleOpenConn(t *testing.T) { db := newTestDB(t, "people") defer closeDB(t, db) @@ -1093,6 +1144,26 @@ func TestSingleOpenConn(t *testing.T) { } } +func TestStats(t *testing.T) { + db := newTestDB(t, "people") + stats := db.Stats() + if got := stats.OpenConnections; got != 1 { + t.Errorf("stats.OpenConnections = %d; want 1", got) + } + + tx, err := db.Begin() + if err != nil { + t.Fatal(err) + } + tx.Commit() + + closeDB(t, db) + stats = db.Stats() + if got := stats.OpenConnections; got != 0 { + t.Errorf("stats.OpenConnections = %d; want 0", got) + } +} + // golang.org/issue/5323 func TestStmtCloseDeps(t *testing.T) { if testing.Short() { @@ -1314,7 +1385,80 @@ func TestStmtCloseOrder(t *testing.T) { } } -// golang.org/issue/5781 +// Test cases where there's more than maxBadConnRetries bad connections in the +// pool (issue 8834) +func TestManyErrBadConn(t *testing.T) { + manyErrBadConnSetup := func() *DB { + db := newTestDB(t, "people") + + nconn := maxBadConnRetries + 1 + db.SetMaxIdleConns(nconn) + db.SetMaxOpenConns(nconn) + // open enough connections + func() { + for i := 0; i < nconn; i++ { + rows, err := db.Query("SELECT|people|age,name|") + if err != nil { + t.Fatal(err) + } + defer rows.Close() + } + }() + + if db.numOpen != nconn { + t.Fatalf("unexpected numOpen %d (was expecting %d)", db.numOpen, nconn) + } else if len(db.freeConn) != nconn { + t.Fatalf("unexpected len(db.freeConn) %d (was expecting %d)", len(db.freeConn), nconn) + } + for _, conn := range db.freeConn { + conn.ci.(*fakeConn).stickyBad = true + } + return db + } + + // Query + db := manyErrBadConnSetup() + defer closeDB(t, db) + rows, err := db.Query("SELECT|people|age,name|") + if err != nil { + t.Fatal(err) + } + if err = rows.Close(); err != nil { + t.Fatal(err) + } + + // Exec + db = manyErrBadConnSetup() + defer closeDB(t, db) + _, err = db.Exec("INSERT|people|name=Julia,age=19") + if err != nil { + t.Fatal(err) + } + + // Begin + db = manyErrBadConnSetup() + defer closeDB(t, db) + tx, err := db.Begin() + if err != nil { + t.Fatal(err) + } + if err = tx.Rollback(); err != nil { + t.Fatal(err) + } + + // Prepare + db = manyErrBadConnSetup() + defer closeDB(t, db) + stmt, err := db.Prepare("SELECT|people|age,name|") + if err != nil { + t.Fatal(err) + } + if err = stmt.Close(); err != nil { + t.Fatal(err) + } +} + +// golang.org/issue/5718 func TestErrBadConnReconnect(t *testing.T) { db := newTestDB(t, "foo") defer closeDB(t, db) @@ -1764,56 +1908,6 @@ func doConcurrentTest(t testing.TB, ct concurrentTest) { wg.Wait() } -func manyConcurrentQueries(t testing.TB) { - maxProcs, numReqs := 16, 500 - if testing.Short() { - maxProcs, numReqs = 4, 50 - } - defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(maxProcs)) - - db := newTestDB(t, "people") - defer closeDB(t, db) - - stmt, err := db.Prepare("SELECT|people|name|") - if err != nil { - t.Fatal(err) - } - defer stmt.Close() - - var wg sync.WaitGroup - wg.Add(numReqs) - - reqs := make(chan bool) - defer close(reqs) - - for i := 0; i < maxProcs*2; i++ { - go func() { - for range reqs { - rows, err := stmt.Query() - if err != nil { - t.Errorf("error on query: %v", err) - wg.Done() - continue - } - - var name string - for rows.Next() { - rows.Scan(&name) - } - rows.Close() - - wg.Done() - } - }() - } - - for i := 0; i < numReqs; i++ { - reqs <- true - } - - wg.Wait() -} - func TestIssue6081(t *testing.T) { db := newTestDB(t, "people") defer closeDB(t, db) @@ -1985,3 +2079,31 @@ func BenchmarkConcurrentRandom(b *testing.B) { doConcurrentTest(b, ct) } } + +func BenchmarkManyConcurrentQueries(b *testing.B) { + b.ReportAllocs() + // To see lock contention in Go 1.4, 16~ cores and 128~ goroutines are required. + const parallelism = 16 + + db := newTestDB(b, "magicquery") + defer closeDB(b, db) + db.SetMaxIdleConns(runtime.GOMAXPROCS(0) * parallelism) + + stmt, err := db.Prepare("SELECT|magicquery|op|op=?,millis=?") + if err != nil { + b.Fatal(err) + } + defer stmt.Close() + + b.SetParallelism(parallelism) + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + rows, err := stmt.Query("sleep", 1) + if err != nil { + b.Error(err) + return + } + rows.Close() + } + }) +} diff --git a/libgo/go/debug/dwarf/buf.go b/libgo/go/debug/dwarf/buf.go index 53c46eb4b81..2ade0bd76ad 100644 --- a/libgo/go/debug/dwarf/buf.go +++ b/libgo/go/debug/dwarf/buf.go @@ -163,6 +163,17 @@ func (b *buf) addr() uint64 { return 0 } +func (b *buf) unitLength() (length Offset, dwarf64 bool) { + length = Offset(b.uint32()) + if length == 0xffffffff { + dwarf64 = true + length = Offset(b.uint64()) + } else if length >= 0xfffffff0 { + b.error("unit length has reserved value") + } + return +} + func (b *buf) error(s string) { if b.err == nil { b.data = nil diff --git a/libgo/go/debug/dwarf/class_string.go b/libgo/go/debug/dwarf/class_string.go new file mode 100644 index 00000000000..0b1206b9f3d --- /dev/null +++ b/libgo/go/debug/dwarf/class_string.go @@ -0,0 +1,17 @@ +// generated by stringer -type=Class; DO NOT EDIT + +package dwarf + +import "fmt" + +const _Class_name = "ClassAddressClassBlockClassConstantClassExprLocClassFlagClassLinePtrClassLocListPtrClassMacPtrClassRangeListPtrClassReferenceClassReferenceSigClassStringClassReferenceAltClassStringAlt" + +var _Class_index = [...]uint8{0, 12, 22, 35, 47, 56, 68, 83, 94, 111, 125, 142, 153, 170, 184} + +func (i Class) String() string { + i -= 1 + if i < 0 || i+1 >= Class(len(_Class_index)) { + return fmt.Sprintf("Class(%d)", i+1) + } + return _Class_name[_Class_index[i]:_Class_index[i+1]] +} diff --git a/libgo/go/debug/dwarf/const.go b/libgo/go/debug/dwarf/const.go index 6cc6bc937a5..2170db1e32d 100644 --- a/libgo/go/debug/dwarf/const.go +++ b/libgo/go/debug/dwarf/const.go @@ -453,29 +453,30 @@ const ( encImaginaryFloat = 0x09 ) -// Line number opcodes. +// Statement program standard opcode encodings. const ( - LineExtendedOp = 0 - LineCopy = 1 - LineAdvancePC = 2 - LineAdvanceLine = 3 - LineSetFile = 4 - LineSetColumn = 5 - LineNegateStmt = 6 - LineSetBasicBlock = 7 - LineConstAddPC = 8 - LineFixedAdvancePC = 9 - // next 3 are DWARF 3 - LineSetPrologueEnd = 10 - LineSetEpilogueBegin = 11 - LineSetISA = 12 + lnsCopy = 1 + lnsAdvancePC = 2 + lnsAdvanceLine = 3 + lnsSetFile = 4 + lnsSetColumn = 5 + lnsNegateStmt = 6 + lnsSetBasicBlock = 7 + lnsConstAddPC = 8 + lnsFixedAdvancePC = 9 + + // DWARF 3 + lnsSetPrologueEnd = 10 + lnsSetEpilogueBegin = 11 + lnsSetISA = 12 ) -// Line number extended opcodes. +// Statement program extended opcode encodings. const ( - LineExtEndSequence = 1 - LineExtSetAddress = 2 - LineExtDefineFile = 3 - // next 1 is DWARF 4 - LineExtSetDiscriminator = 4 + lneEndSequence = 1 + lneSetAddress = 2 + lneDefineFile = 3 + + // DWARF 4 + lneSetDiscriminator = 4 ) diff --git a/libgo/go/debug/dwarf/entry.go b/libgo/go/debug/dwarf/entry.go index b6ba8c0d1c3..d607e5b4a38 100644 --- a/libgo/go/debug/dwarf/entry.go +++ b/libgo/go/debug/dwarf/entry.go @@ -23,8 +23,9 @@ type abbrev struct { } type afield struct { - attr Attr - fmt format + attr Attr + fmt format + class Class } // a map from entry format ids to their descriptions @@ -32,7 +33,7 @@ type abbrevTable map[uint32]abbrev // ParseAbbrev returns the abbreviation table that starts at byte off // in the .debug_abbrev section. -func (d *Data) parseAbbrev(off uint32) (abbrevTable, error) { +func (d *Data) parseAbbrev(off uint32, vers int) (abbrevTable, error) { if m, ok := d.abbrevCache[off]; ok { return m, nil } @@ -80,6 +81,7 @@ func (d *Data) parseAbbrev(off uint32) (abbrevTable, error) { for i := range a.field { a.field[i].attr = Attr(b.uint()) a.field[i].fmt = format(b.uint()) + a.field[i].class = formToClass(a.field[i].fmt, a.field[i].attr, vers, &b) } b.uint() b.uint() @@ -93,6 +95,118 @@ func (d *Data) parseAbbrev(off uint32) (abbrevTable, error) { return m, nil } +// attrIsExprloc indicates attributes that allow exprloc values that +// are encoded as block values in DWARF 2 and 3. See DWARF 4, Figure +// 20. +var attrIsExprloc = map[Attr]bool{ + AttrLocation: true, + AttrByteSize: true, + AttrBitOffset: true, + AttrBitSize: true, + AttrStringLength: true, + AttrLowerBound: true, + AttrReturnAddr: true, + AttrStrideSize: true, + AttrUpperBound: true, + AttrCount: true, + AttrDataMemberLoc: true, + AttrFrameBase: true, + AttrSegment: true, + AttrStaticLink: true, + AttrUseLocation: true, + AttrVtableElemLoc: true, + AttrAllocated: true, + AttrAssociated: true, + AttrDataLocation: true, + AttrStride: true, +} + +// attrPtrClass indicates the *ptr class of attributes that have +// encoding formSecOffset in DWARF 4 or formData* in DWARF 2 and 3. +var attrPtrClass = map[Attr]Class{ + AttrLocation: ClassLocListPtr, + AttrStmtList: ClassLinePtr, + AttrStringLength: ClassLocListPtr, + AttrReturnAddr: ClassLocListPtr, + AttrStartScope: ClassRangeListPtr, + AttrDataMemberLoc: ClassLocListPtr, + AttrFrameBase: ClassLocListPtr, + AttrMacroInfo: ClassMacPtr, + AttrSegment: ClassLocListPtr, + AttrStaticLink: ClassLocListPtr, + AttrUseLocation: ClassLocListPtr, + AttrVtableElemLoc: ClassLocListPtr, + AttrRanges: ClassRangeListPtr, +} + +// formToClass returns the DWARF 4 Class for the given form. If the +// DWARF version is less then 4, it will disambiguate some forms +// depending on the attribute. +func formToClass(form format, attr Attr, vers int, b *buf) Class { + switch form { + default: + b.error("cannot determine class of unknown attribute form") + return 0 + + case formAddr: + return ClassAddress + + case formDwarfBlock1, formDwarfBlock2, formDwarfBlock4, formDwarfBlock: + // In DWARF 2 and 3, ClassExprLoc was encoded as a + // block. DWARF 4 distinguishes ClassBlock and + // ClassExprLoc, but there are no attributes that can + // be both, so we also promote ClassBlock values in + // DWARF 4 that should be ClassExprLoc in case + // producers get this wrong. + if attrIsExprloc[attr] { + return ClassExprLoc + } + return ClassBlock + + case formData1, formData2, formData4, formData8, formSdata, formUdata: + // In DWARF 2 and 3, ClassPtr was encoded as a + // constant. Unlike ClassExprLoc/ClassBlock, some + // DWARF 4 attributes need to distinguish Class*Ptr + // from ClassConstant, so we only do this promotion + // for versions 2 and 3. + if class, ok := attrPtrClass[attr]; vers < 4 && ok { + return class + } + return ClassConstant + + case formFlag, formFlagPresent: + return ClassFlag + + case formRefAddr, formRef1, formRef2, formRef4, formRef8, formRefUdata: + return ClassReference + + case formRefSig8: + return ClassReferenceSig + + case formString, formStrp: + return ClassString + + case formSecOffset: + // DWARF 4 defines four *ptr classes, but doesn't + // distinguish them in the encoding. Disambiguate + // these classes using the attribute. + if class, ok := attrPtrClass[attr]; ok { + return class + } + b.error("cannot determine class of unknown attribute with formSecOffset") + return 0 + + case formExprloc: + return ClassExprLoc + + case formGnuRefAlt: + return ClassReferenceAlt + + case formGnuStrpAlt: + return ClassStringAlt + } +} + // An entry is a sequence of attribute/value pairs. type Entry struct { Offset Offset // offset of Entry in DWARF info @@ -102,9 +216,115 @@ type Entry struct { } // A Field is a single attribute/value pair in an Entry. +// +// A value can be one of several "attribute classes" defined by DWARF. +// The Go types corresponding to each class are: +// +// DWARF class Go type Class +// ----------- ------- ----- +// address uint64 ClassAddress +// block []byte ClassBlock +// constant int64 ClassConstant +// flag bool ClassFlag +// reference +// to info dwarf.Offset ClassReference +// to type unit uint64 ClassReferenceSig +// string string ClassString +// exprloc []byte ClassExprLoc +// lineptr int64 ClassLinePtr +// loclistptr int64 ClassLocListPtr +// macptr int64 ClassMacPtr +// rangelistptr int64 ClassRangeListPtr type Field struct { - Attr Attr - Val interface{} + Attr Attr + Val interface{} + Class Class +} + +// A Class is the DWARF 4 class of an attibute value. +// +// In general, a given attribute's value may take on one of several +// possible classes defined by DWARF, each of which leads to a +// slightly different interpretation of the attribute. +// +// DWARF version 4 distinguishes attribute value classes more finely +// than previous versions of DWARF. The reader will disambiguate +// coarser classes from earlier versions of DWARF into the appropriate +// DWARF 4 class. For example, DWARF 2 uses "constant" for constants +// as well as all types of section offsets, but the reader will +// canonicalize attributes in DWARF 2 files that refer to section +// offsets to one of the Class*Ptr classes, even though these classes +// were only defined in DWARF 3. +type Class int + +const ( + // ClassAddress represents values of type uint64 that are + // addresses on the target machine. + ClassAddress Class = 1 + iota + + // ClassBlock represents values of type []byte whose + // interpretation depends on the attribute. + ClassBlock + + // ClassConstant represents values of type int64 that are + // constants. The interpretation of this constant depends on + // the attribute. + ClassConstant + + // ClassExprLoc represents values of type []byte that contain + // an encoded DWARF expression or location description. + ClassExprLoc + + // ClassFlag represents values of type bool. + ClassFlag + + // ClassLinePtr represents values that are an int64 offset + // into the "line" section. + ClassLinePtr + + // ClassLocListPtr represents values that are an int64 offset + // into the "loclist" section. + ClassLocListPtr + + // ClassMacPtr represents values that are an int64 offset into + // the "mac" section. + ClassMacPtr + + // ClassMacPtr represents values that are an int64 offset into + // the "rangelist" section. + ClassRangeListPtr + + // ClassReference represents values that are an Offset offset + // of an Entry in the info section (for use with Reader.Seek). + // The DWARF specification combines ClassReference and + // ClassReferenceSig into class "reference". + ClassReference + + // ClassReferenceSig represents values that are a uint64 type + // signature referencing a type Entry. + ClassReferenceSig + + // ClassString represents values that are strings. If the + // compilation unit specifies the AttrUseUTF8 flag (strongly + // recommended), the string value will be encoded in UTF-8. + // Otherwise, the encoding is unspecified. + ClassString + + // ClassReferenceAlt represents values of type int64 that are + // an offset into the DWARF "info" section of an alternate + // object file. + ClassReferenceAlt + + // ClassStringAlt represents values of type int64 that are an + // offset into the DWARF string section of an alternate object + // file. + ClassStringAlt +) + +//go:generate stringer -type=Class + +func (i Class) GoString() string { + return "dwarf." + i.String() } // Val returns the value associated with attribute Attr in Entry, @@ -112,12 +332,21 @@ type Field struct { // // A common idiom is to merge the check for nil return with // the check that the value has the expected dynamic type, as in: -// v, ok := e.Val(AttrSibling).(int64); +// v, ok := e.Val(AttrSibling).(int64) // func (e *Entry) Val(a Attr) interface{} { - for _, f := range e.Field { + if f := e.AttrField(a); f != nil { + return f.Val + } + return nil +} + +// AttrField returns the Field associated with attribute Attr in +// Entry, or nil if there is no such attribute. +func (e *Entry) AttrField(a Attr) *Field { + for i, f := range e.Field { if f.Attr == a { - return f.Val + return &e.Field[i] } } return nil @@ -148,6 +377,7 @@ func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry { } for i := range e.Field { e.Field[i].Attr = a.field[i].attr + e.Field[i].Class = a.field[i].class fmt := a.field[i].fmt if fmt == formIndirect { fmt = format(b.uint()) @@ -292,13 +522,10 @@ func (d *Data) Reader() *Reader { return r } -// unitReader returns a new reader starting at a specific unit. -func (d *Data) unitReader(i int) *Reader { - r := &Reader{d: d} - r.unit = i - u := &d.unit[i] - r.b = makeBuf(d, u, "info", u.off, u.data) - return r +// AddressSize returns the size in bytes of addresses in the current compilation +// unit. +func (r *Reader) AddressSize() int { + return r.d.unit[r.unit].asize } // Seek positions the Reader at offset off in the encoded entry stream. @@ -317,18 +544,14 @@ func (r *Reader) Seek(off Offset) { return } - // TODO(rsc): binary search (maybe a new package) - var i int - var u *unit - for i = range d.unit { - u = &d.unit[i] - if u.off <= off && off < u.off+Offset(len(u.data)) { - r.unit = i - r.b = makeBuf(r.d, u, "info", off, u.data[off-u.off:]) - return - } + i := d.offsetToUnit(off) + if i == -1 { + r.err = errors.New("offset out of range") + return } - r.err = errors.New("offset out of range") + u := &d.unit[i] + r.unit = i + r.b = makeBuf(r.d, u, "info", off, u.data[off-u.off:]) } // maybeNextUnit advances to the next unit if this one is finished. diff --git a/libgo/go/debug/dwarf/line.go b/libgo/go/debug/dwarf/line.go index c463c3b0d8f..ca64bbd7f3b 100644 --- a/libgo/go/debug/dwarf/line.go +++ b/libgo/go/debug/dwarf/line.go @@ -1,481 +1,590 @@ -// Copyright 2012 The Go Authors. All rights reserved. +// Copyright 2015 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. -// DWARF line number information. - package dwarf import ( "errors" - "path/filepath" - "sort" - "strconv" + "fmt" + "io" + "path" ) -// A Line holds all the available information about the source code -// corresponding to a specific program counter address. -type Line struct { - Filename string // source file name - OpIndex int // index of operation in VLIW instruction - Line int // line number - Column int // column number - ISA int // instruction set code - Discriminator int // block discriminator - Stmt bool // instruction starts statement - Block bool // instruction starts basic block - EndPrologue bool // instruction ends function prologue - BeginEpilogue bool // instruction begins function epilogue +// A LineReader reads a sequence of LineEntry structures from a DWARF +// "line" section for a single compilation unit. LineEntries occur in +// order of increasing PC and each LineEntry gives metadata for the +// instructions from that LineEntry's PC to just before the next +// LineEntry's PC. The last entry will have its EndSequence field set. +type LineReader struct { + buf buf + + // Original .debug_line section data. Used by Seek. + section []byte + + // Header information + version uint16 + minInstructionLength int + maxOpsPerInstruction int + defaultIsStmt bool + lineBase int + lineRange int + opcodeBase int + opcodeLengths []int + directories []string + fileEntries []*LineFile + + programOffset Offset // section offset of line number program + endOffset Offset // section offset of byte following program + + initialFileEntries int // initial length of fileEntries + + // Current line number program state machine registers + state LineEntry // public state + fileIndex int // private state } -// LineForPc returns the line number information for a program counter -// address, if any. When this returns multiple Line structures in a -// context where only one can be used, the last one is the best. -func (d *Data) LineForPC(pc uint64) ([]*Line, error) { - for i := range d.unit { - u := &d.unit[i] - if u.pc == nil { - if err := d.readUnitLine(i, u); err != nil { - return nil, err - } - } - for _, ar := range u.pc { - if pc >= ar.low && pc < ar.high { - return d.findLine(u, pc) - } - } +// A LineEntry is a row in a DWARF line table. +type LineEntry struct { + // Address is the program-counter value of a machine + // instruction generated by the compiler. This LineEntry + // applies to each instruction from Address to just before the + // Address of the next LineEntry. + Address uint64 + + // OpIndex is the index of an operation within a VLIW + // instruction. The index of the first operation is 0. For + // non-VLIW architectures, it will always be 0. Address and + // OpIndex together form an operation pointer that can + // reference any individual operation within the instruction + // stream. + OpIndex int + + // File is the source file corresponding to these + // instructions. + File *LineFile + + // Line is the source code line number corresponding to these + // instructions. Lines are numbered beginning at 1. It may be + // 0 if these instructions cannot be attributed to any source + // line. + Line int + + // Column is the column number within the source line of these + // instructions. Columns are numbered beginning at 1. It may + // be 0 to indicate the "left edge" of the line. + Column int + + // IsStmt indicates that Address is a recommended breakpoint + // location, such as the beginning of a line, statement, or a + // distinct subpart of a statement. + IsStmt bool + + // BasicBlock indicates that Address is the beginning of a + // basic block. + BasicBlock bool + + // PrologueEnd indicates that Address is one (of possibly + // many) PCs where execution should be suspended for a + // breakpoint on entry to the containing function. + // + // Added in DWARF 3. + PrologueEnd bool + + // EpilogueBegin indicates that Address is one (of possibly + // many) PCs where execution should be suspended for a + // breakpoint on exit from this function. + // + // Added in DWARF 3. + EpilogueBegin bool + + // ISA is the instruction set architecture for these + // instructions. Possible ISA values should be defined by the + // applicable ABI specification. + // + // Added in DWARF 3. + ISA int + + // Discriminator is an arbitrary integer indicating the block + // to which these instructions belong. It serves to + // distinguish among multiple blocks that may all have with + // the same source file, line, and column. Where only one + // block exists for a given source position, it should be 0. + // + // Added in DWARF 3. + Discriminator int + + // EndSequence indicates that Address is the first byte after + // the end of a sequence of target machine instructions. If it + // is set, only this and the Address field are meaningful. A + // line number table may contain information for multiple + // potentially disjoint instruction sequences. The last entry + // in a line table should always have EndSequence set. + EndSequence bool +} + +// A LineFile is a source file referenced by a DWARF line table entry. +type LineFile struct { + Name string + Mtime uint64 // Implementation defined modification time, or 0 if unknown + Length int // File length, or 0 if unknown +} + +// LineReader returns a new reader for the line table of compilation +// unit cu, which must be an Entry with tag TagCompileUnit. +// +// If this compilation unit has no line table, it returns nil, nil. +func (d *Data) LineReader(cu *Entry) (*LineReader, error) { + if d.line == nil { + // No line tables available. + return nil, nil + } + + // Get line table information from cu. + off, ok := cu.Val(AttrStmtList).(int64) + if !ok { + // cu has no line table. + return nil, nil } - return nil, nil + if off > int64(len(d.line)) { + return nil, errors.New("AttrStmtList value out of range") + } + // AttrCompDir is optional if all file names are absolute. Use + // the empty string if it's not present. + compDir, _ := cu.Val(AttrCompDir).(string) + + // Create the LineReader. + u := &d.unit[d.offsetToUnit(cu.Offset)] + buf := makeBuf(d, u, "line", Offset(off), d.line[off:]) + // The compilation directory is implicitly directories[0]. + r := LineReader{buf: buf, section: d.line, directories: []string{compDir}} + + // Read the header. + if err := r.readHeader(); err != nil { + return nil, err + } + + // Initialize line reader state. + r.Reset() + + return &r, nil } -// readUnitLine reads in the line number information for a compilation -// unit. -func (d *Data) readUnitLine(i int, u *unit) error { - r := d.unitReader(i) - setLineOff := false - for { - e, err := r.Next() - if err != nil { - return err +// readHeader reads the line number program header from r.buf and sets +// all of the header fields in r. +func (r *LineReader) readHeader() error { + buf := &r.buf + + // Read basic header fields [DWARF2 6.2.4]. + hdrOffset := buf.off + unitLength, dwarf64 := buf.unitLength() + r.endOffset = buf.off + unitLength + if r.endOffset > buf.off+Offset(len(buf.data)) { + return DecodeError{"line", hdrOffset, fmt.Sprintf("line table end %d exceeds section size %d", r.endOffset, buf.off+Offset(len(buf.data)))} + } + r.version = buf.uint16() + if buf.err == nil && (r.version < 2 || r.version > 4) { + // DWARF goes to all this effort to make new opcodes + // backward-compatible, and then adds fields right in + // the middle of the header in new versions, so we're + // picky about only supporting known line table + // versions. + return DecodeError{"line", hdrOffset, fmt.Sprintf("unknown line table version %d", r.version)} + } + var headerLength Offset + if dwarf64 { + headerLength = Offset(buf.uint64()) + } else { + headerLength = Offset(buf.uint32()) + } + r.programOffset = buf.off + headerLength + r.minInstructionLength = int(buf.uint8()) + if r.version >= 4 { + // [DWARF4 6.2.4] + r.maxOpsPerInstruction = int(buf.uint8()) + } else { + r.maxOpsPerInstruction = 1 + } + r.defaultIsStmt = buf.uint8() != 0 + r.lineBase = int(int8(buf.uint8())) + r.lineRange = int(buf.uint8()) + + // Validate header. + if buf.err != nil { + return buf.err + } + if r.maxOpsPerInstruction == 0 { + return DecodeError{"line", hdrOffset, "invalid maximum operations per instruction: 0"} + } + if r.lineRange == 0 { + return DecodeError{"line", hdrOffset, "invalid line range: 0"} + } + + // Read standard opcode length table. This table starts with opcode 1. + r.opcodeBase = int(buf.uint8()) + r.opcodeLengths = make([]int, r.opcodeBase) + for i := 1; i < r.opcodeBase; i++ { + r.opcodeLengths[i] = int(buf.uint8()) + } + + // Validate opcode lengths. + if buf.err != nil { + return buf.err + } + for i, length := range r.opcodeLengths { + if known, ok := knownOpcodeLengths[i]; ok && known != length { + return DecodeError{"line", hdrOffset, fmt.Sprintf("opcode %d expected to have length %d, but has length %d", i, known, length)} } - if e == nil { - break + } + + // Read include directories table. The caller already set + // directories[0] to the compilation directory. + for { + directory := buf.string() + if buf.err != nil { + return buf.err } - if r.unit != i { + if len(directory) == 0 { break } - switch e.Tag { - case TagCompileUnit, TagSubprogram, TagEntryPoint, TagInlinedSubroutine: - low, lowok := e.Val(AttrLowpc).(uint64) - var high uint64 - var highok bool - switch v := e.Val(AttrHighpc).(type) { - case uint64: - high = v - highok = true - case int64: - high = low + uint64(v) - highok = true - } - if lowok && highok { - u.pc = append(u.pc, addrRange{low, high}) - } else if off, ok := e.Val(AttrRanges).(Offset); ok { - if err := d.readAddressRanges(off, low, u); err != nil { - return err - } - } - val := e.Val(AttrStmtList) - if val != nil { - if off, ok := val.(int64); ok { - u.lineoff = Offset(off) - setLineOff = true - } else if off, ok := val.(Offset); ok { - u.lineoff = off - setLineOff = true - } else { - return errors.New("unrecognized format for DW_ATTR_stmt_list") - } - } - if dir, ok := e.Val(AttrCompDir).(string); ok { - u.dir = dir - } + if !path.IsAbs(directory) { + // Relative paths are implicitly relative to + // the compilation directory. + directory = path.Join(r.directories[0], directory) } + r.directories = append(r.directories, directory) } - if !setLineOff { - u.lineoff = Offset(0) - u.lineoff-- + + // Read file name list. File numbering starts with 1, so leave + // the first entry nil. + r.fileEntries = make([]*LineFile, 1) + for { + if done, err := r.readFileEntry(); err != nil { + return err + } else if done { + break + } } - return nil + r.initialFileEntries = len(r.fileEntries) + + return buf.err } -// readAddressRanges adds address ranges to a unit. -func (d *Data) readAddressRanges(off Offset, base uint64, u *unit) error { - b := makeBuf(d, u, "ranges", off, d.ranges[off:]) - var highest uint64 - switch u.addrsize() { - case 1: - highest = 0xff - case 2: - highest = 0xffff - case 4: - highest = 0xffffffff - case 8: - highest = 0xffffffffffffffff - default: - return errors.New("unknown address size") +// readFileEntry reads a file entry from either the header or a +// DW_LNE_define_file extended opcode and adds it to r.fileEntries. A +// true return value indicates that there are no more entries to read. +func (r *LineReader) readFileEntry() (bool, error) { + name := r.buf.string() + if r.buf.err != nil { + return false, r.buf.err } - for { - if b.err != nil { - return b.err - } - low := b.addr() - high := b.addr() - if low == 0 && high == 0 { - return b.err - } else if low == highest { - base = high - } else { - u.pc = append(u.pc, addrRange{low + base, high + base}) + if len(name) == 0 { + return true, nil + } + off := r.buf.off + dirIndex := int(r.buf.uint()) + if !path.IsAbs(name) { + if dirIndex >= len(r.directories) { + return false, DecodeError{"line", off, "directory index too large"} } + name = path.Join(r.directories[dirIndex], name) } + mtime := r.buf.uint() + length := int(r.buf.uint()) + + r.fileEntries = append(r.fileEntries, &LineFile{name, mtime, length}) + return false, nil } -// findLine finds the line information for a PC value, given the unit -// containing the information. -func (d *Data) findLine(u *unit, pc uint64) ([]*Line, error) { - if u.lines == nil { - if err := d.parseLine(u); err != nil { - return nil, err - } +// updateFile updates r.state.File after r.fileIndex has +// changed or r.fileEntries has changed. +func (r *LineReader) updateFile() { + if r.fileIndex < len(r.fileEntries) { + r.state.File = r.fileEntries[r.fileIndex] + } else { + r.state.File = nil } +} - for _, ln := range u.lines { - if pc < ln.addrs[0].pc || pc > ln.addrs[len(ln.addrs)-1].pc { - continue +// Next sets *entry to the next row in this line table and moves to +// the next row. If there are no more entries and the line table is +// properly terminated, it returns io.EOF. +// +// Rows are always in order of increasing entry.Address, but +// entry.Line may go forward or backward. +func (r *LineReader) Next(entry *LineEntry) error { + if r.buf.err != nil { + return r.buf.err + } + + // Execute opcodes until we reach an opcode that emits a line + // table entry. + for { + if len(r.buf.data) == 0 { + return io.EOF } - i := sort.Search(len(ln.addrs), - func(i int) bool { return ln.addrs[i].pc > pc }) - i-- - p := new(Line) - *p = ln.line - p.Line = ln.addrs[i].line - ret := []*Line{p} - for i++; i < len(ln.addrs) && ln.addrs[i].pc == pc; i++ { - p = new(Line) - *p = ln.line - p.Line = ln.addrs[i].line - ret = append(ret, p) + emit := r.step(entry) + if r.buf.err != nil { + return r.buf.err + } + if emit { + return nil } - return ret, nil } +} - return nil, nil +// knownOpcodeLengths gives the opcode lengths (in varint arguments) +// of known standard opcodes. +var knownOpcodeLengths = map[int]int{ + lnsCopy: 0, + lnsAdvancePC: 1, + lnsAdvanceLine: 1, + lnsSetFile: 1, + lnsNegateStmt: 0, + lnsSetBasicBlock: 0, + lnsConstAddPC: 0, + lnsSetPrologueEnd: 0, + lnsSetEpilogueBegin: 0, + lnsSetISA: 1, + // lnsFixedAdvancePC takes a uint8 rather than a varint; it's + // unclear what length the header is supposed to claim, so + // ignore it. } -// FileLine returns the file name and line number for a program -// counter address, or "", 0 if unknown. -func (d *Data) FileLine(pc uint64) (string, int, error) { - r, err := d.LineForPC(pc) - if err != nil { - return "", 0, err - } - if r == nil { - return "", 0, nil +// step processes the next opcode and updates r.state. If the opcode +// emits a row in the line table, this updates *entry and returns +// true. +func (r *LineReader) step(entry *LineEntry) bool { + opcode := int(r.buf.uint8()) + + if opcode >= r.opcodeBase { + // Special opcode [DWARF2 6.2.5.1, DWARF4 6.2.5.1] + adjustedOpcode := opcode - r.opcodeBase + r.advancePC(adjustedOpcode / r.lineRange) + lineDelta := r.lineBase + int(adjustedOpcode)%r.lineRange + r.state.Line += lineDelta + goto emit } - ln := r[len(r)-1] - return ln.Filename, ln.Line, nil -} -// A mapLineInfo holds the PC values and line numbers associated with -// a single Line structure. This representation is chosen to reduce -// memory usage based on typical debug info. -type mapLineInfo struct { - line Line // line.Line will be zero - addrs lineAddrs // sorted by PC -} + switch opcode { + case 0: + // Extended opcode [DWARF2 6.2.5.3] + length := Offset(r.buf.uint()) + startOff := r.buf.off + opcode := r.buf.uint8() -// A list of lines. This will be sorted by PC. -type lineAddrs []oneLineInfo + switch opcode { + case lneEndSequence: + r.state.EndSequence = true + *entry = r.state + r.resetState() -func (p lineAddrs) Len() int { return len(p) } -func (p lineAddrs) Less(i, j int) bool { return p[i].pc < p[j].pc } -func (p lineAddrs) Swap(i, j int) { p[i], p[j] = p[j], p[i] } + case lneSetAddress: + r.state.Address = r.buf.addr() -// A oneLineInfo is a single PC and line number. -type oneLineInfo struct { - pc uint64 - line int -} + case lneDefineFile: + if done, err := r.readFileEntry(); err != nil { + r.buf.err = err + return false + } else if done { + r.buf.err = DecodeError{"line", startOff, "malformed DW_LNE_define_file operation"} + return false + } + r.updateFile() -// A lineHdr holds the relevant information from a line number -// program header. -type lineHdr struct { - version uint16 // version of line number encoding - minInsnLen uint8 // minimum instruction length - maxOpsPerInsn uint8 // maximum number of ops per instruction - defStmt bool // initial value of stmt register - lineBase int8 // line adjustment base - lineRange uint8 // line adjustment step - opBase uint8 // base of special opcode values - opLen []uint8 // lengths of standard opcodes - dirs []string // directories - files []string // file names -} + case lneSetDiscriminator: + // [DWARF4 6.2.5.3] + r.state.Discriminator = int(r.buf.uint()) + } -// parseLine parses the line number information for a compilation unit -func (d *Data) parseLine(u *unit) error { - if u.lineoff+1 == 0 { - return errors.New("unknown line offset") - } - b := makeBuf(d, u, "line", u.lineoff, d.line[u.lineoff:]) - len := uint64(b.uint32()) - dwarf64 := false - if len == 0xffffffff { - len = b.uint64() - dwarf64 = true - } - end := b.off + Offset(len) - hdr := d.parseLineHdr(u, &b, dwarf64) - if b.err == nil { - d.parseLineProgram(u, &b, hdr, end) - } - return b.err -} + r.buf.skip(int(startOff + length - r.buf.off)) -// parseLineHdr parses a line number program header. -func (d *Data) parseLineHdr(u *unit, b *buf, dwarf64 bool) (hdr lineHdr) { - hdr.version = b.uint16() - if hdr.version < 2 || hdr.version > 4 { - b.error("unsupported DWARF version " + strconv.Itoa(int(hdr.version))) - return - } + if opcode == lneEndSequence { + return true + } - var hlen Offset - if dwarf64 { - hlen = Offset(b.uint64()) - } else { - hlen = Offset(b.uint32()) - } - end := b.off + hlen + // Standard opcodes [DWARF2 6.2.5.2] + case lnsCopy: + goto emit - hdr.minInsnLen = b.uint8() - if hdr.version < 4 { - hdr.maxOpsPerInsn = 1 - } else { - hdr.maxOpsPerInsn = b.uint8() - } + case lnsAdvancePC: + r.advancePC(int(r.buf.uint())) - if b.uint8() == 0 { - hdr.defStmt = false - } else { - hdr.defStmt = true - } - hdr.lineBase = int8(b.uint8()) - hdr.lineRange = b.uint8() - hdr.opBase = b.uint8() - hdr.opLen = b.bytes(int(hdr.opBase - 1)) + case lnsAdvanceLine: + r.state.Line += int(r.buf.int()) - for d := b.string(); len(d) > 0; d = b.string() { - hdr.dirs = append(hdr.dirs, d) - } + case lnsSetFile: + r.fileIndex = int(r.buf.uint()) + r.updateFile() - for f := b.string(); len(f) > 0; f = b.string() { - d := b.uint() - if !filepath.IsAbs(f) { - if d > 0 { - if d > uint64(len(hdr.dirs)) { - b.error("DWARF directory index out of range") - return - } - f = filepath.Join(hdr.dirs[d-1], f) - } else if u.dir != "" { - f = filepath.Join(u.dir, f) - } + case lnsSetColumn: + r.state.Column = int(r.buf.uint()) + + case lnsNegateStmt: + r.state.IsStmt = !r.state.IsStmt + + case lnsSetBasicBlock: + r.state.BasicBlock = true + + case lnsConstAddPC: + r.advancePC((255 - r.opcodeBase) / r.lineRange) + + case lnsFixedAdvancePC: + r.state.Address += uint64(r.buf.uint16()) + + // DWARF3 standard opcodes [DWARF3 6.2.5.2] + case lnsSetPrologueEnd: + r.state.PrologueEnd = true + + case lnsSetEpilogueBegin: + r.state.EpilogueBegin = true + + case lnsSetISA: + r.state.ISA = int(r.buf.uint()) + + default: + // Unhandled standard opcode. Skip the number of + // arguments that the prologue says this opcode has. + for i := 0; i < r.opcodeLengths[opcode]; i++ { + r.buf.uint() } - b.uint() // file's last mtime - b.uint() // file length - hdr.files = append(hdr.files, f) } + return false - if end > b.off { - b.bytes(int(end - b.off)) - } +emit: + *entry = r.state + r.state.BasicBlock = false + r.state.PrologueEnd = false + r.state.EpilogueBegin = false + r.state.Discriminator = 0 + return true +} + +// advancePC advances "operation pointer" (the combination of Address +// and OpIndex) in r.state by opAdvance steps. +func (r *LineReader) advancePC(opAdvance int) { + opIndex := r.state.OpIndex + opAdvance + r.state.Address += uint64(r.minInstructionLength * (opIndex / r.maxOpsPerInstruction)) + r.state.OpIndex = opIndex % r.maxOpsPerInstruction +} + +// A LineReaderPos represents a position in a line table. +type LineReaderPos struct { + // off is the current offset in the DWARF line section. + off Offset + // numFileEntries is the length of fileEntries. + numFileEntries int + // state and fileIndex are the statement machine state at + // offset off. + state LineEntry + fileIndex int +} + +// Tell returns the current position in the line table. +func (r *LineReader) Tell() LineReaderPos { + return LineReaderPos{r.buf.off, len(r.fileEntries), r.state, r.fileIndex} +} + +// Seek restores the line table reader to a position returned by Tell. +// +// The argument pos must have been returned by a call to Tell on this +// line table. +func (r *LineReader) Seek(pos LineReaderPos) { + r.buf.off = pos.off + r.buf.data = r.section[r.buf.off:r.endOffset] + r.fileEntries = r.fileEntries[:pos.numFileEntries] + r.state = pos.state + r.fileIndex = pos.fileIndex +} + +// Reset repositions the line table reader at the beginning of the +// line table. +func (r *LineReader) Reset() { + // Reset buffer to the line number program offset. + r.buf.off = r.programOffset + r.buf.data = r.section[r.buf.off:r.endOffset] - return + // Reset file entries list. + r.fileEntries = r.fileEntries[:r.initialFileEntries] + + // Reset line number program state. + r.resetState() } -// parseLineProgram parses a line program, adding information to -// d.lineInfo as it goes. -func (d *Data) parseLineProgram(u *unit, b *buf, hdr lineHdr, end Offset) { - address := uint64(0) - line := 1 - resetLineInfo := Line{ - Filename: "", +// resetState resets r.state to its default values +func (r *LineReader) resetState() { + // Reset the state machine registers to the defaults given in + // [DWARF4 6.2.2]. + r.state = LineEntry{ + Address: 0, OpIndex: 0, - Line: 0, + File: nil, + Line: 1, Column: 0, + IsStmt: r.defaultIsStmt, + BasicBlock: false, + PrologueEnd: false, + EpilogueBegin: false, ISA: 0, Discriminator: 0, - Stmt: hdr.defStmt, - Block: false, - EndPrologue: false, - BeginEpilogue: false, } - if len(hdr.files) > 0 { - resetLineInfo.Filename = hdr.files[0] + r.fileIndex = 1 + r.updateFile() +} + +// ErrUnknownPC is the error returned by LineReader.ScanPC when the +// seek PC is not covered by any entry in the line table. +var ErrUnknownPC = errors.New("ErrUnknownPC") + +// SeekPC sets *entry to the LineEntry that includes pc and positions +// the reader on the next entry in the line table. If necessary, this +// will seek backwards to find pc. +// +// If pc is not covered by any entry in this line table, SeekPC +// returns ErrUnknownPC. In this case, *entry and the final seek +// position are unspecified. +// +// Note that DWARF line tables only permit sequential, forward scans. +// Hence, in the worst case, this takes time linear in the size of the +// line table. If the caller wishes to do repeated fast PC lookups, it +// should build an appropriate index of the line table. +func (r *LineReader) SeekPC(pc uint64, entry *LineEntry) error { + if err := r.Next(entry); err != nil { + return err } - lineInfo := resetLineInfo - - var lines []mapLineInfo - - minInsnLen := uint64(hdr.minInsnLen) - maxOpsPerInsn := uint64(hdr.maxOpsPerInsn) - lineBase := int(hdr.lineBase) - lineRange := hdr.lineRange - newLineInfo := true - for b.off < end && b.err == nil { - op := b.uint8() - if op >= hdr.opBase { - // This is a special opcode. - op -= hdr.opBase - advance := uint64(op / hdr.lineRange) - opIndex := uint64(lineInfo.OpIndex) - address += minInsnLen * ((opIndex + advance) / maxOpsPerInsn) - newOpIndex := int((opIndex + advance) % maxOpsPerInsn) - line += lineBase + int(op%lineRange) - if newOpIndex != lineInfo.OpIndex { - lineInfo.OpIndex = newOpIndex - newLineInfo = true - } - lines, lineInfo, newLineInfo = d.addLine(lines, lineInfo, address, line, newLineInfo) - } else if op == LineExtendedOp { - c := b.uint() - op = b.uint8() - switch op { - case LineExtEndSequence: - u.lines = append(u.lines, lines...) - lineInfo = resetLineInfo - lines = nil - newLineInfo = true - case LineExtSetAddress: - address = b.addr() - case LineExtDefineFile: - f := b.string() - d := b.uint() - b.uint() // mtime - b.uint() // length - if d > 0 && !filepath.IsAbs(f) { - if d >= uint64(len(hdr.dirs)) { - b.error("DWARF directory index out of range") - return - } - f = filepath.Join(hdr.dirs[d-1], f) - } - hdr.files = append(hdr.files, f) - case LineExtSetDiscriminator: - lineInfo.Discriminator = int(b.uint()) - newLineInfo = true - default: - if c > 0 { - b.bytes(int(c) - 1) - } - } - } else { - switch op { - case LineCopy: - lines, lineInfo, newLineInfo = d.addLine(lines, lineInfo, address, line, newLineInfo) - case LineAdvancePC: - advance := b.uint() - opIndex := uint64(lineInfo.OpIndex) - address += minInsnLen * ((opIndex + advance) / maxOpsPerInsn) - newOpIndex := int((opIndex + advance) % maxOpsPerInsn) - if newOpIndex != lineInfo.OpIndex { - lineInfo.OpIndex = newOpIndex - newLineInfo = true - } - case LineAdvanceLine: - line += int(b.int()) - case LineSetFile: - i := b.uint() - if i > uint64(len(hdr.files)) { - b.error("DWARF file number out of range") - return - } - lineInfo.Filename = hdr.files[i-1] - newLineInfo = true - case LineSetColumn: - lineInfo.Column = int(b.uint()) - newLineInfo = true - case LineNegateStmt: - lineInfo.Stmt = !lineInfo.Stmt - newLineInfo = true - case LineSetBasicBlock: - lineInfo.Block = true - newLineInfo = true - case LineConstAddPC: - op = 255 - hdr.opBase - advance := uint64(op / hdr.lineRange) - opIndex := uint64(lineInfo.OpIndex) - address += minInsnLen * ((opIndex + advance) / maxOpsPerInsn) - newOpIndex := int((opIndex + advance) % maxOpsPerInsn) - if newOpIndex != lineInfo.OpIndex { - lineInfo.OpIndex = newOpIndex - newLineInfo = true - } - case LineFixedAdvancePC: - address += uint64(b.uint16()) - if lineInfo.OpIndex != 0 { - lineInfo.OpIndex = 0 - newLineInfo = true - } - case LineSetPrologueEnd: - lineInfo.EndPrologue = true - newLineInfo = true - case LineSetEpilogueBegin: - lineInfo.BeginEpilogue = true - newLineInfo = true - case LineSetISA: - lineInfo.ISA = int(b.uint()) - newLineInfo = true - default: - if int(op) >= len(hdr.opLen) { - b.error("DWARF line opcode has unknown length") - return - } - for i := hdr.opLen[op-1]; i > 0; i-- { - b.int() - } - } + if entry.Address > pc { + // We're too far. Start at the beginning of the table. + r.Reset() + if err := r.Next(entry); err != nil { + return err + } + if entry.Address > pc { + // The whole table starts after pc. + r.Reset() + return ErrUnknownPC } } -} -// addLine adds the current address and line to lines using lineInfo. -// If newLineInfo is true this is a new lineInfo. This returns the -// updated lines, lineInfo, and newLineInfo. -func (d *Data) addLine(lines []mapLineInfo, lineInfo Line, address uint64, line int, newLineInfo bool) ([]mapLineInfo, Line, bool) { - if newLineInfo { - if len(lines) > 0 { - sort.Sort(lines[len(lines)-1].addrs) - p := &lines[len(lines)-1] - if len(p.addrs) > 0 && address > p.addrs[len(p.addrs)-1].pc { - p.addrs = append(p.addrs, oneLineInfo{address, p.addrs[len(p.addrs)-1].line}) + // Scan until we pass pc, then back up one. + for { + var next LineEntry + pos := r.Tell() + if err := r.Next(&next); err != nil { + if err == io.EOF { + return ErrUnknownPC } + return err } - lines = append(lines, mapLineInfo{line: lineInfo}) - } - p := &lines[len(lines)-1] - p.addrs = append(p.addrs, oneLineInfo{address, line}) - - if lineInfo.Block || lineInfo.EndPrologue || lineInfo.BeginEpilogue || lineInfo.Discriminator != 0 { - lineInfo.Block = false - lineInfo.EndPrologue = false - lineInfo.BeginEpilogue = false - lineInfo.Discriminator = 0 - newLineInfo = true - } else { - newLineInfo = false + if next.Address > pc { + if entry.EndSequence { + // pc is in a hole in the table. + return ErrUnknownPC + } + // entry is the desired entry. Back up the + // cursor to "next" and return success. + r.Seek(pos) + return nil + } + *entry = next } - - return lines, lineInfo, newLineInfo } diff --git a/libgo/go/debug/dwarf/line_test.go b/libgo/go/debug/dwarf/line_test.go index 2476a6faf53..4104b5d49b8 100644 --- a/libgo/go/debug/dwarf/line_test.go +++ b/libgo/go/debug/dwarf/line_test.go @@ -1,4 +1,4 @@ -// Copyright 2012 The Go Authors. All rights reserved. +// Copyright 2015 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. @@ -6,48 +6,224 @@ package dwarf_test import ( . "debug/dwarf" - "path/filepath" + "io" "testing" ) -type lineTest struct { - pc uint64 - file string - line int -} +var ( + file1C = &LineFile{Name: "/home/austin/go.dev/src/debug/dwarf/testdata/line1.c"} + file1H = &LineFile{Name: "/home/austin/go.dev/src/debug/dwarf/testdata/line1.h"} + file2C = &LineFile{Name: "/home/austin/go.dev/src/debug/dwarf/testdata/line2.c"} +) -var elfLineTests = [...]lineTest{ - {0x4004c4, "typedef.c", 83}, - {0x4004c8, "typedef.c", 84}, - {0x4004ca, "typedef.c", 84}, - {0x4003e0, "", 0}, -} +func TestLineELFGCC(t *testing.T) { + // Generated by: + // # gcc --version | head -n1 + // gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2 + // # gcc -g -o line-gcc.elf line*.c + + // Line table based on readelf --debug-dump=rawline,decodedline + want := []LineEntry{ + {Address: 0x40059d, File: file1H, Line: 2, IsStmt: true}, + {Address: 0x4005a5, File: file1H, Line: 2, IsStmt: true}, + {Address: 0x4005b4, File: file1H, Line: 5, IsStmt: true}, + {Address: 0x4005bd, File: file1H, Line: 6, IsStmt: true, Discriminator: 2}, + {Address: 0x4005c7, File: file1H, Line: 5, IsStmt: true, Discriminator: 2}, + {Address: 0x4005cb, File: file1H, Line: 5, IsStmt: false, Discriminator: 1}, + {Address: 0x4005d1, File: file1H, Line: 7, IsStmt: true}, + {Address: 0x4005e7, File: file1C, Line: 6, IsStmt: true}, + {Address: 0x4005eb, File: file1C, Line: 7, IsStmt: true}, + {Address: 0x4005f5, File: file1C, Line: 8, IsStmt: true}, + {Address: 0x4005ff, File: file1C, Line: 9, IsStmt: true}, + {Address: 0x400601, EndSequence: true}, -var machoLineTests = [...]lineTest{ - {0x0, "typedef.c", 83}, + {Address: 0x400601, File: file2C, Line: 4, IsStmt: true}, + {Address: 0x400605, File: file2C, Line: 5, IsStmt: true}, + {Address: 0x40060f, File: file2C, Line: 6, IsStmt: true}, + {Address: 0x400611, EndSequence: true}, + } + + testLineTable(t, want, elfData(t, "testdata/line-gcc.elf")) } -func TestLineElf(t *testing.T) { - testLine(t, elfData(t, "testdata/typedef.elf"), elfLineTests[:], "elf") +func TestLineELFClang(t *testing.T) { + // Generated by: + // # clang --version | head -n1 + // Ubuntu clang version 3.4-1ubuntu3 (tags/RELEASE_34/final) (based on LLVM 3.4) + // # clang -g -o line-clang.elf line*. + + want := []LineEntry{ + {Address: 0x400530, File: file1C, Line: 6, IsStmt: true}, + {Address: 0x400534, File: file1C, Line: 7, IsStmt: true, PrologueEnd: true}, + {Address: 0x400539, File: file1C, Line: 8, IsStmt: true}, + {Address: 0x400545, File: file1C, Line: 9, IsStmt: true}, + {Address: 0x400550, File: file1H, Line: 2, IsStmt: true}, + {Address: 0x400554, File: file1H, Line: 5, IsStmt: true, PrologueEnd: true}, + {Address: 0x400568, File: file1H, Line: 6, IsStmt: true}, + {Address: 0x400571, File: file1H, Line: 5, IsStmt: true}, + {Address: 0x400581, File: file1H, Line: 7, IsStmt: true}, + {Address: 0x400583, EndSequence: true}, + + {Address: 0x400590, File: file2C, Line: 4, IsStmt: true}, + {Address: 0x4005a0, File: file2C, Line: 5, IsStmt: true, PrologueEnd: true}, + {Address: 0x4005a7, File: file2C, Line: 6, IsStmt: true}, + {Address: 0x4005b0, EndSequence: true}, + } + + testLineTable(t, want, elfData(t, "testdata/line-clang.elf")) } -func TestLineMachO(t *testing.T) { - testLine(t, machoData(t, "testdata/typedef.macho"), machoLineTests[:], "macho") +func TestLineSeek(t *testing.T) { + d := elfData(t, "testdata/line-gcc.elf") + + // Get the line table for the first CU. + cu, err := d.Reader().Next() + if err != nil { + t.Fatal("d.Reader().Next:", err) + } + lr, err := d.LineReader(cu) + if err != nil { + t.Fatal("d.LineReader:", err) + } + + // Read entries forward. + var line LineEntry + var posTable []LineReaderPos + var table []LineEntry + for { + posTable = append(posTable, lr.Tell()) + + err := lr.Next(&line) + if err != nil { + if err == io.EOF { + break + } + t.Fatal("lr.Next:", err) + } + table = append(table, line) + } + + // Test that Reset returns to the first line. + lr.Reset() + if err := lr.Next(&line); err != nil { + t.Fatal("lr.Next after Reset failed:", err) + } else if line != table[0] { + t.Fatal("lr.Next after Reset returned", line, "instead of", table[0]) + } + + // Check that entries match when seeking backward. + for i := len(posTable) - 1; i >= 0; i-- { + lr.Seek(posTable[i]) + err := lr.Next(&line) + if i == len(posTable)-1 { + if err != io.EOF { + t.Fatal("expected io.EOF after seek to end, got", err) + } + } else if err != nil { + t.Fatal("lr.Next after seek to", posTable[i], "failed:", err) + } else if line != table[i] { + t.Fatal("lr.Next after seek to", posTable[i], "returned", line, "instead of", table[i]) + } + } + + // Check that seeking to a PC returns the right line. + if err := lr.SeekPC(table[0].Address-1, &line); err != ErrUnknownPC { + t.Fatalf("lr.SeekPC to %#x returned %v instead of ErrUnknownPC", table[0].Address-1, err) + } + for i, testLine := range table { + if testLine.EndSequence { + if err := lr.SeekPC(testLine.Address, &line); err != ErrUnknownPC { + t.Fatalf("lr.SeekPC to %#x returned %v instead of ErrUnknownPC", testLine.Address, err) + } + continue + } + + nextPC := table[i+1].Address + for pc := testLine.Address; pc < nextPC; pc++ { + if err := lr.SeekPC(pc, &line); err != nil { + t.Fatalf("lr.SeekPC to %#x failed: %v", pc, err) + } else if line != testLine { + t.Fatalf("lr.SeekPC to %#x returned %v instead of %v", pc, line, testLine) + } + } + } } -func testLine(t *testing.T, d *Data, tests []lineTest, kind string) { - for _, v := range tests { - file, line, err := d.FileLine(v.pc) +func testLineTable(t *testing.T, want []LineEntry, d *Data) { + // Get line table from d. + var got []LineEntry + dr := d.Reader() + for { + ent, err := dr.Next() if err != nil { - t.Errorf("%s: %v", kind, err) + t.Fatal("dr.Next:", err) + } else if ent == nil { + break + } + + if ent.Tag != TagCompileUnit { + dr.SkipChildren() continue } - if file != "" { - file = filepath.Base(file) + + // Decode CU's line table. + lr, err := d.LineReader(ent) + if err != nil { + t.Fatal("d.LineReader:", err) + } else if lr == nil { + continue } - if file != v.file || line != v.line { - t.Errorf("%s: for %d have %q:%d want %q:%d", - kind, v.pc, file, line, v.file, v.line) + + for { + var line LineEntry + err := lr.Next(&line) + if err != nil { + if err == io.EOF { + break + } + t.Fatal("lr.Next:", err) + } + got = append(got, line) } } + + // Compare line tables. + if !compareLines(got, want) { + t.Log("Line tables do not match. Got:") + dumpLines(t, got) + t.Log("Want:") + dumpLines(t, want) + t.FailNow() + } +} + +func compareLines(a, b []LineEntry) bool { + if len(a) != len(b) { + return false + } + + for i := range a { + al, bl := a[i], b[i] + // If both are EndSequence, then the only other valid + // field is Address. Otherwise, test equality of all + // fields. + if al.EndSequence && bl.EndSequence && al.Address == bl.Address { + continue + } + if al.File.Name != bl.File.Name { + return false + } + al.File = nil + bl.File = nil + if al != bl { + return false + } + } + return true +} + +func dumpLines(t *testing.T, lines []LineEntry) { + for _, l := range lines { + t.Logf(" %+v File:%+v", l, l.File) + } } diff --git a/libgo/go/debug/dwarf/testdata/line-clang.elf b/libgo/go/debug/dwarf/testdata/line-clang.elf new file mode 100644 index 00000000000..b63cc781c41 Binary files /dev/null and b/libgo/go/debug/dwarf/testdata/line-clang.elf differ diff --git a/libgo/go/debug/dwarf/testdata/line-gcc.elf b/libgo/go/debug/dwarf/testdata/line-gcc.elf new file mode 100644 index 00000000000..50500a8eecd Binary files /dev/null and b/libgo/go/debug/dwarf/testdata/line-gcc.elf differ diff --git a/libgo/go/debug/dwarf/testdata/line1.c b/libgo/go/debug/dwarf/testdata/line1.c new file mode 100644 index 00000000000..f35864776ca --- /dev/null +++ b/libgo/go/debug/dwarf/testdata/line1.c @@ -0,0 +1,9 @@ +#include "line1.h" + +void f2(); + +int main() +{ + f1(); + f2(); +} diff --git a/libgo/go/debug/dwarf/testdata/line1.h b/libgo/go/debug/dwarf/testdata/line1.h new file mode 100644 index 00000000000..974d4c88177 --- /dev/null +++ b/libgo/go/debug/dwarf/testdata/line1.h @@ -0,0 +1,7 @@ +static void f1() +{ + char buf[10]; + int i; + for(i = 0; i < 10; i++) + buf[i] = 1; +} diff --git a/libgo/go/debug/dwarf/testdata/line2.c b/libgo/go/debug/dwarf/testdata/line2.c new file mode 100644 index 00000000000..38d89983cbb --- /dev/null +++ b/libgo/go/debug/dwarf/testdata/line2.c @@ -0,0 +1,6 @@ +#include + +void f2() +{ + printf("hello\n"); +} diff --git a/libgo/go/debug/dwarf/type.go b/libgo/go/debug/dwarf/type.go index 6986b19e722..a5daa1d0bb1 100644 --- a/libgo/go/debug/dwarf/type.go +++ b/libgo/go/debug/dwarf/type.go @@ -268,6 +268,9 @@ type typeReader interface { Next() (*Entry, error) clone() typeReader offset() Offset + // AddressSize returns the size in bytes of addresses in the current + // compilation unit. + AddressSize() int } // Type reads the type at off in the DWARF ``info'' section. @@ -286,6 +289,7 @@ func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Off if err != nil { return nil, err } + addressSize := r.AddressSize() if e == nil || e.Offset != off { return nil, DecodeError{name, off, "no type at offset"} } @@ -668,6 +672,12 @@ func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Off b, ok := e.Val(AttrByteSize).(int64) if !ok { b = -1 + switch t := typ.(type) { + case *TypedefType: + b = t.Type.Size() + case *PtrType: + b = int64(addressSize) + } } typ.Common().ByteSize = b } diff --git a/libgo/go/debug/dwarf/typeunit.go b/libgo/go/debug/dwarf/typeunit.go index 3fd1c9973e5..9cfb4a8b256 100644 --- a/libgo/go/debug/dwarf/typeunit.go +++ b/libgo/go/debug/dwarf/typeunit.go @@ -27,21 +27,15 @@ func (d *Data) parseTypes(name string, types []byte) error { b := makeBuf(d, unknownFormat{}, name, 0, types) for len(b.data) > 0 { base := b.off - dwarf64 := false - n := b.uint32() - if n == 0xffffffff { - n64 := b.uint64() - if n64 != uint64(uint32(n64)) { - b.error("type unit length overflow") - return b.err - } - n = uint32(n64) - dwarf64 = true + n, dwarf64 := b.unitLength() + if n != Offset(uint32(n)) { + b.error("type unit length overflow") + return b.err } hdroff := b.off - vers := b.uint16() + vers := int(b.uint16()) if vers != 4 { - b.error("unsupported DWARF version " + strconv.Itoa(int(vers))) + b.error("unsupported DWARF version " + strconv.Itoa(vers)) return b.err } var ao uint32 @@ -55,7 +49,7 @@ func (d *Data) parseTypes(name string, types []byte) error { } ao = uint32(ao64) } - atable, err := d.parseAbbrev(ao) + atable, err := d.parseAbbrev(ao, vers) if err != nil { return err } @@ -79,7 +73,7 @@ func (d *Data) parseTypes(name string, types []byte) error { unit: unit{ base: base, off: boff, - data: b.bytes(int(Offset(n) - (b.off - hdroff))), + data: b.bytes(int(n - (b.off - hdroff))), atable: atable, asize: int(asize), vers: int(vers), @@ -135,6 +129,11 @@ func (tur *typeUnitReader) Seek(off Offset) { tur.b = makeBuf(tur.d, tur.tu, tur.tu.name, off, tur.tu.data[doff:]) } +// AddressSize returns the size in bytes of addresses in the current type unit. +func (tur *typeUnitReader) AddressSize() int { + return tur.tu.unit.asize +} + // Next reads the next Entry from the type unit. func (tur *typeUnitReader) Next() (*Entry, error) { if tur.err != nil { diff --git a/libgo/go/debug/dwarf/unit.go b/libgo/go/debug/dwarf/unit.go index be6093519d5..ceb6cdbff32 100644 --- a/libgo/go/debug/dwarf/unit.go +++ b/libgo/go/debug/dwarf/unit.go @@ -4,23 +4,22 @@ package dwarf -import "strconv" +import ( + "sort" + "strconv" +) // DWARF debug info is split into a sequence of compilation units. // Each unit has its own abbreviation table and address size. type unit struct { - base Offset // byte offset of header within the aggregate info - off Offset // byte offset of data within the aggregate info - lineoff Offset // byte offset of data within the line info - data []byte - atable abbrevTable - asize int - vers int - is64 bool // True for 64-bit DWARF format - dir string - pc []addrRange // PC ranges in this compilation unit - lines []mapLineInfo // PC -> line mapping + base Offset // byte offset of header within the aggregate info + off Offset // byte offset of data within the aggregate info + data []byte + atable abbrevTable + asize int + vers int + is64 bool // True for 64-bit DWARF format } // Implement the dataFormat interface. @@ -37,25 +36,15 @@ func (u *unit) addrsize() int { return u.asize } -// A range is an address range. -type addrRange struct { - low uint64 - high uint64 -} - func (d *Data) parseUnits() ([]unit, error) { // Count units. nunit := 0 b := makeBuf(d, unknownFormat{}, "info", 0, d.info) for len(b.data) > 0 { - len := b.uint32() - if len == 0xffffffff { - len64 := b.uint64() - if len64 != uint64(uint32(len64)) { - b.error("unit length overflow") - break - } - len = uint32(len64) + len, _ := b.unitLength() + if len != Offset(uint32(len)) { + b.error("unit length overflow") + break } b.skip(int(len)) nunit++ @@ -70,18 +59,15 @@ func (d *Data) parseUnits() ([]unit, error) { for i := range units { u := &units[i] u.base = b.off - n := b.uint32() - if n == 0xffffffff { - u.is64 = true - n = uint32(b.uint64()) - } + var n Offset + n, u.is64 = b.unitLength() vers := b.uint16() if vers != 2 && vers != 3 && vers != 4 { b.error("unsupported DWARF version " + strconv.Itoa(int(vers))) break } u.vers = int(vers) - atable, err := d.parseAbbrev(b.uint32()) + atable, err := d.parseAbbrev(b.uint32(), u.vers) if err != nil { if b.err == nil { b.err = err @@ -98,3 +84,20 @@ func (d *Data) parseUnits() ([]unit, error) { } return units, nil } + +// offsetToUnit returns the index of the unit containing offset off. +// It returns -1 if no unit contains this offset. +func (d *Data) offsetToUnit(off Offset) int { + // Find the unit after off + next := sort.Search(len(d.unit), func(i int) bool { + return d.unit[i].off > off + }) + if next == 0 { + return -1 + } + u := &d.unit[next-1] + if u.off <= off && off < u.off+Offset(len(u.data)) { + return next - 1 + } + return -1 +} diff --git a/libgo/go/debug/elf/elf.go b/libgo/go/debug/elf/elf.go index a9466bbdcd6..c97ccaa4c1c 100644 --- a/libgo/go/debug/elf/elf.go +++ b/libgo/go/debug/elf/elf.go @@ -312,7 +312,7 @@ const ( SHN_HIOS SectionIndex = 0xff3f /* Last operating system-specific. */ SHN_ABS SectionIndex = 0xfff1 /* Absolute values. */ SHN_COMMON SectionIndex = 0xfff2 /* Common data. */ - SHN_XINDEX SectionIndex = 0xffff /* Escape -- index stored elsewhere. */ + SHN_XINDEX SectionIndex = 0xffff /* Escape; index stored elsewhere. */ SHN_HIRESERVE SectionIndex = 0xffff /* Last of reserved range. */ ) @@ -1414,7 +1414,7 @@ var rppcStrings = []intName{ func (i R_PPC) String() string { return stringName(uint32(i), rppcStrings, false) } func (i R_PPC) GoString() string { return stringName(uint32(i), rppcStrings, true) } -// Relocation types for PowerPC 64. +// Relocation types for 64-bit PowerPC or Power Architecture processors. type R_PPC64 int const ( diff --git a/libgo/go/debug/elf/file.go b/libgo/go/debug/elf/file.go index 0135f7f8dbf..370c5e6437c 100644 --- a/libgo/go/debug/elf/file.go +++ b/libgo/go/debug/elf/file.go @@ -13,6 +13,7 @@ import ( "fmt" "io" "os" + "strings" ) // TODO: error reporting detail @@ -523,26 +524,24 @@ func (f *File) Section(name string) *Section { // applyRelocations applies relocations to dst. rels is a relocations section // in RELA format. func (f *File) applyRelocations(dst []byte, rels []byte) error { - if f.Class == ELFCLASS64 && f.Machine == EM_X86_64 { + switch { + case f.Class == ELFCLASS64 && f.Machine == EM_X86_64: return f.applyRelocationsAMD64(dst, rels) - } - if f.Class == ELFCLASS32 && f.Machine == EM_386 { + case f.Class == ELFCLASS32 && f.Machine == EM_386: return f.applyRelocations386(dst, rels) - } - if f.Class == ELFCLASS64 && f.Machine == EM_AARCH64 { + case f.Class == ELFCLASS32 && f.Machine == EM_ARM: + return f.applyRelocationsARM(dst, rels) + case f.Class == ELFCLASS64 && f.Machine == EM_AARCH64: return f.applyRelocationsARM64(dst, rels) - } - if f.Class == ELFCLASS32 && f.Machine == EM_PPC { + case f.Class == ELFCLASS32 && f.Machine == EM_PPC: return f.applyRelocationsPPC(dst, rels) - } - if f.Class == ELFCLASS64 && f.Machine == EM_PPC64 { + case f.Class == ELFCLASS64 && f.Machine == EM_PPC64: return f.applyRelocationsPPC64(dst, rels) - } - if f.Class == ELFCLASS64 && f.Machine == EM_S390 { + case f.Class == ELFCLASS64 && f.Machine == EM_S390: return f.applyRelocationsS390x(dst, rels) + default: + return errors.New("applyRelocations: not implemented") } - - return errors.New("not implemented") } func (f *File) applyRelocationsAMD64(dst []byte, rels []byte) error { @@ -631,6 +630,44 @@ func (f *File) applyRelocations386(dst []byte, rels []byte) error { return nil } +func (f *File) applyRelocationsARM(dst []byte, rels []byte) error { + // 8 is the size of Rel32. + if len(rels)%8 != 0 { + return errors.New("length of relocation section is not a multiple of 8") + } + + symbols, _, err := f.getSymbols(SHT_SYMTAB) + if err != nil { + return err + } + + b := bytes.NewReader(rels) + var rel Rel32 + + for b.Len() > 0 { + binary.Read(b, f.ByteOrder, &rel) + symNo := rel.Info >> 8 + t := R_ARM(rel.Info & 0xff) + + if symNo == 0 || symNo > uint32(len(symbols)) { + continue + } + sym := &symbols[symNo-1] + + switch t { + case R_ARM_ABS32: + if rel.Off+4 >= uint32(len(dst)) { + continue + } + val := f.ByteOrder.Uint32(dst[rel.Off : rel.Off+4]) + val += uint32(sym.Value) + f.ByteOrder.PutUint32(dst[rel.Off:rel.Off+4], val) + } + } + + return nil +} + func (f *File) applyRelocationsARM64(dst []byte, rels []byte) error { // 24 is the size of Rela64. if len(rels)%24 != 0 { @@ -807,53 +844,52 @@ func (f *File) applyRelocationsS390x(dst []byte, rels []byte) error { } func (f *File) DWARF() (*dwarf.Data, error) { - // There are many other DWARF sections, but these - // are the required ones, and the debug/dwarf package - // does not use the others, so don't bother loading them. - var names = [...]string{"abbrev", "info", "line", "ranges", "str"} - var dat [len(names)][]byte - for i, name := range names { - name = ".debug_" + name - s := f.Section(name) - if s == nil { - continue - } + // sectionData gets the data for s, checks its size, and + // applies any applicable relations. + sectionData := func(i int, s *Section) ([]byte, error) { b, err := s.Data() if err != nil && uint64(len(b)) < s.Size { return nil, err } - dat[i] = b - } - // If there's a relocation table for .debug_info, we have to process it - // now otherwise the data in .debug_info is invalid for x86-64 objects. - rela := f.Section(".rela.debug_info") - if rela != nil && rela.Type == SHT_RELA && (f.Machine == EM_X86_64 || f.Machine == EM_AARCH64 || f.Machine == EM_PPC || f.Machine == EM_PPC64 || f.Machine == EM_S390) { - data, err := rela.Data() - if err != nil { - return nil, err - } - err = f.applyRelocations(dat[1], data) - if err != nil { - return nil, err + for _, r := range f.Sections { + if r.Type != SHT_RELA && r.Type != SHT_REL { + continue + } + if int(r.Info) != i { + continue + } + rd, err := r.Data() + if err != nil { + return nil, err + } + err = f.applyRelocations(b, rd) + if err != nil { + return nil, err + } } + return b, nil } - // When using clang we need to process relocations even for 386. - rel := f.Section(".rel.debug_info") - if rel != nil && rel.Type == SHT_REL && f.Machine == EM_386 { - data, err := rel.Data() - if err != nil { - return nil, err + // There are many other DWARF sections, but these + // are the ones the debug/dwarf package uses. + // Don't bother loading others. + var dat = map[string][]byte{"abbrev": nil, "info": nil, "str": nil, "line": nil, "ranges": nil} + for i, s := range f.Sections { + if !strings.HasPrefix(s.Name, ".debug_") { + continue + } + if _, ok := dat[s.Name[7:]]; !ok { + continue } - err = f.applyRelocations(dat[1], data) + b, err := sectionData(i, s) if err != nil { return nil, err } + dat[s.Name[7:]] = b } - abbrev, info, line, ranges, str := dat[0], dat[1], dat[2], dat[3], dat[4] - d, err := dwarf.New(abbrev, nil, nil, info, line, nil, ranges, str) + d, err := dwarf.New(dat["abbrev"], nil, nil, dat["info"], dat["line"], nil, dat["ranges"], dat["str"]) if err != nil { return nil, err } @@ -861,28 +897,11 @@ func (f *File) DWARF() (*dwarf.Data, error) { // Look for DWARF4 .debug_types sections. for i, s := range f.Sections { if s.Name == ".debug_types" { - b, err := s.Data() - if err != nil && uint64(len(b)) < s.Size { + b, err := sectionData(i, s) + if err != nil { return nil, err } - for _, r := range f.Sections { - if r.Type != SHT_RELA && r.Type != SHT_REL { - continue - } - if int(r.Info) != i { - continue - } - rd, err := r.Data() - if err != nil { - return nil, err - } - err = f.applyRelocations(b, rd) - if err != nil { - return nil, err - } - } - err = d.AddTypes(fmt.Sprintf("types-%d", i), b) if err != nil { return nil, err diff --git a/libgo/go/debug/elf/file_test.go b/libgo/go/debug/elf/file_test.go index 56e2604d9d3..1ad43146ac8 100644 --- a/libgo/go/debug/elf/file_test.go +++ b/libgo/go/debug/elf/file_test.go @@ -245,50 +245,62 @@ var relocationTests = []relocationTest{ { "testdata/go-relocation-test-gcc441-x86-64.obj", []relocationTestEntry{ - {0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "go-relocation-test.c"}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: uint64(0x6)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}}}, + {0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1", Class: dwarf.ClassString}, {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrName, Val: "go-relocation-test.c", Class: dwarf.ClassString}, {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress}, {Attr: dwarf.AttrHighpc, Val: uint64(0x6), Class: dwarf.ClassAddress}, {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr}}}}, }, }, { "testdata/go-relocation-test-gcc441-x86.obj", []relocationTestEntry{ - {0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "t.c"}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: uint64(0x5)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}}}, + {0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1", Class: dwarf.ClassString}, {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrName, Val: "t.c", Class: dwarf.ClassString}, {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress}, {Attr: dwarf.AttrHighpc, Val: uint64(0x5), Class: dwarf.ClassAddress}, {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr}}}}, }, }, { "testdata/go-relocation-test-gcc424-x86-64.obj", []relocationTestEntry{ - {0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.2.4 (Ubuntu 4.2.4-1ubuntu4)"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc424.c"}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: uint64(0x6)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}}}, + {0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.2.4 (Ubuntu 4.2.4-1ubuntu4)", Class: dwarf.ClassString}, {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc424.c", Class: dwarf.ClassString}, {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress}, {Attr: dwarf.AttrHighpc, Val: uint64(0x6), Class: dwarf.ClassAddress}, {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr}}}}, }, }, { - "testdata/go-relocation-test-gcc5-ppc.obj", + "testdata/go-relocation-test-gcc482-aarch64.obj", []relocationTestEntry{ - {0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{dwarf.Field{Attr: dwarf.AttrProducer, Val: "GNU C11 5.0.0 20150116 (experimental) -Asystem=linux -Asystem=unix -Asystem=posix -g"}, dwarf.Field{Attr: dwarf.AttrLanguage, Val: int64(12)}, dwarf.Field{Attr: dwarf.AttrName, Val: "go-relocation-test-gcc5-ppc.c"}, dwarf.Field{Attr: dwarf.AttrCompDir, Val: "/tmp"}, dwarf.Field{Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, dwarf.Field{Attr: dwarf.AttrHighpc, Val: int64(0x44)}, dwarf.Field{Attr: dwarf.AttrStmtList, Val: int64(0)}}}}, + {0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.8.2 -g -fstack-protector", Class: dwarf.ClassString}, {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc482.c", Class: dwarf.ClassString}, {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress}, {Attr: dwarf.AttrHighpc, Val: int64(0x24), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr}}}}, }, }, { - "testdata/go-relocation-test-gcc482-ppc64le.obj", + "testdata/go-relocation-test-gcc492-arm.obj", []relocationTestEntry{ - {0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{dwarf.Field{Attr: dwarf.AttrProducer, Val: "GNU C 4.8.2 -Asystem=linux -Asystem=unix -Asystem=posix -msecure-plt -mtune=power8 -mcpu=power7 -gdwarf-2 -fstack-protector"}, dwarf.Field{Attr: dwarf.AttrLanguage, Val: int64(1)}, dwarf.Field{Attr: dwarf.AttrName, Val: "go-relocation-test-gcc482-ppc64le.c"}, dwarf.Field{Attr: dwarf.AttrCompDir, Val: "/tmp"}, dwarf.Field{Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, dwarf.Field{Attr: dwarf.AttrHighpc, Val: uint64(0x24)}, dwarf.Field{Attr: dwarf.AttrStmtList, Val: int64(0)}}}}, + {0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.9.2 20141224 (prerelease) -march=armv7-a -mfloat-abi=hard -mfpu=vfpv3-d16 -mtls-dialect=gnu -g", Class: dwarf.ClassString}, {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc492.c", Class: dwarf.ClassString}, {Attr: dwarf.AttrCompDir, Val: "/root/go/src/debug/elf/testdata", Class: dwarf.ClassString}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress}, {Attr: dwarf.AttrHighpc, Val: int64(0x28), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr}}}}, }, }, { - "testdata/go-relocation-test-gcc482-aarch64.obj", + "testdata/go-relocation-test-clang-arm.obj", + []relocationTestEntry{ + {0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{dwarf.Field{Attr: dwarf.AttrProducer, Val: "Debian clang version 3.5.0-10 (tags/RELEASE_350/final) (based on LLVM 3.5.0)", Class: dwarf.ClassString}, dwarf.Field{Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant}, dwarf.Field{Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString}, dwarf.Field{Attr: dwarf.AttrStmtList, Val: int64(0x0), Class: dwarf.ClassLinePtr}, dwarf.Field{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}, dwarf.Field{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress}, dwarf.Field{Attr: dwarf.AttrHighpc, Val: int64(48), Class: dwarf.ClassConstant}}}}, + }, + }, + { + "testdata/go-relocation-test-gcc5-ppc.obj", + []relocationTestEntry{ + {0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{dwarf.Field{Attr: dwarf.AttrProducer, Val: "GNU C11 5.0.0 20150116 (experimental) -Asystem=linux -Asystem=unix -Asystem=posix -g", Class: dwarf.ClassString}, dwarf.Field{Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant}, dwarf.Field{Attr: dwarf.AttrName, Val: "go-relocation-test-gcc5-ppc.c", Class: dwarf.ClassString}, dwarf.Field{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}, dwarf.Field{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress}, dwarf.Field{Attr: dwarf.AttrHighpc, Val: int64(0x44), Class: dwarf.ClassConstant}, dwarf.Field{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr}}}}, + }, + }, + { + "testdata/go-relocation-test-gcc482-ppc64le.obj", []relocationTestEntry{ - {0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.8.2 -g -fstack-protector"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc482.c"}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: int64(0x24)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}}}, + {0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{dwarf.Field{Attr: dwarf.AttrProducer, Val: "GNU C 4.8.2 -Asystem=linux -Asystem=unix -Asystem=posix -msecure-plt -mtune=power8 -mcpu=power7 -gdwarf-2 -fstack-protector", Class: dwarf.ClassString}, dwarf.Field{Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant}, dwarf.Field{Attr: dwarf.AttrName, Val: "go-relocation-test-gcc482-ppc64le.c", Class: dwarf.ClassString}, dwarf.Field{Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}, dwarf.Field{Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress}, dwarf.Field{Attr: dwarf.AttrHighpc, Val: uint64(0x24), Class: dwarf.ClassAddress}, dwarf.Field{Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr}}}}, }, }, { "testdata/go-relocation-test-clang-x86.obj", []relocationTestEntry{ - {0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "clang version google3-trunk (trunk r209387)"}, {Attr: dwarf.AttrLanguage, Val: int64(12)}, {Attr: dwarf.AttrName, Val: "go-relocation-test-clang.c"}, {Attr: dwarf.AttrStmtList, Val: int64(0)}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}}}}, + {0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "clang version google3-trunk (trunk r209387)", Class: dwarf.ClassString}, {Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrName, Val: "go-relocation-test-clang.c", Class: dwarf.ClassString}, {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr}, {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}}}}, }, }, { "testdata/gcc-amd64-openbsd-debug-with-rela.obj", []relocationTestEntry{ - {203, &dwarf.Entry{Offset: 0xc62, Tag: dwarf.TagMember, Children: false, Field: []dwarf.Field{{Attr: dwarf.AttrName, Val: "it_interval"}, {Attr: dwarf.AttrDeclFile, Val: int64(7)}, {Attr: dwarf.AttrDeclLine, Val: int64(236)}, {Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f)}, {Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x0}}}}}, - {204, &dwarf.Entry{Offset: 0xc70, Tag: dwarf.TagMember, Children: false, Field: []dwarf.Field{{Attr: dwarf.AttrName, Val: "it_value"}, {Attr: dwarf.AttrDeclFile, Val: int64(7)}, {Attr: dwarf.AttrDeclLine, Val: int64(237)}, {Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f)}, {Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x10}}}}}, + {203, &dwarf.Entry{Offset: 0xc62, Tag: dwarf.TagMember, Children: false, Field: []dwarf.Field{{Attr: dwarf.AttrName, Val: "it_interval", Class: dwarf.ClassString}, {Attr: dwarf.AttrDeclFile, Val: int64(7), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrDeclLine, Val: int64(236), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f), Class: dwarf.ClassReference}, {Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x0}, Class: dwarf.ClassExprLoc}}}}, + {204, &dwarf.Entry{Offset: 0xc70, Tag: dwarf.TagMember, Children: false, Field: []dwarf.Field{{Attr: dwarf.AttrName, Val: "it_value", Class: dwarf.ClassString}, {Attr: dwarf.AttrDeclFile, Val: int64(7), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrDeclLine, Val: int64(237), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f), Class: dwarf.ClassReference}, {Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x10}, Class: dwarf.ClassExprLoc}}}}, }, }, } diff --git a/libgo/go/debug/elf/testdata/go-relocation-test-clang-arm.obj b/libgo/go/debug/elf/testdata/go-relocation-test-clang-arm.obj new file mode 100644 index 00000000000..1cc7e4b1114 Binary files /dev/null and b/libgo/go/debug/elf/testdata/go-relocation-test-clang-arm.obj differ diff --git a/libgo/go/debug/elf/testdata/go-relocation-test-gcc492-arm.obj b/libgo/go/debug/elf/testdata/go-relocation-test-gcc492-arm.obj new file mode 100644 index 00000000000..ed45be2c55f Binary files /dev/null and b/libgo/go/debug/elf/testdata/go-relocation-test-gcc492-arm.obj differ diff --git a/libgo/go/debug/gosym/pclntab_test.go b/libgo/go/debug/gosym/pclntab_test.go index 35502e8c395..53f3e952d62 100644 --- a/libgo/go/debug/gosym/pclntab_test.go +++ b/libgo/go/debug/gosym/pclntab_test.go @@ -6,7 +6,6 @@ package gosym import ( "debug/elf" - "fmt" "io/ioutil" "os" "os/exec" @@ -30,10 +29,6 @@ func dotest(self bool) bool { if self && runtime.GOOS != "linux" { return false } - // Command below expects "sh", so Unix. - if runtime.GOOS == "windows" || runtime.GOOS == "plan9" { - return false - } if pclinetestBinary != "" { return true } @@ -49,9 +44,14 @@ func dotest(self bool) bool { // the resulting binary looks like it was built from pclinetest.s, // but we have renamed it to keep it away from the go tool. pclinetestBinary = filepath.Join(pclineTempDir, "pclinetest") - command := fmt.Sprintf("go tool 6a -o %s.6 pclinetest.asm && go tool 6l -H linux -E main -o %s %s.6", - pclinetestBinary, pclinetestBinary, pclinetestBinary) - cmd := exec.Command("sh", "-c", command) + cmd := exec.Command("go", "tool", "asm", "-o", pclinetestBinary+".o", "pclinetest.asm") + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + panic(err) + } + cmd = exec.Command("go", "tool", "link", "-H", "linux", "-E", "main", + "-o", pclinetestBinary, pclinetestBinary+".o") cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr if err := cmd.Run(); err != nil { @@ -84,7 +84,11 @@ func crack(file string, t *testing.T) (*elf.File, *Table) { } func parse(file string, f *elf.File, t *testing.T) (*elf.File, *Table) { - symdat, err := f.Section(".gosymtab").Data() + s := f.Section(".gosymtab") + if s == nil { + t.Skip("no .gosymtab section") + } + symdat, err := s.Data() if err != nil { f.Close() t.Fatalf("reading %s gosymtab: %v", file, err) diff --git a/libgo/go/debug/gosym/symtab.go b/libgo/go/debug/gosym/symtab.go index ee18499d111..46f07833442 100644 --- a/libgo/go/debug/gosym/symtab.go +++ b/libgo/go/debug/gosym/symtab.go @@ -30,7 +30,7 @@ type Sym struct { Type byte Name string GoType uint64 - // If this symbol if a function symbol, the corresponding Func + // If this symbol is a function symbol, the corresponding Func Func *Func } diff --git a/libgo/go/debug/macho/file.go b/libgo/go/debug/macho/file.go index da13c510064..a7599aa5b2b 100644 --- a/libgo/go/debug/macho/file.go +++ b/libgo/go/debug/macho/file.go @@ -472,8 +472,8 @@ func (f *File) Section(name string) *Section { // DWARF returns the DWARF debug information for the Mach-O file. func (f *File) DWARF() (*dwarf.Data, error) { // There are many other DWARF sections, but these - // are the required ones, and the debug/dwarf package - // does not use the others, so don't bother loading them. + // are the ones the debug/dwarf package uses. + // Don't bother loading others. var names = [...]string{"abbrev", "info", "line", "str"} var dat [len(names)][]byte for i, name := range names { diff --git a/libgo/go/debug/pe/file.go b/libgo/go/debug/pe/file.go index 759e5674fd6..3df4ae73681 100644 --- a/libgo/go/debug/pe/file.go +++ b/libgo/go/debug/pe/file.go @@ -296,9 +296,9 @@ func (f *File) Section(name string) *Section { func (f *File) DWARF() (*dwarf.Data, error) { // There are many other DWARF sections, but these - // are the required ones, and the debug/dwarf package - // does not use the others, so don't bother loading them. - var names = [...]string{"abbrev", "info", "str"} + // are the ones the debug/dwarf package uses. + // Don't bother loading others. + var names = [...]string{"abbrev", "info", "line", "str"} var dat [len(names)][]byte for i, name := range names { name = ".debug_" + name @@ -310,11 +310,14 @@ func (f *File) DWARF() (*dwarf.Data, error) { if err != nil && uint32(len(b)) < s.Size { return nil, err } + if 0 < s.VirtualSize && s.VirtualSize < s.Size { + b = b[:s.VirtualSize] + } dat[i] = b } - abbrev, info, str := dat[0], dat[1], dat[2] - return dwarf.New(abbrev, nil, nil, info, nil, nil, nil, str) + abbrev, info, line, str := dat[0], dat[1], dat[2], dat[3] + return dwarf.New(abbrev, nil, nil, info, line, nil, nil, str) } // ImportedSymbols returns the names of all symbols diff --git a/libgo/go/debug/pe/file_test.go b/libgo/go/debug/pe/file_test.go index 0d73969bca9..316a569ede9 100644 --- a/libgo/go/debug/pe/file_test.go +++ b/libgo/go/debug/pe/file_test.go @@ -5,24 +5,30 @@ package pe import ( + "debug/dwarf" + "io/ioutil" + "os" + "os/exec" + "path/filepath" "reflect" + "runtime" "testing" ) type fileTest struct { - file string - hdr FileHeader - opthdr interface{} - sections []*SectionHeader - symbols []*Symbol + file string + hdr FileHeader + opthdr interface{} + sections []*SectionHeader + symbols []*Symbol + hasNoDwarfInfo bool } var fileTests = []fileTest{ { - "testdata/gcc-386-mingw-obj", - FileHeader{0x014c, 0x000c, 0x0, 0x64a, 0x1e, 0x0, 0x104}, - nil, - []*SectionHeader{ + file: "testdata/gcc-386-mingw-obj", + hdr: FileHeader{0x014c, 0x000c, 0x0, 0x64a, 0x1e, 0x0, 0x104}, + sections: []*SectionHeader{ {".text", 0, 0, 36, 500, 1440, 0, 3, 0, 0x60300020}, {".data", 0, 0, 0, 0, 0, 0, 0, 0, 3224371264}, {".bss", 0, 0, 0, 0, 0, 0, 0, 0, 3224371328}, @@ -36,7 +42,7 @@ var fileTests = []fileTest{ {".debug_pubtypes", 0, 0, 38, 1370, 1580, 0, 1, 0, 1108344832}, {".debug_aranges", 0, 0, 32, 1408, 1590, 0, 2, 0, 1108344832}, }, - []*Symbol{ + symbols: []*Symbol{ {".file", 0x0, -2, 0x0, 0x67}, {"_main", 0x0, 1, 0x20, 0x2}, {".text", 0x0, 1, 0x0, 0x3}, @@ -56,9 +62,9 @@ var fileTests = []fileTest{ }, }, { - "testdata/gcc-386-mingw-exec", - FileHeader{0x014c, 0x000f, 0x4c6a1b60, 0x3c00, 0x282, 0xe0, 0x107}, - &OptionalHeader32{ + file: "testdata/gcc-386-mingw-exec", + hdr: FileHeader{0x014c, 0x000f, 0x4c6a1b60, 0x3c00, 0x282, 0xe0, 0x107}, + opthdr: &OptionalHeader32{ 0x10b, 0x2, 0x38, 0xe00, 0x1a00, 0x200, 0x1160, 0x1000, 0x2000, 0x400000, 0x1000, 0x200, 0x4, 0x0, 0x1, 0x0, 0x4, 0x0, 0x0, 0x10000, 0x400, 0x14abb, 0x3, 0x0, 0x200000, 0x1000, 0x100000, 0x1000, 0x0, 0x10, [16]DataDirectory{ {0x0, 0x0}, @@ -79,7 +85,7 @@ var fileTests = []fileTest{ {0x0, 0x0}, }, }, - []*SectionHeader{ + sections: []*SectionHeader{ {".text", 0xcd8, 0x1000, 0xe00, 0x400, 0x0, 0x0, 0x0, 0x0, 0x60500060}, {".data", 0x10, 0x2000, 0x200, 0x1200, 0x0, 0x0, 0x0, 0x0, 0xc0300040}, {".rdata", 0x120, 0x3000, 0x200, 0x1400, 0x0, 0x0, 0x0, 0x0, 0x40300040}, @@ -96,13 +102,11 @@ var fileTests = []fileTest{ {".debug_frame", 0x34, 0xe000, 0x200, 0x3800, 0x0, 0x0, 0x0, 0x0, 0x42300000}, {".debug_loc", 0x38, 0xf000, 0x200, 0x3a00, 0x0, 0x0, 0x0, 0x0, 0x42100000}, }, - []*Symbol{}, }, { - "testdata/gcc-amd64-mingw-obj", - FileHeader{0x8664, 0x6, 0x0, 0x198, 0x12, 0x0, 0x4}, - nil, - []*SectionHeader{ + file: "testdata/gcc-amd64-mingw-obj", + hdr: FileHeader{0x8664, 0x6, 0x0, 0x198, 0x12, 0x0, 0x4}, + sections: []*SectionHeader{ {".text", 0x0, 0x0, 0x30, 0x104, 0x15c, 0x0, 0x3, 0x0, 0x60500020}, {".data", 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0500040}, {".bss", 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0500080}, @@ -110,7 +114,7 @@ var fileTests = []fileTest{ {".xdata", 0x0, 0x0, 0xc, 0x144, 0x0, 0x0, 0x0, 0x0, 0x40300040}, {".pdata", 0x0, 0x0, 0xc, 0x150, 0x17a, 0x0, 0x3, 0x0, 0x40300040}, }, - []*Symbol{ + symbols: []*Symbol{ {".file", 0x0, -2, 0x0, 0x67}, {"main", 0x0, 1, 0x20, 0x2}, {".text", 0x0, 1, 0x0, 0x3}, @@ -122,11 +126,12 @@ var fileTests = []fileTest{ {"__main", 0x0, 0, 0x20, 0x2}, {"puts", 0x0, 0, 0x20, 0x2}, }, + hasNoDwarfInfo: true, }, { - "testdata/gcc-amd64-mingw-exec", - FileHeader{0x8664, 0x11, 0x53e4364f, 0x39600, 0x6fc, 0xf0, 0x27}, - &OptionalHeader64{ + file: "testdata/gcc-amd64-mingw-exec", + hdr: FileHeader{0x8664, 0x11, 0x53e4364f, 0x39600, 0x6fc, 0xf0, 0x27}, + opthdr: &OptionalHeader64{ 0x20b, 0x2, 0x16, 0x6a00, 0x2400, 0x1600, 0x14e0, 0x1000, 0x400000, 0x1000, 0x200, 0x4, 0x0, 0x0, 0x0, 0x5, 0x2, 0x0, 0x45000, 0x600, 0x46f19, 0x3, 0x0, 0x200000, 0x1000, 0x100000, 0x1000, 0x0, 0x10, [16]DataDirectory{ {0x0, 0x0}, @@ -146,7 +151,7 @@ var fileTests = []fileTest{ {0x0, 0x0}, {0x0, 0x0}, }}, - []*SectionHeader{ + sections: []*SectionHeader{ {".text", 0x6860, 0x1000, 0x6a00, 0x600, 0x0, 0x0, 0x0, 0x0, 0x60500020}, {".data", 0xe0, 0x8000, 0x200, 0x7000, 0x0, 0x0, 0x0, 0x0, 0xc0500040}, {".rdata", 0x6b0, 0x9000, 0x800, 0x7200, 0x0, 0x0, 0x0, 0x0, 0x40600040}, @@ -165,7 +170,6 @@ var fileTests = []fileTest{ {".debug_loc", 0x13240, 0x30000, 0x13400, 0x25600, 0x0, 0x0, 0x0, 0x0, 0x42100040}, {".debug_ranges", 0xa70, 0x44000, 0xc00, 0x38a00, 0x0, 0x0, 0x0, 0x0, 0x42100040}, }, - []*Symbol{}, }, } @@ -231,6 +235,12 @@ func TestOpen(t *testing.T) { t.Errorf("open %s, symbol %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want) } } + if !tt.hasNoDwarfInfo { + _, err = f.DWARF() + if err != nil { + t.Errorf("fetching %s dwarf details failed: %v", tt.file, err) + } + } } } @@ -241,3 +251,59 @@ func TestOpenFailure(t *testing.T) { t.Errorf("open %s: succeeded unexpectedly", filename) } } + +func TestDWARF(t *testing.T) { + if runtime.GOOS != "windows" { + t.Skip("skipping windows only test") + } + + tmpdir, err := ioutil.TempDir("", "TestDWARF") + if err != nil { + t.Fatal("TempDir failed: ", err) + } + defer os.RemoveAll(tmpdir) + + prog := ` +package main +func main() { +} +` + src := filepath.Join(tmpdir, "a.go") + exe := filepath.Join(tmpdir, "a.exe") + err = ioutil.WriteFile(src, []byte(prog), 0644) + output, err := exec.Command("go", "build", "-o", exe, src).CombinedOutput() + if err != nil { + t.Fatalf("building test executable failed: %s %s", err, output) + } + + f, err := Open(exe) + if err != nil { + t.Fatal(err) + } + defer f.Close() + + d, err := f.DWARF() + if err != nil { + t.Fatal(err) + } + + // look for main.main + r := d.Reader() + for { + e, err := r.Next() + if err != nil { + t.Fatal("r.Next:", err) + } + if e == nil { + break + } + if e.Tag == dwarf.TagSubprogram { + for _, f := range e.Field { + if f.Attr == dwarf.AttrName && e.Val(dwarf.AttrName) == "main.main" { + return + } + } + } + } + t.Fatal("main.main not found") +} diff --git a/libgo/go/encoding/asn1/asn1.go b/libgo/go/encoding/asn1/asn1.go index 8b3d1b34121..2ac411af882 100644 --- a/libgo/go/encoding/asn1/asn1.go +++ b/libgo/go/encoding/asn1/asn1.go @@ -20,11 +20,13 @@ package asn1 // everything by any means. import ( + "errors" "fmt" "math/big" "reflect" "strconv" "time" + "unicode/utf8" ) // A StructuralError suggests that the ASN.1 data is valid, but the Go type @@ -287,11 +289,23 @@ 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) + + formatStr := "0601021504Z0700" + ret, err = time.Parse(formatStr, s) + if err != nil { + formatStr = "060102150405Z0700" + ret, err = time.Parse(formatStr, s) + } if err != nil { - ret, err = time.Parse("060102150405Z0700", s) + return } - if err == nil && ret.Year() >= 2050 { + + if serialized := ret.Format(formatStr); serialized != s { + err = fmt.Errorf("asn1: time did not serialize back to the original value and may be invalid: given %q, but serialized as %q", s, serialized) + return + } + + if 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) } @@ -302,7 +316,18 @@ func parseUTCTime(bytes []byte) (ret time.Time, err error) { // parseGeneralizedTime parses the GeneralizedTime from the given byte slice // and returns the resulting time. func parseGeneralizedTime(bytes []byte) (ret time.Time, err error) { - return time.Parse("20060102150405Z0700", string(bytes)) + const formatStr = "20060102150405Z0700" + s := string(bytes) + + if ret, err = time.Parse(formatStr, s); err != nil { + return + } + + if serialized := ret.Format(formatStr); serialized != s { + err = fmt.Errorf("asn1: time did not serialize back to the original value and may be invalid: given %q, but serialized as %q", s, serialized) + } + + return } // PrintableString @@ -320,7 +345,7 @@ func parsePrintableString(bytes []byte) (ret string, err error) { return } -// isPrintable returns true iff the given b is in the ASN.1 PrintableString set. +// isPrintable reports whether the given b is in the ASN.1 PrintableString set. func isPrintable(b byte) bool { return 'a' <= b && b <= 'z' || 'A' <= b && b <= 'Z' || @@ -365,6 +390,9 @@ func parseT61String(bytes []byte) (ret string, err error) { // parseUTF8String parses a ASN.1 UTF8String (raw UTF-8) from the given byte // array and returns it. func parseUTF8String(bytes []byte) (ret string, err error) { + if !utf8.Valid(bytes) { + return "", errors.New("asn1: invalid UTF-8 string") + } return string(bytes), nil } @@ -389,6 +417,12 @@ type RawContent []byte // don't distinguish between ordered and unordered objects in this code. func parseTagAndLength(bytes []byte, initOffset int) (ret tagAndLength, offset int, err error) { offset = initOffset + // parseTagAndLength should not be called without at least a single + // byte to read. Thus this check is for robustness: + if offset >= len(bytes) { + err = errors.New("asn1: internal error in parseTagAndLength") + return + } b := bytes[offset] offset++ ret.class = int(b >> 6) @@ -579,6 +613,8 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam result, err = parseObjectIdentifier(innerBytes) case tagUTCTime: result, err = parseUTCTime(innerBytes) + case tagGeneralizedTime: + result, err = parseGeneralizedTime(innerBytes) case tagOctetString: result = innerBytes default: @@ -609,6 +645,10 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam if params.application { expectedClass = classApplication } + if offset == len(bytes) { + err = StructuralError{"explicit tag has no child"} + return + } if t.class == expectedClass && t.tag == *params.tag && (t.length == 0 || t.isCompound) { if t.length > 0 { t, offset, err = parseTagAndLength(bytes, offset) diff --git a/libgo/go/encoding/asn1/asn1_test.go b/libgo/go/encoding/asn1/asn1_test.go index 4e864d08ac0..893d0801b00 100644 --- a/libgo/go/encoding/asn1/asn1_test.go +++ b/libgo/go/encoding/asn1/asn1_test.go @@ -9,6 +9,7 @@ import ( "fmt" "math/big" "reflect" + "strings" "testing" "time" ) @@ -258,6 +259,24 @@ var utcTestData = []timeTest{ {"91050633444aZ", false, time.Time{}}, {"910506334461Z", false, time.Time{}}, {"910506334400Za", false, time.Time{}}, + /* These are invalid times. However, the time package normalises times + * and they were accepted in some versions. See #11134. */ + {"000100000000Z", false, time.Time{}}, + {"101302030405Z", false, time.Time{}}, + {"100002030405Z", false, time.Time{}}, + {"100100030405Z", false, time.Time{}}, + {"100132030405Z", false, time.Time{}}, + {"100231030405Z", false, time.Time{}}, + {"100102240405Z", false, time.Time{}}, + {"100102036005Z", false, time.Time{}}, + {"100102030460Z", false, time.Time{}}, + {"-100102030410Z", false, time.Time{}}, + {"10-0102030410Z", false, time.Time{}}, + {"10-0002030410Z", false, time.Time{}}, + {"1001-02030410Z", false, time.Time{}}, + {"100102-030410Z", false, time.Time{}}, + {"10010203-0410Z", false, time.Time{}}, + {"1001020304-10Z", false, time.Time{}}, } func TestUTCTime(t *testing.T) { @@ -287,6 +306,24 @@ var generalizedTimeTestData = []timeTest{ {"20100102030405", false, time.Time{}}, {"20100102030405+0607", true, time.Date(2010, 01, 02, 03, 04, 05, 0, time.FixedZone("", 6*60*60+7*60))}, {"20100102030405-0607", true, time.Date(2010, 01, 02, 03, 04, 05, 0, time.FixedZone("", -6*60*60-7*60))}, + /* These are invalid times. However, the time package normalises times + * and they were accepted in some versions. See #11134. */ + {"00000100000000Z", false, time.Time{}}, + {"20101302030405Z", false, time.Time{}}, + {"20100002030405Z", false, time.Time{}}, + {"20100100030405Z", false, time.Time{}}, + {"20100132030405Z", false, time.Time{}}, + {"20100231030405Z", false, time.Time{}}, + {"20100102240405Z", false, time.Time{}}, + {"20100102036005Z", false, time.Time{}}, + {"20100102030460Z", false, time.Time{}}, + {"-20100102030410Z", false, time.Time{}}, + {"2010-0102030410Z", false, time.Time{}}, + {"2010-0002030410Z", false, time.Time{}}, + {"201001-02030410Z", false, time.Time{}}, + {"20100102-030410Z", false, time.Time{}}, + {"2010010203-0410Z", false, time.Time{}}, + {"201001020304-10Z", false, time.Time{}}, } func TestGeneralizedTime(t *testing.T) { @@ -297,7 +334,7 @@ func TestGeneralizedTime(t *testing.T) { } if err == nil { if !reflect.DeepEqual(test.out, ret) { - t.Errorf("#%d: Bad result: %v (expected %v)", i, ret, test.out) + t.Errorf("#%d: Bad result: %q → %v (expected %v)", i, test.in, ret, test.out) } } } @@ -358,6 +395,8 @@ func newBool(b bool) *bool { return &b } var parseFieldParametersTestData []parseFieldParametersTest = []parseFieldParametersTest{ {"", fieldParameters{}}, {"ia5", fieldParameters{stringType: tagIA5String}}, + {"generalized", fieldParameters{timeType: tagGeneralizedTime}}, + {"utc", fieldParameters{timeType: tagUTCTime}}, {"printable", fieldParameters{stringType: tagPrintableString}}, {"optional", fieldParameters{optional: true}}, {"explicit", fieldParameters{explicit: true, tag: new(int)}}, @@ -366,7 +405,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, false}}, + {"optional,explicit,default:42,tag:17,rubbish1", fieldParameters{true, true, false, newInt64(42), newInt(17), 0, 0, false, false}}, {"set", fieldParameters{set: true}}, } @@ -865,3 +904,39 @@ func TestImplicitTaggedTime(t *testing.T) { t.Errorf("Wrong result. Got %v, want %v", result.Time, expected) } } + +type truncatedExplicitTagTest struct { + Test int `asn1:"explicit,tag:0"` +} + +func TestTruncatedExplicitTag(t *testing.T) { + // This crashed Unmarshal in the past. See #11154. + der := []byte{ + 0x30, // SEQUENCE + 0x02, // two bytes long + 0xa0, // context-specific, tag 0 + 0x30, // 48 bytes long + } + + var result truncatedExplicitTagTest + if _, err := Unmarshal(der, &result); err == nil { + t.Error("Unmarshal returned without error") + } +} + +type invalidUTF8Test struct { + Str string `asn1:"utf8"` +} + +func TestUnmarshalInvalidUTF8(t *testing.T) { + data := []byte("0\x05\f\x03a\xc9c") + var result invalidUTF8Test + _, err := Unmarshal(data, &result) + + const expectedSubstring = "UTF" + if err == nil { + t.Fatal("Successfully unmarshaled invalid UTF-8 data") + } else if !strings.Contains(err.Error(), expectedSubstring) { + t.Fatalf("Expected error to mention %q but error was %q", expectedSubstring, err.Error()) + } +} diff --git a/libgo/go/encoding/asn1/common.go b/libgo/go/encoding/asn1/common.go index 33a117ece19..ab85e0496ff 100644 --- a/libgo/go/encoding/asn1/common.go +++ b/libgo/go/encoding/asn1/common.go @@ -74,6 +74,7 @@ type fieldParameters struct { defaultValue *int64 // a default value for INTEGER typed fields (maybe nil). tag *int // the EXPLICIT or IMPLICIT tag (maybe nil). stringType int // the string tag to use when marshaling. + timeType int // the time 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. @@ -94,6 +95,10 @@ func parseFieldParameters(str string) (ret fieldParameters) { if ret.tag == nil { ret.tag = new(int) } + case part == "generalized": + ret.timeType = tagGeneralizedTime + case part == "utc": + ret.timeType = tagUTCTime case part == "ia5": ret.stringType = tagIA5String case part == "printable": diff --git a/libgo/go/encoding/asn1/marshal.go b/libgo/go/encoding/asn1/marshal.go index b2f104b4cbe..67a019db2d4 100644 --- a/libgo/go/encoding/asn1/marshal.go +++ b/libgo/go/encoding/asn1/marshal.go @@ -18,7 +18,7 @@ import ( // A forkableWriter is an in-memory buffer that can be // 'forked' to create new forkableWriters that bracket the // original. After -// pre, post := w.fork(); +// pre, post := w.fork() // the overall sequence of bytes represented is logically w+pre+post. type forkableWriter struct { *bytes.Buffer @@ -410,9 +410,11 @@ func stripTagAndLength(in []byte) []byte { func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameters) (err error) { switch value.Type() { + case flagType: + return nil case timeType: t := value.Interface().(time.Time) - if outsideUTCRange(t) { + if params.timeType == tagGeneralizedTime || outsideUTCRange(t) { return marshalGeneralizedTime(out, t) } else { return marshalUTCTime(out, t) @@ -552,6 +554,10 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters) } class := classUniversal + if params.timeType != 0 && tag != tagUTCTime { + return StructuralError{"explicit time type given to non-time member"} + } + if params.stringType != 0 && tag != tagPrintableString { return StructuralError{"explicit string type given to non-string member"} } @@ -575,7 +581,7 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters) tag = params.stringType } case tagUTCTime: - if outsideUTCRange(v.Interface().(time.Time)) { + if params.timeType == tagGeneralizedTime || outsideUTCRange(v.Interface().(time.Time)) { tag = tagGeneralizedTime } } diff --git a/libgo/go/encoding/asn1/marshal_test.go b/libgo/go/encoding/asn1/marshal_test.go index 5b0115f28c5..cdca8aa3363 100644 --- a/libgo/go/encoding/asn1/marshal_test.go +++ b/libgo/go/encoding/asn1/marshal_test.go @@ -42,6 +42,14 @@ type explicitTagTest struct { A int `asn1:"explicit,tag:5"` } +type flagTest struct { + A Flag `asn1:"tag:0,optional"` +} + +type generalizedTimeTest struct { + A time.Time `asn1:"generalized"` +} + type ia5StringTest struct { A string `asn1:"ia5"` } @@ -92,10 +100,13 @@ var marshalTests = []marshalTest{ {[]byte{1, 2, 3}, "0403010203"}, {implicitTagTest{64}, "3003850140"}, {explicitTagTest{64}, "3005a503020140"}, + {flagTest{true}, "30028000"}, + {flagTest{false}, "3000"}, {time.Unix(0, 0).UTC(), "170d3730303130313030303030305a"}, {time.Unix(1258325776, 0).UTC(), "170d3039313131353232353631365a"}, {time.Unix(1258325776, 0).In(PST), "17113039313131353134353631362d30383030"}, {farFuture(), "180f32313030303430353132303130315a"}, + {generalizedTimeTest{time.Unix(1258325776, 0).UTC()}, "3011180f32303039313131353232353631365a"}, {BitString{[]byte{0x80}, 1}, "03020780"}, {BitString{[]byte{0x81, 0xf0}, 12}, "03030481f0"}, {ObjectIdentifier([]int{1, 2, 3, 4}), "06032a0304"}, diff --git a/libgo/go/encoding/base64/base64.go b/libgo/go/encoding/base64/base64.go index ad3abe66239..3302fb4a742 100644 --- a/libgo/go/encoding/base64/base64.go +++ b/libgo/go/encoding/base64/base64.go @@ -6,10 +6,8 @@ package base64 import ( - "bytes" "io" "strconv" - "strings" ) /* @@ -22,18 +20,32 @@ import ( // (RFC 1421). RFC 4648 also defines an alternate encoding, which is // the standard encoding with - and _ substituted for + and /. type Encoding struct { - encode string + encode [64]byte decodeMap [256]byte + padChar rune } +const ( + StdPadding rune = '=' // Standard padding character + NoPadding rune = -1 // No padding +) + const encodeStd = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" const encodeURL = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_" -// NewEncoding returns a new Encoding defined by the given alphabet, +// NewEncoding returns a new padded Encoding defined by the given alphabet, // which must be a 64-byte string. +// The resulting Encoding uses the default padding character ('='), +// which may be changed or disabled via WithPadding. func NewEncoding(encoder string) *Encoding { + if len(encoder) != 64 { + panic("encoding alphabet is not 64-bytes long") + } + e := new(Encoding) - e.encode = encoder + e.padChar = StdPadding + copy(e.encode[:], encoder) + for i := 0; i < len(e.decodeMap); i++ { e.decodeMap[i] = 0xFF } @@ -43,6 +55,13 @@ func NewEncoding(encoder string) *Encoding { return e } +// WithPadding creates a new encoding identical to enc except +// with a specified padding character, or NoPadding to disable padding. +func (enc Encoding) WithPadding(padding rune) *Encoding { + enc.padChar = padding + return &enc +} + // StdEncoding is the standard base64 encoding, as defined in // RFC 4648. var StdEncoding = NewEncoding(encodeStd) @@ -51,12 +70,15 @@ var StdEncoding = NewEncoding(encodeStd) // It is typically used in URLs and file names. var URLEncoding = NewEncoding(encodeURL) -var removeNewlinesMapper = func(r rune) rune { - if r == '\r' || r == '\n' { - return -1 - } - return r -} +// RawStdEncoding is the standard raw, unpadded base64 encoding, +// as defined in RFC 4648 section 3.2. +// This is the same as StdEncoding but omits padding characters. +var RawStdEncoding = StdEncoding.WithPadding(NoPadding) + +// URLEncoding is the unpadded alternate base64 encoding defined in RFC 4648. +// It is typically used in URLs and file names. +// This is the same as URLEncoding but omits padding characters. +var RawURLEncoding = URLEncoding.WithPadding(NoPadding) /* * Encoder @@ -73,42 +95,45 @@ func (enc *Encoding) Encode(dst, src []byte) { return } - for len(src) > 0 { - var b0, b1, b2, b3 byte + di, si := 0, 0 + n := (len(src) / 3) * 3 + for si < n { + // Convert 3x 8bit source bytes into 4 bytes + val := uint(src[si+0])<<16 | uint(src[si+1])<<8 | uint(src[si+2]) - // Unpack 4x 6-bit source blocks into a 4 byte - // destination quantum - switch len(src) { - default: - b3 = src[2] & 0x3F - b2 = src[2] >> 6 - fallthrough - case 2: - b2 |= (src[1] << 2) & 0x3F - b1 = src[1] >> 4 - fallthrough - case 1: - b1 |= (src[0] << 4) & 0x3F - b0 = src[0] >> 2 - } + dst[di+0] = enc.encode[val>>18&0x3F] + dst[di+1] = enc.encode[val>>12&0x3F] + dst[di+2] = enc.encode[val>>6&0x3F] + dst[di+3] = enc.encode[val&0x3F] - // Encode 6-bit blocks using the base64 alphabet - dst[0] = enc.encode[b0] - dst[1] = enc.encode[b1] - dst[2] = enc.encode[b2] - dst[3] = enc.encode[b3] - - // Pad the final quantum - if len(src) < 3 { - dst[3] = '=' - if len(src) < 2 { - dst[2] = '=' - } - break - } + si += 3 + di += 4 + } + + remain := len(src) - si + if remain == 0 { + return + } + // Add the remaining small block + val := uint(src[si+0]) << 16 + if remain == 2 { + val |= uint(src[si+1]) << 8 + } + + dst[di+0] = enc.encode[val>>18&0x3F] + dst[di+1] = enc.encode[val>>12&0x3F] - src = src[3:] - dst = dst[4:] + switch remain { + case 2: + dst[di+2] = enc.encode[val>>6&0x3F] + if enc.padChar != NoPadding { + dst[di+3] = byte(enc.padChar) + } + case 1: + if enc.padChar != NoPadding { + dst[di+2] = byte(enc.padChar) + dst[di+3] = byte(enc.padChar) + } } } @@ -145,8 +170,8 @@ func (e *encoder) Write(p []byte) (n int, err error) { if e.nbuf < 3 { return } - e.enc.Encode(e.out[0:], e.buf[0:]) - if _, e.err = e.w.Write(e.out[0:4]); e.err != nil { + e.enc.Encode(e.out[:], e.buf[:]) + if _, e.err = e.w.Write(e.out[:4]); e.err != nil { return n, e.err } e.nbuf = 0 @@ -159,7 +184,7 @@ func (e *encoder) Write(p []byte) (n int, err error) { nn = len(p) nn -= nn % 3 } - e.enc.Encode(e.out[0:], p[0:nn]) + e.enc.Encode(e.out[:], p[:nn]) if _, e.err = e.w.Write(e.out[0 : nn/3*4]); e.err != nil { return n, e.err } @@ -181,9 +206,9 @@ func (e *encoder) Write(p []byte) (n int, err error) { func (e *encoder) Close() error { // If there's anything left in the buffer, flush it out if e.err == nil && e.nbuf > 0 { - e.enc.Encode(e.out[0:], e.buf[0:e.nbuf]) + e.enc.Encode(e.out[:], e.buf[:e.nbuf]) + _, e.err = e.w.Write(e.out[:e.enc.EncodedLen(e.nbuf)]) e.nbuf = 0 - _, e.err = e.w.Write(e.out[0:4]) } return e.err } @@ -199,7 +224,12 @@ func NewEncoder(enc *Encoding, w io.Writer) io.WriteCloser { // EncodedLen returns the length in bytes of the base64 encoding // of an input buffer of length n. -func (enc *Encoding) EncodedLen(n int) int { return (n + 2) / 3 * 4 } +func (enc *Encoding) EncodedLen(n int) int { + if enc.padChar == NoPadding { + return (n*8 + 5) / 6 // minimum # chars at 6 bits per char + } + return (n + 2) / 3 * 4 // minimum # 4-char quanta, 3 bytes each +} /* * Decoder @@ -212,66 +242,86 @@ func (e CorruptInputError) Error() string { } // decode is like Decode but returns an additional 'end' value, which -// indicates if end-of-message padding was encountered and thus any -// additional data is an error. This method assumes that src has been -// stripped of all supported whitespace ('\r' and '\n'). +// indicates if end-of-message padding or a partial quantum was encountered +// and thus any additional data is an error. func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) { - olen := len(src) - for len(src) > 0 && !end { + si := 0 + + // skip over newlines + for si < len(src) && (src[si] == '\n' || src[si] == '\r') { + si++ + } + + for si < len(src) && !end { // Decode quantum using the base64 alphabet var dbuf [4]byte - dlen := 4 + dinc, dlen := 3, 4 for j := range dbuf { - if len(src) == 0 { - return n, false, CorruptInputError(olen - len(src) - j) + if len(src) == si { + if enc.padChar != NoPadding || j < 2 { + return n, false, CorruptInputError(si - j) + } + dinc, dlen, end = j-1, j, true + break } - in := src[0] - src = src[1:] - if in == '=' { + in := src[si] + + si++ + // skip over newlines + for si < len(src) && (src[si] == '\n' || src[si] == '\r') { + si++ + } + + if rune(in) == enc.padChar { // We've reached the end and there's padding switch j { case 0, 1: // incorrect padding - return n, false, CorruptInputError(olen - len(src) - 1) + return n, false, CorruptInputError(si - 1) case 2: // "==" is expected, the first "=" is already consumed. - if len(src) == 0 { + if si == len(src) { // not enough padding - return n, false, CorruptInputError(olen) + return n, false, CorruptInputError(len(src)) } - if src[0] != '=' { + if rune(src[si]) != enc.padChar { // incorrect padding - return n, false, CorruptInputError(olen - len(src) - 1) + return n, false, CorruptInputError(si - 1) + } + + si++ + // skip over newlines + for si < len(src) && (src[si] == '\n' || src[si] == '\r') { + si++ } - src = src[1:] } - if len(src) > 0 { + if si < len(src) { // trailing garbage - err = CorruptInputError(olen - len(src)) + err = CorruptInputError(si) } - dlen, end = j, true + dinc, dlen, end = 3, j, true break } dbuf[j] = enc.decodeMap[in] if dbuf[j] == 0xFF { - return n, false, CorruptInputError(olen - len(src) - 1) + return n, false, CorruptInputError(si - 1) } } - // Pack 4x 6-bit source blocks into 3 byte destination - // quantum + // Convert 4x 6bit source bytes into 3 bytes + val := uint(dbuf[0])<<18 | uint(dbuf[1])<<12 | uint(dbuf[2])<<6 | uint(dbuf[3]) switch dlen { case 4: - dst[2] = dbuf[2]<<6 | dbuf[3] + dst[2] = byte(val >> 0) fallthrough case 3: - dst[1] = dbuf[1]<<4 | dbuf[2]>>2 + dst[1] = byte(val >> 8) fallthrough case 2: - dst[0] = dbuf[0]<<2 | dbuf[1]>>4 + dst[0] = byte(val >> 16) } - dst = dst[3:] + dst = dst[dinc:] n += dlen - 1 } @@ -284,14 +334,12 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) { // number of bytes successfully written and CorruptInputError. // New line characters (\r and \n) are ignored. func (enc *Encoding) Decode(dst, src []byte) (n int, err error) { - src = bytes.Map(removeNewlinesMapper, src) n, _, err = enc.decode(dst, src) return } // DecodeString returns the bytes represented by the base64 string s. func (enc *Encoding) DecodeString(s string) ([]byte, error) { - s = strings.Map(removeNewlinesMapper, s) dbuf := make([]byte, enc.DecodedLen(len(s))) n, _, err := enc.decode(dbuf, []byte(s)) return dbuf[:n], err @@ -320,6 +368,8 @@ func (d *decoder) Read(p []byte) (n int, err error) { return n, nil } + // This code assumes that d.r strips supported whitespace ('\r' and '\n'). + // Read a chunk. nn := len(p) / 3 * 4 if nn < 4 { @@ -338,12 +388,12 @@ func (d *decoder) Read(p []byte) (n int, err error) { nr := d.nbuf / 4 * 4 nw := d.nbuf / 4 * 3 if nw > len(p) { - nw, d.end, d.err = d.enc.decode(d.outbuf[0:], d.buf[0:nr]) - d.out = d.outbuf[0:nw] + nw, d.end, d.err = d.enc.decode(d.outbuf[:], d.buf[:nr]) + d.out = d.outbuf[:nw] n = copy(p, d.out) d.out = d.out[n:] } else { - n, d.end, d.err = d.enc.decode(p, d.buf[0:nr]) + n, d.end, d.err = d.enc.decode(p, d.buf[:nr]) } d.nbuf -= nr for i := 0; i < d.nbuf; i++ { @@ -364,7 +414,7 @@ func (r *newlineFilteringReader) Read(p []byte) (int, error) { n, err := r.wrapped.Read(p) for n > 0 { offset := 0 - for i, b := range p[0:n] { + for i, b := range p[:n] { if b != '\r' && b != '\n' { if i != offset { p[offset] = b @@ -388,4 +438,11 @@ func NewDecoder(enc *Encoding, r io.Reader) io.Reader { // DecodedLen returns the maximum length in bytes of the decoded data // corresponding to n bytes of base64-encoded data. -func (enc *Encoding) DecodedLen(n int) int { return n / 4 * 3 } +func (enc *Encoding) DecodedLen(n int) int { + if enc.padChar == NoPadding { + // Unpadded data may end with partial block of 2-3 characters. + return (n*6 + 7) / 8 + } + // Padded base64 should always be a multiple of 4 characters in length. + return n / 4 * 3 +} diff --git a/libgo/go/encoding/base64/base64_test.go b/libgo/go/encoding/base64/base64_test.go index 7d199bfa089..d144b96821f 100644 --- a/libgo/go/encoding/base64/base64_test.go +++ b/libgo/go/encoding/base64/base64_test.go @@ -45,6 +45,48 @@ var pairs = []testpair{ {"sure.", "c3VyZS4="}, } +// Do nothing to a reference base64 string (leave in standard format) +func stdRef(ref string) string { + return ref +} + +// Convert a reference string to URL-encoding +func urlRef(ref string) string { + ref = strings.Replace(ref, "+", "-", -1) + ref = strings.Replace(ref, "/", "_", -1) + return ref +} + +// Convert a reference string to raw, unpadded format +func rawRef(ref string) string { + return strings.TrimRight(ref, "=") +} + +// Both URL and unpadding conversions +func rawUrlRef(ref string) string { + return rawRef(urlRef(ref)) +} + +// A nonstandard encoding with a funny padding character, for testing +var funnyEncoding = NewEncoding(encodeStd).WithPadding(rune('@')) + +func funnyRef(ref string) string { + return strings.Replace(ref, "=", "@", -1) +} + +type encodingTest struct { + enc *Encoding // Encoding to test + conv func(string) string // Reference string converter +} + +var encodingTests = []encodingTest{ + encodingTest{StdEncoding, stdRef}, + encodingTest{URLEncoding, urlRef}, + encodingTest{RawStdEncoding, rawRef}, + encodingTest{RawURLEncoding, rawUrlRef}, + encodingTest{funnyEncoding, funnyRef}, +} + var bigtest = testpair{ "Twas brillig, and the slithy toves", "VHdhcyBicmlsbGlnLCBhbmQgdGhlIHNsaXRoeSB0b3Zlcw==", @@ -60,8 +102,11 @@ func testEqual(t *testing.T, msg string, args ...interface{}) bool { func TestEncode(t *testing.T) { for _, p := range pairs { - got := StdEncoding.EncodeToString([]byte(p.decoded)) - testEqual(t, "Encode(%q) = %q, want %q", p.decoded, got, p.encoded) + for _, tt := range encodingTests { + got := tt.enc.EncodeToString([]byte(p.decoded)) + testEqual(t, "Encode(%q) = %q, want %q", p.decoded, + got, tt.conv(p.encoded)) + } } } @@ -97,18 +142,21 @@ func TestEncoderBuffering(t *testing.T) { func TestDecode(t *testing.T) { for _, p := range pairs { - dbuf := make([]byte, StdEncoding.DecodedLen(len(p.encoded))) - count, end, err := StdEncoding.decode(dbuf, []byte(p.encoded)) - testEqual(t, "Decode(%q) = error %v, want %v", p.encoded, err, error(nil)) - testEqual(t, "Decode(%q) = length %v, want %v", p.encoded, count, len(p.decoded)) - if len(p.encoded) > 0 { - testEqual(t, "Decode(%q) = end %v, want %v", p.encoded, end, (p.encoded[len(p.encoded)-1] == '=')) - } - testEqual(t, "Decode(%q) = %q, want %q", p.encoded, string(dbuf[0:count]), p.decoded) + for _, tt := range encodingTests { + encoded := tt.conv(p.encoded) + dbuf := make([]byte, tt.enc.DecodedLen(len(encoded))) + count, end, err := tt.enc.decode(dbuf, []byte(encoded)) + testEqual(t, "Decode(%q) = error %v, want %v", encoded, err, error(nil)) + testEqual(t, "Decode(%q) = length %v, want %v", encoded, count, len(p.decoded)) + if len(encoded) > 0 { + testEqual(t, "Decode(%q) = end %v, want %v", encoded, end, len(p.decoded)%3 != 0) + } + testEqual(t, "Decode(%q) = %q, want %q", encoded, string(dbuf[0:count]), p.decoded) - dbuf, err = StdEncoding.DecodeString(p.encoded) - testEqual(t, "DecodeString(%q) = error %v, want %v", p.encoded, err, error(nil)) - testEqual(t, "DecodeString(%q) = %q, want %q", string(dbuf), p.decoded) + dbuf, err = tt.enc.DecodeString(encoded) + testEqual(t, "DecodeString(%q) = error %v, want %v", encoded, err, error(nil)) + testEqual(t, "DecodeString(%q) = %q, want %q", string(dbuf), p.decoded) + } } } diff --git a/libgo/go/encoding/binary/binary.go b/libgo/go/encoding/binary/binary.go index 466bf97c973..2bbe07c02ff 100644 --- a/libgo/go/encoding/binary/binary.go +++ b/libgo/go/encoding/binary/binary.go @@ -13,7 +13,7 @@ // The varint functions encode and decode single integer values using // a variable-length encoding; smaller values require fewer bytes. // For a specification, see -// http://code.google.com/apis/protocolbuffers/docs/encoding.html. +// https://developers.google.com/protocol-buffers/docs/encoding. // // This package favors simplicity over efficiency. Clients that require // high-performance serialization, especially for large data structures, @@ -239,78 +239,62 @@ func Write(w io.Writer, order ByteOrder, data interface{}) error { } switch v := data.(type) { case *int8: - bs = b[:1] b[0] = byte(*v) case int8: - bs = b[:1] b[0] = byte(v) case []int8: for i, x := range v { bs[i] = byte(x) } case *uint8: - bs = b[:1] b[0] = *v case uint8: - bs = b[:1] b[0] = byte(v) case []uint8: bs = v case *int16: - bs = b[:2] order.PutUint16(bs, uint16(*v)) case int16: - bs = b[:2] order.PutUint16(bs, uint16(v)) case []int16: for i, x := range v { order.PutUint16(bs[2*i:], uint16(x)) } case *uint16: - bs = b[:2] order.PutUint16(bs, *v) case uint16: - bs = b[:2] order.PutUint16(bs, v) case []uint16: for i, x := range v { order.PutUint16(bs[2*i:], x) } case *int32: - bs = b[:4] order.PutUint32(bs, uint32(*v)) case int32: - bs = b[:4] order.PutUint32(bs, uint32(v)) case []int32: for i, x := range v { order.PutUint32(bs[4*i:], uint32(x)) } case *uint32: - bs = b[:4] order.PutUint32(bs, *v) case uint32: - bs = b[:4] order.PutUint32(bs, v) case []uint32: for i, x := range v { order.PutUint32(bs[4*i:], x) } case *int64: - bs = b[:8] order.PutUint64(bs, uint64(*v)) case int64: - bs = b[:8] order.PutUint64(bs, uint64(v)) case []int64: for i, x := range v { order.PutUint64(bs[8*i:], uint64(x)) } case *uint64: - bs = b[:8] order.PutUint64(bs, *v) case uint64: - bs = b[:8] order.PutUint64(bs, v) case []uint64: for i, x := range v { @@ -605,25 +589,25 @@ func (e *encoder) skip(v reflect.Value) { // It returns zero if the type cannot be implemented by the fast path in Read or Write. func intDataSize(data interface{}) int { switch data := data.(type) { - case int8, *int8, *uint8: + case int8, uint8, *int8, *uint8: return 1 case []int8: return len(data) case []uint8: return len(data) - case int16, *int16, *uint16: + case int16, uint16, *int16, *uint16: return 2 case []int16: return 2 * len(data) case []uint16: return 2 * len(data) - case int32, *int32, *uint32: + case int32, uint32, *int32, *uint32: return 4 case []int32: return 4 * len(data) case []uint32: return 4 * len(data) - case int64, *int64, *uint64: + case int64, uint64, *int64, *uint64: return 8 case []int64: return 8 * len(data) diff --git a/libgo/go/encoding/csv/example_test.go b/libgo/go/encoding/csv/example_test.go new file mode 100644 index 00000000000..e3c3bd51228 --- /dev/null +++ b/libgo/go/encoding/csv/example_test.go @@ -0,0 +1,133 @@ +// Copyright 2015 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 + +package csv_test + +import ( + "encoding/csv" + "fmt" + "io" + "log" + "os" + "strings" +) + +func ExampleReader() { + in := `first_name,last_name,username +"Rob","Pike",rob +Ken,Thompson,ken +"Robert","Griesemer","gri" +` + r := csv.NewReader(strings.NewReader(in)) + + for { + record, err := r.Read() + if err == io.EOF { + break + } + if err != nil { + log.Fatal(err) + } + + fmt.Println(record) + } + // Output: + // [first_name last_name username] + // [Rob Pike rob] + // [Ken Thompson ken] + // [Robert Griesemer gri] +} + +// This example shows how csv.Reader can be configured to handle other +// types of CSV files. +func ExampleReader_options() { + in := `first_name;last_name;username +"Rob";"Pike";rob +# lines beginning with a # character are ignored +Ken;Thompson;ken +"Robert";"Griesemer";"gri" +` + r := csv.NewReader(strings.NewReader(in)) + r.Comma = ';' + r.Comment = '#' + + records, err := r.ReadAll() + if err != nil { + log.Fatal(err) + } + + fmt.Print(records) + // Output: + // [[first_name last_name username] [Rob Pike rob] [Ken Thompson ken] [Robert Griesemer gri]] +} + +func ExampleReader_ReadAll() { + in := `first_name,last_name,username +"Rob","Pike",rob +Ken,Thompson,ken +"Robert","Griesemer","gri" +` + r := csv.NewReader(strings.NewReader(in)) + + records, err := r.ReadAll() + if err != nil { + log.Fatal(err) + } + + fmt.Print(records) + // Output: + // [[first_name last_name username] [Rob Pike rob] [Ken Thompson ken] [Robert Griesemer gri]] +} + +func ExampleWriter() { + records := [][]string{ + {"first_name", "last_name", "username"}, + {"Rob", "Pike", "rob"}, + {"Ken", "Thompson", "ken"}, + {"Robert", "Griesemer", "gri"}, + } + + w := csv.NewWriter(os.Stdout) + + for _, record := range records { + if err := w.Write(record); err != nil { + log.Fatalln("error writing record to csv:", err) + } + } + + // Write any buffered data to the underlying writer (standard output). + w.Flush() + + if err := w.Error(); err != nil { + log.Fatal(err) + } + // Output: + // first_name,last_name,username + // Rob,Pike,rob + // Ken,Thompson,ken + // Robert,Griesemer,gri +} + +func ExampleWriter_WriteAll() { + records := [][]string{ + {"first_name", "last_name", "username"}, + {"Rob", "Pike", "rob"}, + {"Ken", "Thompson", "ken"}, + {"Robert", "Griesemer", "gri"}, + } + + w := csv.NewWriter(os.Stdout) + w.WriteAll(records) // calls Flush internally + + if err := w.Error(); err != nil { + log.Fatalln("error writing csv:", err) + } + // Output: + // first_name,last_name,username + // Rob,Pike,rob + // Ken,Thompson,ken + // Robert,Griesemer,gri +} diff --git a/libgo/go/encoding/csv/reader.go b/libgo/go/encoding/csv/reader.go index d9432954ac9..37bf80ceaed 100644 --- a/libgo/go/encoding/csv/reader.go +++ b/libgo/go/encoding/csv/reader.go @@ -215,7 +215,7 @@ func (r *Reader) parseRecord() (fields []string, err error) { r.column = -1 // Peek at the first rune. If it is an error we are done. - // If we are support comments and it is the comment character + // If we support comments and it is the comment character // then skip to the end of line. r1, _, err := r.r.ReadRune() @@ -232,6 +232,11 @@ func (r *Reader) parseRecord() (fields []string, err error) { for { haveField, delim, err := r.parseField() if haveField { + // If FieldsPerRecord is greater then 0 we can assume the final + // length of fields to be equal to FieldsPerRecord. + if r.FieldsPerRecord > 0 && fields == nil { + fields = make([]string, 0, r.FieldsPerRecord) + } fields = append(fields, r.field.String()) } if delim == '\n' || err == io.EOF { diff --git a/libgo/go/encoding/csv/reader_test.go b/libgo/go/encoding/csv/reader_test.go index 123df06bc85..be1002d034a 100644 --- a/libgo/go/encoding/csv/reader_test.go +++ b/libgo/go/encoding/csv/reader_test.go @@ -86,6 +86,15 @@ field"`, {"d", "e", "f"}, }, }, + { + Name: "BlankLineFieldCount", + Input: "a,b,c\n\nd,e,f\n\n", + UseFieldsPerRecord: true, + Output: [][]string{ + {"a", "b", "c"}, + {"d", "e", "f"}, + }, + }, { Name: "TrimSpace", Input: " a, b, c\n", @@ -282,3 +291,25 @@ func TestRead(t *testing.T) { } } } + +func BenchmarkRead(b *testing.B) { + data := `x,y,z,w +x,y,z, +x,y,, +x,,, +,,, +"x","y","z","w" +"x","y","z","" +"x","y","","" +"x","","","" +"","","","" +` + + for i := 0; i < b.N; i++ { + _, err := NewReader(strings.NewReader(data)).ReadAll() + + if err != nil { + b.Fatalf("could not read data: %s", err) + } + } +} diff --git a/libgo/go/encoding/csv/writer.go b/libgo/go/encoding/csv/writer.go index 17e7bb7f5c7..353d91f238f 100644 --- a/libgo/go/encoding/csv/writer.go +++ b/libgo/go/encoding/csv/writer.go @@ -114,7 +114,7 @@ func (w *Writer) WriteAll(records [][]string) (err error) { return w.w.Flush() } -// fieldNeedsQuotes returns true if our field must be enclosed in quotes. +// fieldNeedsQuotes reports whether our field must be enclosed in quotes. // Fields with a Comma, fields with a quote or newline, and // fields which start with a space must be enclosed in quotes. // We used to quote empty strings, but we do not anymore (as of Go 1.4). @@ -125,7 +125,7 @@ func (w *Writer) WriteAll(records [][]string) (err error) { // CSV with quoted empty strings strictly less useful. // Not quoting the empty string also makes this package match the behavior // of Microsoft Excel and Google Drive. -// For Postgres, quote the data termating string `\.`. +// For Postgres, quote the data terminating string `\.`. func (w *Writer) fieldNeedsQuotes(field string) bool { if field == "" { return false diff --git a/libgo/go/encoding/gob/codec_test.go b/libgo/go/encoding/gob/codec_test.go index 56a7298fa55..c2583bfee33 100644 --- a/libgo/go/encoding/gob/codec_test.go +++ b/libgo/go/encoding/gob/codec_test.go @@ -1473,3 +1473,22 @@ func TestFuzzOneByte(t *testing.T) { } } } + +// Don't crash, just give error with invalid type id. +// Issue 9649. +func TestErrorInvalidTypeId(t *testing.T) { + data := []byte{0x01, 0x00, 0x01, 0x00} + d := NewDecoder(bytes.NewReader(data)) + // When running d.Decode(&foo) the first time the decoder stops + // after []byte{0x01, 0x00} and reports an errBadType. Running + // d.Decode(&foo) again on exactly the same input sequence should + // give another errBadType, but instead caused a panic because + // decoderMap wasn't cleaned up properly after the first error. + for i := 0; i < 2; i++ { + var foo struct{} + err := d.Decode(&foo) + if err != errBadType { + t.Fatal("decode: expected %s, got %s", errBadType, err) + } + } +} diff --git a/libgo/go/encoding/gob/decode.go b/libgo/go/encoding/gob/decode.go index a5bef93141b..e913f15c545 100644 --- a/libgo/go/encoding/gob/decode.go +++ b/libgo/go/encoding/gob/decode.go @@ -182,6 +182,17 @@ func (state *decoderState) decodeInt() int64 { return int64(x >> 1) } +// getLength decodes the next uint and makes sure it is a possible +// size for a data item that follows, which means it must fit in a +// non-negative int and fit in the buffer. +func (state *decoderState) getLength() (int, bool) { + n := int(state.decodeUint()) + if n < 0 || state.b.Len() < n || tooBig <= n { + return 0, false + } + return n, true +} + // decOp is the signature of a decoding operator for a given type. type decOp func(i *decInstr, state *decoderState, v reflect.Value) @@ -363,16 +374,9 @@ func decComplex128(i *decInstr, state *decoderState, value reflect.Value) { // describing the data. // uint8 slices are encoded as an unsigned count followed by the raw bytes. func decUint8Slice(i *decInstr, state *decoderState, value reflect.Value) { - u := state.decodeUint() - n := int(u) - if n < 0 || uint64(n) != u { - errorf("length of %s exceeds input size (%d bytes)", value.Type(), u) - } - if n > state.b.Len() { - errorf("%s data too long for buffer: %d", value.Type(), n) - } - if n > tooBig { - errorf("byte slice too big: %d", n) + n, ok := state.getLength() + if !ok { + errorf("bad %s slice length: %d", value.Type(), n) } if value.Cap() < n { value.Set(reflect.MakeSlice(value.Type(), n, n)) @@ -388,13 +392,9 @@ func decUint8Slice(i *decInstr, state *decoderState, value reflect.Value) { // describing the data. // Strings are encoded as an unsigned count followed by the raw bytes. func decString(i *decInstr, state *decoderState, value reflect.Value) { - u := state.decodeUint() - n := int(u) - if n < 0 || uint64(n) != u || n > state.b.Len() { - errorf("length of %s exceeds input size (%d bytes)", value.Type(), u) - } - if n > state.b.Len() { - errorf("%s data too long for buffer: %d", value.Type(), n) + n, ok := state.getLength() + if !ok { + errorf("bad %s slice length: %d", value.Type(), n) } // Read the data. data := make([]byte, n) @@ -406,7 +406,11 @@ func decString(i *decInstr, state *decoderState, value reflect.Value) { // ignoreUint8Array skips over the data for a byte slice value with no destination. func ignoreUint8Array(i *decInstr, state *decoderState, value reflect.Value) { - b := make([]byte, state.decodeUint()) + n, ok := state.getLength() + if !ok { + errorf("slice length too large") + } + b := make([]byte, n) state.b.Read(b) } @@ -571,6 +575,9 @@ func (dec *Decoder) decodeMap(mtyp reflect.Type, state *decoderState, value refl func (dec *Decoder) ignoreArrayHelper(state *decoderState, elemOp decOp, length int) { instr := &decInstr{elemOp, 0, nil, errors.New("no error")} for i := 0; i < length; i++ { + if state.b.Len() == 0 { + errorf("decoding array or slice: length exceeds input size (%d elements)", length) + } elemOp(instr, state, noValue) } } @@ -678,7 +685,11 @@ func (dec *Decoder) decodeInterface(ityp reflect.Type, state *decoderState, valu // ignoreInterface discards the data for an interface value with no destination. func (dec *Decoder) ignoreInterface(state *decoderState) { // Read the name of the concrete type. - b := make([]byte, state.decodeUint()) + n, ok := state.getLength() + if !ok { + errorf("bad interface encoding: name too large for buffer") + } + b := make([]byte, n) _, err := state.b.Read(b) if err != nil { error_(err) @@ -688,14 +699,22 @@ func (dec *Decoder) ignoreInterface(state *decoderState) { error_(dec.err) } // At this point, the decoder buffer contains a delimited value. Just toss it. - state.b.Drop(int(state.decodeUint())) + n, ok = state.getLength() + if !ok { + errorf("bad interface encoding: data length too large for buffer") + } + state.b.Drop(n) } // decodeGobDecoder decodes something implementing the GobDecoder interface. // The data is encoded as a byte slice. func (dec *Decoder) decodeGobDecoder(ut *userTypeInfo, state *decoderState, value reflect.Value) { // Read the bytes for the value. - b := make([]byte, state.decodeUint()) + n, ok := state.getLength() + if !ok { + errorf("GobDecoder: length too large for buffer") + } + b := make([]byte, n) _, err := state.b.Read(b) if err != nil { error_(err) @@ -717,7 +736,11 @@ func (dec *Decoder) decodeGobDecoder(ut *userTypeInfo, state *decoderState, valu // ignoreGobDecoder discards the data for a GobDecoder value with no destination. func (dec *Decoder) ignoreGobDecoder(state *decoderState) { // Read the bytes for the value. - b := make([]byte, state.decodeUint()) + n, ok := state.getLength() + if !ok { + errorf("GobDecoder: length too large for buffer") + } + b := make([]byte, n) _, err := state.b.Read(b) if err != nil { error_(err) @@ -840,16 +863,22 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string, inProg } // decIgnoreOpFor returns the decoding op for a field that has no destination. -func (dec *Decoder) decIgnoreOpFor(wireId typeId) decOp { +func (dec *Decoder) decIgnoreOpFor(wireId typeId, inProgress map[typeId]*decOp) *decOp { + // If this type is already in progress, it's a recursive type (e.g. map[string]*T). + // Return the pointer to the op we're already building. + if opPtr := inProgress[wireId]; opPtr != nil { + return opPtr + } op, ok := decIgnoreOpMap[wireId] if !ok { + inProgress[wireId] = &op if wireId == tInterface { // Special case because it's a method: the ignored item might // define types and we need to record their state in the decoder. op = func(i *decInstr, state *decoderState, value reflect.Value) { state.dec.ignoreInterface(state) } - return op + return &op } // Special cases wire := dec.wireType[wireId] @@ -858,25 +887,25 @@ func (dec *Decoder) decIgnoreOpFor(wireId typeId) decOp { errorf("bad data: undefined type %s", wireId.string()) case wire.ArrayT != nil: elemId := wire.ArrayT.Elem - elemOp := dec.decIgnoreOpFor(elemId) + elemOp := dec.decIgnoreOpFor(elemId, inProgress) op = func(i *decInstr, state *decoderState, value reflect.Value) { - state.dec.ignoreArray(state, elemOp, wire.ArrayT.Len) + state.dec.ignoreArray(state, *elemOp, wire.ArrayT.Len) } case wire.MapT != nil: keyId := dec.wireType[wireId].MapT.Key elemId := dec.wireType[wireId].MapT.Elem - keyOp := dec.decIgnoreOpFor(keyId) - elemOp := dec.decIgnoreOpFor(elemId) + keyOp := dec.decIgnoreOpFor(keyId, inProgress) + elemOp := dec.decIgnoreOpFor(elemId, inProgress) op = func(i *decInstr, state *decoderState, value reflect.Value) { - state.dec.ignoreMap(state, keyOp, elemOp) + state.dec.ignoreMap(state, *keyOp, *elemOp) } case wire.SliceT != nil: elemId := wire.SliceT.Elem - elemOp := dec.decIgnoreOpFor(elemId) + elemOp := dec.decIgnoreOpFor(elemId, inProgress) op = func(i *decInstr, state *decoderState, value reflect.Value) { - state.dec.ignoreSlice(state, elemOp) + state.dec.ignoreSlice(state, *elemOp) } case wire.StructT != nil: @@ -899,7 +928,7 @@ func (dec *Decoder) decIgnoreOpFor(wireId typeId) decOp { if op == nil { errorf("bad data: ignore can't handle type %s", wireId.string()) } - return op + return &op } // gobDecodeOpFor returns the op for a type that is known to implement @@ -1033,9 +1062,9 @@ func (dec *Decoder) compileSingle(remoteId typeId, ut *userTypeInfo) (engine *de func (dec *Decoder) compileIgnoreSingle(remoteId typeId) (engine *decEngine, err error) { engine = new(decEngine) engine.instr = make([]decInstr, 1) // one item - op := dec.decIgnoreOpFor(remoteId) + op := dec.decIgnoreOpFor(remoteId, make(map[typeId]*decOp)) ovfl := overflow(dec.typeString(remoteId)) - engine.instr[0] = decInstr{op, 0, nil, ovfl} + engine.instr[0] = decInstr{*op, 0, nil, ovfl} engine.numInstr = 1 return } @@ -1043,6 +1072,7 @@ func (dec *Decoder) compileIgnoreSingle(remoteId typeId) (engine *decEngine, err // compileDec compiles the decoder engine for a value. If the value is not a struct, // it calls out to compileSingle. func (dec *Decoder) compileDec(remoteId typeId, ut *userTypeInfo) (engine *decEngine, err error) { + defer catchError(&err) rt := ut.base srt := rt if srt.Kind() != reflect.Struct || ut.externalDec != 0 { @@ -1077,8 +1107,8 @@ func (dec *Decoder) compileDec(remoteId typeId, ut *userTypeInfo) (engine *decEn localField, present := srt.FieldByName(wireField.Name) // TODO(r): anonymous names if !present || !isExported(wireField.Name) { - op := dec.decIgnoreOpFor(wireField.Id) - engine.instr[fieldnum] = decInstr{op, fieldnum, nil, ovfl} + op := dec.decIgnoreOpFor(wireField.Id, make(map[typeId]*decOp)) + engine.instr[fieldnum] = decInstr{*op, fieldnum, nil, ovfl} continue } if !dec.compatibleType(localField.Type, wireField.Id, make(map[reflect.Type]typeId)) { @@ -1116,7 +1146,7 @@ type emptyStruct struct{} var emptyStructType = reflect.TypeOf(emptyStruct{}) -// getDecEnginePtr returns the engine for the specified type when the value is to be discarded. +// getIgnoreEnginePtr returns the engine for the specified type when the value is to be discarded. func (dec *Decoder) getIgnoreEnginePtr(wireId typeId) (enginePtr **decEngine, err error) { var ok bool if enginePtr, ok = dec.ignorerCache[wireId]; !ok { @@ -1155,8 +1185,9 @@ func (dec *Decoder) decodeValue(wireId typeId, value reflect.Value) { value = decAlloc(value) engine := *enginePtr if st := base; st.Kind() == reflect.Struct && ut.externalDec == 0 { + wt := dec.wireType[wireId] if engine.numInstr == 0 && st.NumField() > 0 && - dec.wireType[wireId] != nil && len(dec.wireType[wireId].StructT.Field) > 0 { + wt != nil && len(wt.StructT.Field) > 0 { name := base.Name() errorf("type mismatch: no fields matched compiling decoder for %s", name) } diff --git a/libgo/go/encoding/gob/doc.go b/libgo/go/encoding/gob/doc.go index d0acaba1adc..4d3d0076fbc 100644 --- a/libgo/go/encoding/gob/doc.go +++ b/libgo/go/encoding/gob/doc.go @@ -6,7 +6,7 @@ Package gob manages streams of gobs - binary values exchanged between an Encoder (transmitter) and a Decoder (receiver). A typical use is transporting arguments and results of remote procedure calls (RPCs) such as those provided by -package "rpc". +package "net/rpc". The implementation compiles a custom codec for each data type in the stream and is most efficient when a single Encoder is used to transmit a stream of values, @@ -83,7 +83,7 @@ allocated. Regardless, the length of the resulting slice reports the number of elements decoded. Functions and channels will not be sent in a gob. Attempting to encode such a value -at top the level will fail. A struct field of chan or func type is treated exactly +at the top level will fail. A struct field of chan or func type is treated exactly like an unexported field and is ignored. Gob can encode a value of any type implementing the GobEncoder or @@ -111,11 +111,11 @@ A signed integer, i, is encoded within an unsigned integer, u. Within u, bits 1 upward contain the value; bit 0 says whether they should be complemented upon receipt. The encode algorithm looks like this: - uint u; + var u uint if i < 0 { - u = (^i << 1) | 1 // complement i, bit 0 is 1 + u = (^uint(i) << 1) | 1 // complement i, bit 0 is 1 } else { - u = (i << 1) // do not complement i, bit 0 is 0 + u = (uint(i) << 1) // do not complement i, bit 0 is 0 } encodeUnsigned(u) @@ -137,9 +137,9 @@ All other slices and arrays are sent as an unsigned count followed by that many elements using the standard gob encoding for their type, recursively. Maps are sent as an unsigned count followed by that many key, element -pairs. Empty but non-nil maps are sent, so if the sender has allocated -a map, the receiver will allocate a map even if no elements are -transmitted. +pairs. Empty but non-nil maps are sent, so if the receiver has not allocated +one already, one will always be allocated on receipt unless the transmitted map +is nil and not at the top level. Structs are sent as a sequence of (field number, field value) pairs. The field value is sent using the standard gob encoding for its type, recursively. If a @@ -246,7 +246,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://golang.org/doc/articles/gobs_of_data.html +https://blog.golang.org/gobs-of-data */ package gob diff --git a/libgo/go/encoding/gob/encoder.go b/libgo/go/encoding/gob/encoder.go index a340e47b5ed..62d0f42e81a 100644 --- a/libgo/go/encoding/gob/encoder.go +++ b/libgo/go/encoding/gob/encoder.go @@ -5,6 +5,7 @@ package gob import ( + "errors" "io" "reflect" "sync" @@ -65,6 +66,11 @@ func (enc *Encoder) writeMessage(w io.Writer, b *encBuffer) { // it by hand. message := b.Bytes() messageLen := len(message) - maxLength + // Length cannot be bigger than the decoder can handle. + if messageLen >= tooBig { + enc.setError(errors.New("gob: encoder: message too big")) + return + } // Encode the length. enc.countState.b.Reset() enc.countState.encodeUint(uint64(messageLen)) diff --git a/libgo/go/encoding/gob/encoder_test.go b/libgo/go/encoding/gob/encoder_test.go index 0ea4c0ec8e5..dc657348223 100644 --- a/libgo/go/encoding/gob/encoder_test.go +++ b/libgo/go/encoding/gob/encoder_test.go @@ -6,8 +6,8 @@ package gob import ( "bytes" + "encoding/hex" "fmt" - "io" "reflect" "strings" "testing" @@ -187,24 +187,6 @@ func TestWrongTypeDecoder(t *testing.T) { badTypeCheck(new(ET4), true, "different type of field", t) } -func corruptDataCheck(s string, err error, t *testing.T) { - b := bytes.NewBufferString(s) - dec := NewDecoder(b) - err1 := dec.Decode(new(ET2)) - if err1 != err { - t.Errorf("from %q expected error %s; got %s", s, err, err1) - } -} - -// Check that we survive bad data. -func TestBadData(t *testing.T) { - corruptDataCheck("", io.EOF, t) - corruptDataCheck("\x7Fhi", io.ErrUnexpectedEOF, t) - corruptDataCheck("\x03now is the time for all good men", errBadType, t) - // issue 6323. - corruptDataCheck("\x04\x24foo", errRange, t) -} - // Types not supported at top level by the Encoder. var unsupportedValues = []interface{}{ make(chan int), @@ -545,6 +527,30 @@ func TestDecodeIntoNothing(t *testing.T) { } } +func TestIgnoreRecursiveType(t *testing.T) { + // It's hard to build a self-contained test for this because + // we can't build compatible types in one package with + // different items so something is ignored. Here is + // some data that represents, according to debug.go: + // type definition { + // slice "recursiveSlice" id=106 + // elem id=106 + // } + data := []byte{ + 0x1d, 0xff, 0xd3, 0x02, 0x01, 0x01, 0x0e, 0x72, + 0x65, 0x63, 0x75, 0x72, 0x73, 0x69, 0x76, 0x65, + 0x53, 0x6c, 0x69, 0x63, 0x65, 0x01, 0xff, 0xd4, + 0x00, 0x01, 0xff, 0xd4, 0x00, 0x00, 0x07, 0xff, + 0xd4, 0x00, 0x02, 0x01, 0x00, 0x00, + } + dec := NewDecoder(bytes.NewReader(data)) + // Issue 10415: This caused infinite recursion. + err := dec.Decode(nil) + if err != nil { + t.Fatal(err) + } +} + // Another bug from golang-nuts, involving nested interfaces. type Bug0Outer struct { Bug0Field interface{} @@ -951,6 +957,64 @@ func TestErrorForHugeSlice(t *testing.T) { t.Fatal("decode: no error") } if !strings.Contains(err.Error(), "slice too big") { - t.Fatal("decode: expected slice too big error, got %s", err.Error()) + t.Fatalf("decode: expected slice too big error, got %s", err.Error()) + } +} + +type badDataTest struct { + input string // The input encoded as a hex string. + error string // A substring of the error that should result. + data interface{} // What to decode into. +} + +var badDataTests = []badDataTest{ + {"", "EOF", nil}, + {"7F6869", "unexpected EOF", nil}, + {"036e6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e", "unknown type id", new(ET2)}, + {"0424666f6f", "field numbers out of bounds", new(ET2)}, // Issue 6323. + {"05100028557b02027f8302", "interface encoding", nil}, // Issue 10270. + // Issue 10273. + {"130a00fb5dad0bf8ff020263e70002fa28020202a89859", "slice length too large", nil}, + {"0f1000fb285d003316020735ff023a65c5", "interface encoding", nil}, + {"03fffb0616fffc00f902ff02ff03bf005d02885802a311a8120228022c028ee7", "GobDecoder", nil}, + // Issue 10491. + {"10fe010f020102fe01100001fe010e000016fe010d030102fe010e00010101015801fe01100000000bfe011000f85555555555555555", "length exceeds input size", nil}, +} + +// TestBadData tests that various problems caused by malformed input +// are caught as errors and do not cause panics. +func TestBadData(t *testing.T) { + for i, test := range badDataTests { + data, err := hex.DecodeString(test.input) + if err != nil { + t.Fatalf("#%d: hex error: %s", i, err) + } + d := NewDecoder(bytes.NewReader(data)) + err = d.Decode(test.data) + if err == nil { + t.Errorf("decode: no error") + continue + } + if !strings.Contains(err.Error(), test.error) { + t.Errorf("#%d: decode: expected %q error, got %s", i, test.error, err.Error()) + } + } +} + +// TestHugeWriteFails tests that enormous messages trigger an error. +func TestHugeWriteFails(t *testing.T) { + if testing.Short() { + // Requires allocating a monster, so don't do this from all.bash. + t.Skip("skipping huge allocation in short mode") + } + huge := make([]byte, tooBig) + huge[0] = 7 // Make sure it's not all zeros. + buf := new(bytes.Buffer) + err := NewEncoder(buf).Encode(huge) + if err == nil { + t.Fatalf("expected error for huge slice") + } + if !strings.Contains(err.Error(), "message too big") { + t.Fatalf("expected 'too big' error; got %s\n", err.Error()) } } diff --git a/libgo/go/encoding/json/bench_test.go b/libgo/go/encoding/json/bench_test.go index 29dbc26d417..ed89d1156ed 100644 --- a/libgo/go/encoding/json/bench_test.go +++ b/libgo/go/encoding/json/bench_test.go @@ -15,6 +15,7 @@ import ( "compress/gzip" "io/ioutil" "os" + "strings" "testing" ) @@ -126,6 +127,28 @@ func BenchmarkCodeDecoder(b *testing.B) { b.SetBytes(int64(len(codeJSON))) } +func BenchmarkDecoderStream(b *testing.B) { + b.StopTimer() + var buf bytes.Buffer + dec := NewDecoder(&buf) + buf.WriteString(`"` + strings.Repeat("x", 1000000) + `"` + "\n\n\n") + var x interface{} + if err := dec.Decode(&x); err != nil { + b.Fatal("Decode:", err) + } + ones := strings.Repeat(" 1\n", 300000) + "\n\n\n" + b.StartTimer() + for i := 0; i < b.N; i++ { + if i%300000 == 0 { + buf.WriteString(ones) + } + x = nil + if err := dec.Decode(&x); err != nil || x != 1.0 { + b.Fatalf("Decode: %v after %d", err, i) + } + } +} + func BenchmarkCodeUnmarshal(b *testing.B) { if codeJSON == nil { b.StopTimer() @@ -187,3 +210,14 @@ func BenchmarkUnmarshalInt64(b *testing.B) { } } } + +func BenchmarkIssue10335(b *testing.B) { + b.ReportAllocs() + var s struct{} + j := []byte(`{"a":{ }}`) + for n := 0; n < b.N; n++ { + if err := Unmarshal(j, &s); err != nil { + b.Fatal(err) + } + } +} diff --git a/libgo/go/encoding/json/decode.go b/libgo/go/encoding/json/decode.go index 705bc2e17a7..530e8521dc5 100644 --- a/libgo/go/encoding/json/decode.go +++ b/libgo/go/encoding/json/decode.go @@ -48,6 +48,13 @@ import ( // map[string]interface{}, for JSON objects // nil for JSON null // +// To unmarshal a JSON array into a slice, Unmarshal resets the slice to nil +// and then appends each element to the slice. +// +// To unmarshal a JSON object into a map, Unmarshal replaces the map +// with an empty map and then adds key-value pairs from the object to +// the map. +// // If a JSON value is not appropriate for a given target type, // or if a JSON number overflows the target type, Unmarshal // skips that field and completes the unmarshalling as best it can. @@ -90,8 +97,9 @@ type Unmarshaler interface { // An UnmarshalTypeError describes a JSON value that was // not appropriate for a value of a specific Go type. type UnmarshalTypeError struct { - Value string // description of JSON value - "bool", "array", "number -5" - Type reflect.Type // type of Go value it could not be assigned to + Value string // description of JSON value - "bool", "array", "number -5" + Type reflect.Type // type of Go value it could not be assigned to + Offset int64 // error occurred after reading Offset bytes } func (e *UnmarshalTypeError) Error() string { @@ -377,7 +385,7 @@ func (d *decodeState) array(v reflect.Value) { return } if ut != nil { - d.saveError(&UnmarshalTypeError{"array", v.Type()}) + d.saveError(&UnmarshalTypeError{"array", v.Type(), int64(d.off)}) d.off-- d.next() return @@ -396,7 +404,7 @@ func (d *decodeState) array(v reflect.Value) { // Otherwise it's invalid. fallthrough default: - d.saveError(&UnmarshalTypeError{"array", v.Type()}) + d.saveError(&UnmarshalTypeError{"array", v.Type(), int64(d.off)}) d.off-- d.next() return @@ -485,7 +493,7 @@ func (d *decodeState) object(v reflect.Value) { return } if ut != nil { - d.saveError(&UnmarshalTypeError{"object", v.Type()}) + d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)}) d.off-- d.next() // skip over { } in input return @@ -504,7 +512,7 @@ func (d *decodeState) object(v reflect.Value) { // map must have string kind t := v.Type() if t.Key().Kind() != reflect.String { - d.saveError(&UnmarshalTypeError{"object", v.Type()}) + d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)}) d.off-- d.next() // skip over { } in input return @@ -515,7 +523,7 @@ func (d *decodeState) object(v reflect.Value) { case reflect.Struct: default: - d.saveError(&UnmarshalTypeError{"object", v.Type()}) + d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)}) d.off-- d.next() // skip over { } in input return @@ -599,7 +607,7 @@ func (d *decodeState) object(v reflect.Value) { case string: d.literalStore([]byte(qv), subv, true) default: - d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal unquoted value into %v", item, v.Type())) + d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal unquoted value into %v", subv.Type())) } } else { d.value(subv) @@ -646,7 +654,7 @@ func (d *decodeState) convertNumber(s string) (interface{}, error) { } f, err := strconv.ParseFloat(s, 64) if err != nil { - return nil, &UnmarshalTypeError{"number " + s, reflect.TypeOf(0.0)} + return nil, &UnmarshalTypeError{"number " + s, reflect.TypeOf(0.0), int64(d.off)} } return f, nil } @@ -679,8 +687,9 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool if fromQuoted { d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) } else { - d.saveError(&UnmarshalTypeError{"string", v.Type()}) + d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)}) } + return } s, ok := unquoteBytes(item) if !ok { @@ -713,7 +722,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool if fromQuoted { d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) } else { - d.saveError(&UnmarshalTypeError{"bool", v.Type()}) + d.saveError(&UnmarshalTypeError{"bool", v.Type(), int64(d.off)}) } case reflect.Bool: v.SetBool(value) @@ -721,7 +730,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool if v.NumMethod() == 0 { v.Set(reflect.ValueOf(value)) } else { - d.saveError(&UnmarshalTypeError{"bool", v.Type()}) + d.saveError(&UnmarshalTypeError{"bool", v.Type(), int64(d.off)}) } } @@ -736,10 +745,10 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool } switch v.Kind() { default: - d.saveError(&UnmarshalTypeError{"string", v.Type()}) + d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)}) case reflect.Slice: - if v.Type() != byteSliceType { - d.saveError(&UnmarshalTypeError{"string", v.Type()}) + if v.Type().Elem().Kind() != reflect.Uint8 { + d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)}) break } b := make([]byte, base64.StdEncoding.DecodedLen(len(s))) @@ -755,7 +764,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool if v.NumMethod() == 0 { v.Set(reflect.ValueOf(string(s))) } else { - d.saveError(&UnmarshalTypeError{"string", v.Type()}) + d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)}) } } @@ -777,7 +786,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool if fromQuoted { d.error(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) } else { - d.error(&UnmarshalTypeError{"number", v.Type()}) + d.error(&UnmarshalTypeError{"number", v.Type(), int64(d.off)}) } case reflect.Interface: n, err := d.convertNumber(s) @@ -786,7 +795,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool break } if v.NumMethod() != 0 { - d.saveError(&UnmarshalTypeError{"number", v.Type()}) + d.saveError(&UnmarshalTypeError{"number", v.Type(), int64(d.off)}) break } v.Set(reflect.ValueOf(n)) @@ -794,7 +803,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: n, err := strconv.ParseInt(s, 10, 64) if err != nil || v.OverflowInt(n) { - d.saveError(&UnmarshalTypeError{"number " + s, v.Type()}) + d.saveError(&UnmarshalTypeError{"number " + s, v.Type(), int64(d.off)}) break } v.SetInt(n) @@ -802,7 +811,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: n, err := strconv.ParseUint(s, 10, 64) if err != nil || v.OverflowUint(n) { - d.saveError(&UnmarshalTypeError{"number " + s, v.Type()}) + d.saveError(&UnmarshalTypeError{"number " + s, v.Type(), int64(d.off)}) break } v.SetUint(n) @@ -810,7 +819,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool case reflect.Float32, reflect.Float64: n, err := strconv.ParseFloat(s, v.Type().Bits()) if err != nil || v.OverflowFloat(n) { - d.saveError(&UnmarshalTypeError{"number " + s, v.Type()}) + d.saveError(&UnmarshalTypeError{"number " + s, v.Type(), int64(d.off)}) break } v.SetFloat(n) diff --git a/libgo/go/encoding/json/decode_test.go b/libgo/go/encoding/json/decode_test.go index 7235969b9fe..8aa158f08cd 100644 --- a/libgo/go/encoding/json/decode_test.go +++ b/libgo/go/encoding/json/decode_test.go @@ -9,6 +9,7 @@ import ( "encoding" "fmt" "image" + "net" "reflect" "strings" "testing" @@ -216,6 +217,9 @@ type XYZ struct { Z interface{} } +func sliceAddr(x []int) *[]int { return &x } +func mapAddr(x map[string]int) *map[string]int { return &x } + var unmarshalTests = []unmarshalTest{ // basic types {in: `true`, ptr: new(bool), out: true}, @@ -231,7 +235,7 @@ var unmarshalTests = []unmarshalTest{ {in: `"g-clef: \uD834\uDD1E"`, ptr: new(string), out: "g-clef: \U0001D11E"}, {in: `"invalid: \uD834x\uDD1E"`, ptr: new(string), out: "invalid: \uFFFDx\uFFFD"}, {in: "null", ptr: new(interface{}), out: nil}, - {in: `{"X": [1,2,3], "Y": 4}`, ptr: new(T), out: T{Y: 4}, err: &UnmarshalTypeError{"array", reflect.TypeOf("")}}, + {in: `{"X": [1,2,3], "Y": 4}`, ptr: new(T), out: T{Y: 4}, err: &UnmarshalTypeError{"array", reflect.TypeOf(""), 7}}, {in: `{"x": 1}`, ptr: new(tx), out: tx{}}, {in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: float64(1), F2: int32(2), F3: Number("3")}}, {in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: Number("1"), F2: int32(2), F3: Number("3")}, useNumber: true}, @@ -302,6 +306,12 @@ var unmarshalTests = []unmarshalTest{ {in: `["X"]`, ptr: &umslicepT, out: &umsliceT}, {in: `{"M":"X"}`, ptr: &umstructT, out: umstructT}, + // Overwriting of data. + // This is different from package xml, but it's what we've always done. + // Now documented and tested. + {in: `[2]`, ptr: sliceAddr([]int{1}), out: []int{2}}, + {in: `{"key": 2}`, ptr: mapAddr(map[string]int{"old": 0, "key": 1}), out: map[string]int{"key": 2}}, + { in: `{ "Level0": 1, @@ -411,7 +421,7 @@ var unmarshalTests = []unmarshalTest{ { in: `{"2009-11-10T23:00:00Z": "hello world"}`, ptr: &map[time.Time]string{}, - err: &UnmarshalTypeError{"object", reflect.TypeOf(map[time.Time]string{})}, + err: &UnmarshalTypeError{"object", reflect.TypeOf(map[time.Time]string{}), 1}, }, } @@ -688,6 +698,7 @@ var wrongStringTests = []wrongStringTest{ {`{"result":"x"}`, `json: invalid use of ,string struct tag, trying to unmarshal "x" into string`}, {`{"result":"foo"}`, `json: invalid use of ,string struct tag, trying to unmarshal "foo" into string`}, {`{"result":"123"}`, `json: invalid use of ,string struct tag, trying to unmarshal "123" into string`}, + {`{"result":123}`, `json: invalid use of ,string struct tag, trying to unmarshal unquoted value into string`}, } // If people misuse the ,string modifier, the error message should be @@ -1085,7 +1096,7 @@ func TestNullString(t *testing.T) { *s.C = 2 err := Unmarshal(data, &s) if err != nil { - t.Fatalf("Unmarshal: %v") + t.Fatalf("Unmarshal: %v", err) } if s.B != 1 || s.C != nil { t.Fatalf("after Unmarshal, s.B=%d, s.C=%p, want 1, nil", s.B, s.C) @@ -1206,7 +1217,28 @@ func TestStringKind(t *testing.T) { if !reflect.DeepEqual(m1, m2) { t.Error("Items should be equal after encoding and then decoding") } +} + +// Custom types with []byte as underlying type could not be marshalled +// and then unmarshalled. +// Issue 8962. +func TestByteKind(t *testing.T) { + type byteKind []byte + a := byteKind("hello") + + data, err := Marshal(a) + if err != nil { + t.Error(err) + } + var b byteKind + err = Unmarshal(data, &b) + if err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(a, b) { + t.Errorf("expected %v == %v", a, b) + } } var decodeTypeErrorTests = []struct { @@ -1371,3 +1403,51 @@ func TestInvalidUnmarshal(t *testing.T) { } } } + +var invalidUnmarshalTextTests = []struct { + v interface{} + want string +}{ + {nil, "json: Unmarshal(nil)"}, + {struct{}{}, "json: Unmarshal(non-pointer struct {})"}, + {(*int)(nil), "json: Unmarshal(nil *int)"}, + {new(net.IP), "json: cannot unmarshal string into Go value of type *net.IP"}, +} + +func TestInvalidUnmarshalText(t *testing.T) { + buf := []byte(`123`) + for _, tt := range invalidUnmarshalTextTests { + err := Unmarshal(buf, tt.v) + if err == nil { + t.Errorf("Unmarshal expecting error, got nil") + continue + } + if got := err.Error(); got != tt.want { + t.Errorf("Unmarshal = %q; want %q", got, tt.want) + } + } +} + +// Test that string option is ignored for invalid types. +// Issue 9812. +func TestInvalidStringOption(t *testing.T) { + num := 0 + item := struct { + T time.Time `json:",string"` + M map[string]string `json:",string"` + S []string `json:",string"` + A [1]string `json:",string"` + I interface{} `json:",string"` + P *int `json:",string"` + }{M: make(map[string]string), S: make([]string, 0), I: num, P: &num} + + data, err := Marshal(item) + if err != nil { + t.Fatalf("Marshal: %v", err) + } + + err = Unmarshal(data, &item) + if err != nil { + t.Fatalf("Unmarshal: %v", err) + } +} diff --git a/libgo/go/encoding/json/encode.go b/libgo/go/encoding/json/encode.go index fca2a0980b2..90782deb70b 100644 --- a/libgo/go/encoding/json/encode.go +++ b/libgo/go/encoding/json/encode.go @@ -7,7 +7,7 @@ // in the documentation for the Marshal and Unmarshal functions. // // See "JSON and Go" for an introduction to this package: -// http://golang.org/doc/articles/json_and_go.html +// https://golang.org/doc/articles/json_and_go.html package json import ( @@ -79,8 +79,8 @@ import ( // // The "string" option signals that a field is stored as JSON inside a // JSON-encoded string. It applies only to fields of string, floating point, -// or integer types. This extra level of encoding is sometimes used when -// communicating with JavaScript programs: +// integer, or boolean types. This extra level of encoding is sometimes used +// when communicating with JavaScript programs: // // Int64String int64 `json:",string"` // @@ -113,8 +113,8 @@ import ( // a JSON tag of "-". // // Map values encode as JSON objects. -// The map's key type must be string; the object keys are used directly -// as map keys. +// The map's key type must be string; the map keys are used as JSON object +// keys, subject to the UTF-8 coercion described for string values above. // // Pointer values encode as the value pointed to. // A nil pointer encodes as the null JSON object. @@ -275,8 +275,6 @@ func (e *encodeState) error(err error) { panic(err) } -var byteSliceType = reflect.TypeOf([]byte(nil)) - func isEmptyValue(v reflect.Value) bool { switch v.Kind() { case reflect.Array, reflect.Map, reflect.Slice, reflect.String: @@ -1045,6 +1043,19 @@ func typeFields(t reflect.Type) []field { ft = ft.Elem() } + // Only strings, floats, integers, and booleans can be quoted. + quoted := false + if opts.Contains("string") { + switch ft.Kind() { + case reflect.Bool, + reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, + reflect.Float32, reflect.Float64, + reflect.String: + quoted = true + } + } + // Record found field and index sequence. if name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct { tagged := name != "" @@ -1057,7 +1068,7 @@ func typeFields(t reflect.Type) []field { index: index, typ: ft, omitEmpty: opts.Contains("omitempty"), - quoted: opts.Contains("string"), + quoted: quoted, })) if count[f.typ] > 1 { // If there were multiple instances, add a second, diff --git a/libgo/go/encoding/json/fold.go b/libgo/go/encoding/json/fold.go index d6f77c93e57..9e170127dba 100644 --- a/libgo/go/encoding/json/fold.go +++ b/libgo/go/encoding/json/fold.go @@ -26,7 +26,7 @@ const ( // The letters S and K are special because they map to 3 runes, not just 2: // * S maps to s and to U+017F 'ſ' Latin small letter long s // * k maps to K and to U+212A 'K' Kelvin sign -// See http://play.golang.org/p/tTxjOc0OGo +// See https://play.golang.org/p/tTxjOc0OGo // // The returned function is specialized for matching against s and // should only be given s. It's not curried for performance reasons. diff --git a/libgo/go/encoding/json/scanner.go b/libgo/go/encoding/json/scanner.go index a4609c89505..38d0b0802b3 100644 --- a/libgo/go/encoding/json/scanner.go +++ b/libgo/go/encoding/json/scanner.go @@ -38,8 +38,15 @@ func nextValue(data []byte, scan *scanner) (value, rest []byte, err error) { scan.reset() for i, c := range data { v := scan.step(scan, int(c)) - if v >= scanEnd { + if v >= scanEndObject { switch v { + // probe the scanner with a space to determine whether we will + // get scanEnd on the next character. Otherwise, if the next character + // is not a space, scanEndTop allocates a needless error. + case scanEndObject, scanEndArray: + if scan.step(scan, ' ') == scanEnd { + return data[:i+1], data[i+1:], nil + } case scanError: return nil, nil, scan.err case scanEnd: diff --git a/libgo/go/encoding/json/scanner_test.go b/libgo/go/encoding/json/scanner_test.go index 78803429029..66383ef0ef7 100644 --- a/libgo/go/encoding/json/scanner_test.go +++ b/libgo/go/encoding/json/scanner_test.go @@ -209,6 +209,7 @@ var benchScan scanner func BenchmarkSkipValue(b *testing.B) { initBig() + b.ResetTimer() for i := 0; i < b.N; i++ { nextValue(jsonBig, &benchScan) } diff --git a/libgo/go/encoding/json/stream.go b/libgo/go/encoding/json/stream.go index 9566ecadcbb..dc53bceff85 100644 --- a/libgo/go/encoding/json/stream.go +++ b/libgo/go/encoding/json/stream.go @@ -12,11 +12,15 @@ import ( // A Decoder reads and decodes JSON objects from an input stream. type Decoder struct { - r io.Reader - buf []byte - d decodeState - scan scanner - err error + r io.Reader + buf []byte + d decodeState + scanp int // start of unread data in buf + scan scanner + err error + + tokenState int + tokenStack []int } // NewDecoder returns a new decoder that reads from r. @@ -41,20 +45,29 @@ func (dec *Decoder) Decode(v interface{}) error { return dec.err } + if err := dec.tokenPrepareForDecode(); err != nil { + return err + } + + if !dec.tokenValueAllowed() { + return &SyntaxError{msg: "not at beginning of value"} + } + + // Read whole value into buffer. n, err := dec.readValue() if err != nil { return err } + dec.d.init(dec.buf[dec.scanp : dec.scanp+n]) + dec.scanp += n // Don't save err from unmarshal into dec.err: // the connection is still usable since we read a complete JSON // object from it before the error happened. - dec.d.init(dec.buf[0:n]) err = dec.d.unmarshal(v) - // Slide rest of data down. - rest := copy(dec.buf, dec.buf[n:]) - dec.buf = dec.buf[0:rest] + // fixup token streaming state + dec.tokenValueEnd() return err } @@ -62,7 +75,7 @@ func (dec *Decoder) Decode(v interface{}) error { // Buffered returns a reader of the data remaining in the Decoder's // buffer. The reader is valid until the next call to Decode. func (dec *Decoder) Buffered() io.Reader { - return bytes.NewReader(dec.buf) + return bytes.NewReader(dec.buf[dec.scanp:]) } // readValue reads a JSON value into dec.buf. @@ -70,7 +83,7 @@ func (dec *Decoder) Buffered() io.Reader { func (dec *Decoder) readValue() (int, error) { dec.scan.reset() - scanp := 0 + scanp := dec.scanp var err error Input: for { @@ -111,20 +124,35 @@ Input: return 0, err } - // Make room to read more into the buffer. - const minRead = 512 - if cap(dec.buf)-len(dec.buf) < minRead { - newBuf := make([]byte, len(dec.buf), 2*cap(dec.buf)+minRead) - copy(newBuf, dec.buf) - dec.buf = newBuf - } + n := scanp - dec.scanp + err = dec.refill() + scanp = dec.scanp + n + } + return scanp - dec.scanp, nil +} - // Read. Delay error for next iteration (after scan). - var n int - n, err = dec.r.Read(dec.buf[len(dec.buf):cap(dec.buf)]) - dec.buf = dec.buf[0 : len(dec.buf)+n] +func (dec *Decoder) refill() error { + // Make room to read more into the buffer. + // First slide down data already consumed. + if dec.scanp > 0 { + n := copy(dec.buf, dec.buf[dec.scanp:]) + dec.buf = dec.buf[:n] + dec.scanp = 0 } - return scanp, nil + + // Grow buffer if not large enough. + const minRead = 512 + if cap(dec.buf)-len(dec.buf) < minRead { + newBuf := make([]byte, len(dec.buf), 2*cap(dec.buf)+minRead) + copy(newBuf, dec.buf) + dec.buf = newBuf + } + + // Read. Delay error for next iteration (after scan). + n, err := dec.r.Read(dec.buf[len(dec.buf):cap(dec.buf)]) + dec.buf = dec.buf[0 : len(dec.buf)+n] + + return err } func nonSpace(b []byte) bool { @@ -198,3 +226,255 @@ func (m *RawMessage) UnmarshalJSON(data []byte) error { var _ Marshaler = (*RawMessage)(nil) var _ Unmarshaler = (*RawMessage)(nil) + +// A Token holds a value of one of these types: +// +// Delim, for the four JSON delimiters [ ] { } +// bool, for JSON booleans +// float64, for JSON numbers +// Number, for JSON numbers +// string, for JSON string literals +// nil, for JSON null +// +type Token interface{} + +const ( + tokenTopValue = iota + tokenArrayStart + tokenArrayValue + tokenArrayComma + tokenObjectStart + tokenObjectKey + tokenObjectColon + tokenObjectValue + tokenObjectComma +) + +// advance tokenstate from a separator state to a value state +func (dec *Decoder) tokenPrepareForDecode() error { + // Note: Not calling peek before switch, to avoid + // putting peek into the standard Decode path. + // peek is only called when using the Token API. + switch dec.tokenState { + case tokenArrayComma: + c, err := dec.peek() + if err != nil { + return err + } + if c != ',' { + return &SyntaxError{"expected comma after array element", 0} + } + dec.scanp++ + dec.tokenState = tokenArrayValue + case tokenObjectColon: + c, err := dec.peek() + if err != nil { + return err + } + if c != ':' { + return &SyntaxError{"expected colon after object key", 0} + } + dec.scanp++ + dec.tokenState = tokenObjectValue + } + return nil +} + +func (dec *Decoder) tokenValueAllowed() bool { + switch dec.tokenState { + case tokenTopValue, tokenArrayStart, tokenArrayValue, tokenObjectValue: + return true + } + return false +} + +func (dec *Decoder) tokenValueEnd() { + switch dec.tokenState { + case tokenArrayStart, tokenArrayValue: + dec.tokenState = tokenArrayComma + case tokenObjectValue: + dec.tokenState = tokenObjectComma + } +} + +// A Delim is a JSON array or object delimiter, one of [ ] { or }. +type Delim rune + +func (d Delim) String() string { + return string(d) +} + +// Token returns the next JSON token in the input stream. +// At the end of the input stream, Token returns nil, io.EOF. +// +// Token guarantees that the delimiters [ ] { } it returns are +// properly nested and matched: if Token encounters an unexpected +// delimiter in the input, it will return an error. +// +// The input stream consists of basic JSON values—bool, string, +// number, and null—along with delimiters [ ] { } of type Delim +// to mark the start and end of arrays and objects. +// Commas and colons are elided. +func (dec *Decoder) Token() (Token, error) { + for { + c, err := dec.peek() + if err != nil { + return nil, err + } + switch c { + case '[': + if !dec.tokenValueAllowed() { + return dec.tokenError(c) + } + dec.scanp++ + dec.tokenStack = append(dec.tokenStack, dec.tokenState) + dec.tokenState = tokenArrayStart + return Delim('['), nil + + case ']': + if dec.tokenState != tokenArrayStart && dec.tokenState != tokenArrayComma { + return dec.tokenError(c) + } + dec.scanp++ + dec.tokenState = dec.tokenStack[len(dec.tokenStack)-1] + dec.tokenStack = dec.tokenStack[:len(dec.tokenStack)-1] + dec.tokenValueEnd() + return Delim(']'), nil + + case '{': + if !dec.tokenValueAllowed() { + return dec.tokenError(c) + } + dec.scanp++ + dec.tokenStack = append(dec.tokenStack, dec.tokenState) + dec.tokenState = tokenObjectStart + return Delim('{'), nil + + case '}': + if dec.tokenState != tokenObjectStart && dec.tokenState != tokenObjectComma { + return dec.tokenError(c) + } + dec.scanp++ + dec.tokenState = dec.tokenStack[len(dec.tokenStack)-1] + dec.tokenStack = dec.tokenStack[:len(dec.tokenStack)-1] + dec.tokenValueEnd() + return Delim('}'), nil + + case ':': + if dec.tokenState != tokenObjectColon { + return dec.tokenError(c) + } + dec.scanp++ + dec.tokenState = tokenObjectValue + continue + + case ',': + if dec.tokenState == tokenArrayComma { + dec.scanp++ + dec.tokenState = tokenArrayValue + continue + } + if dec.tokenState == tokenObjectComma { + dec.scanp++ + dec.tokenState = tokenObjectKey + continue + } + return dec.tokenError(c) + + case '"': + if dec.tokenState == tokenObjectStart || dec.tokenState == tokenObjectKey { + var x string + old := dec.tokenState + dec.tokenState = tokenTopValue + err := dec.Decode(&x) + dec.tokenState = old + if err != nil { + clearOffset(err) + return nil, err + } + dec.tokenState = tokenObjectColon + return x, nil + } + fallthrough + + default: + if !dec.tokenValueAllowed() { + return dec.tokenError(c) + } + var x interface{} + if err := dec.Decode(&x); err != nil { + clearOffset(err) + return nil, err + } + return x, nil + } + } +} + +func clearOffset(err error) { + if s, ok := err.(*SyntaxError); ok { + s.Offset = 0 + } +} + +func (dec *Decoder) tokenError(c byte) (Token, error) { + var context string + switch dec.tokenState { + case tokenTopValue: + context = " looking for beginning of value" + case tokenArrayStart, tokenArrayValue, tokenObjectValue: + context = " looking for beginning of value" + case tokenArrayComma: + context = " after array element" + case tokenObjectKey: + context = " looking for beginning of object key string" + case tokenObjectColon: + context = " after object key" + case tokenObjectComma: + context = " after object key:value pair" + } + return nil, &SyntaxError{"invalid character " + quoteChar(int(c)) + " " + context, 0} +} + +// More reports whether there is another element in the +// current array or object being parsed. +func (dec *Decoder) More() bool { + c, err := dec.peek() + return err == nil && c != ']' && c != '}' +} + +func (dec *Decoder) peek() (byte, error) { + var err error + for { + for i := dec.scanp; i < len(dec.buf); i++ { + c := dec.buf[i] + if isSpace(rune(c)) { + continue + } + dec.scanp = i + return c, nil + } + // buffer has been scanned, now report any error + if err != nil { + return 0, err + } + err = dec.refill() + } +} + +/* +TODO + +// EncodeToken writes the given JSON token to the stream. +// It returns an error if the delimiters [ ] { } are not properly used. +// +// EncodeToken does not call Flush, because usually it is part of +// a larger operation such as Encode, and those will call Flush when finished. +// Callers that create an Encoder and then invoke EncodeToken directly, +// without using Encode, need to call Flush when finished to ensure that +// the JSON is written to the underlying writer. +func (e *Encoder) EncodeToken(t Token) error { + ... +} + +*/ diff --git a/libgo/go/encoding/json/stream_test.go b/libgo/go/encoding/json/stream_test.go index b562e87690d..c2e30408cd8 100644 --- a/libgo/go/encoding/json/stream_test.go +++ b/libgo/go/encoding/json/stream_test.go @@ -6,8 +6,12 @@ package json import ( "bytes" + "io" "io/ioutil" + "log" "net" + "net/http" + "net/http/httptest" "reflect" "strings" "testing" @@ -204,3 +208,147 @@ func BenchmarkEncoderEncode(b *testing.B) { } } } + +type tokenStreamCase struct { + json string + expTokens []interface{} +} + +type decodeThis struct { + v interface{} +} + +var tokenStreamCases []tokenStreamCase = []tokenStreamCase{ + // streaming token cases + {json: `10`, expTokens: []interface{}{float64(10)}}, + {json: ` [10] `, expTokens: []interface{}{ + Delim('['), float64(10), Delim(']')}}, + {json: ` [false,10,"b"] `, expTokens: []interface{}{ + Delim('['), false, float64(10), "b", Delim(']')}}, + {json: `{ "a": 1 }`, expTokens: []interface{}{ + Delim('{'), "a", float64(1), Delim('}')}}, + {json: `{"a": 1, "b":"3"}`, expTokens: []interface{}{ + Delim('{'), "a", float64(1), "b", "3", Delim('}')}}, + {json: ` [{"a": 1},{"a": 2}] `, expTokens: []interface{}{ + Delim('['), + Delim('{'), "a", float64(1), Delim('}'), + Delim('{'), "a", float64(2), Delim('}'), + Delim(']')}}, + {json: `{"obj": {"a": 1}}`, expTokens: []interface{}{ + Delim('{'), "obj", Delim('{'), "a", float64(1), Delim('}'), + Delim('}')}}, + {json: `{"obj": [{"a": 1}]}`, expTokens: []interface{}{ + Delim('{'), "obj", Delim('['), + Delim('{'), "a", float64(1), Delim('}'), + Delim(']'), Delim('}')}}, + + // streaming tokens with intermittent Decode() + {json: `{ "a": 1 }`, expTokens: []interface{}{ + Delim('{'), "a", + decodeThis{float64(1)}, + Delim('}')}}, + {json: ` [ { "a" : 1 } ] `, expTokens: []interface{}{ + Delim('['), + decodeThis{map[string]interface{}{"a": float64(1)}}, + Delim(']')}}, + {json: ` [{"a": 1},{"a": 2}] `, expTokens: []interface{}{ + Delim('['), + decodeThis{map[string]interface{}{"a": float64(1)}}, + decodeThis{map[string]interface{}{"a": float64(2)}}, + Delim(']')}}, + {json: `{ "obj" : [ { "a" : 1 } ] }`, expTokens: []interface{}{ + Delim('{'), "obj", Delim('['), + decodeThis{map[string]interface{}{"a": float64(1)}}, + Delim(']'), Delim('}')}}, + + {json: `{"obj": {"a": 1}}`, expTokens: []interface{}{ + Delim('{'), "obj", + decodeThis{map[string]interface{}{"a": float64(1)}}, + Delim('}')}}, + {json: `{"obj": [{"a": 1}]}`, expTokens: []interface{}{ + Delim('{'), "obj", + decodeThis{[]interface{}{ + map[string]interface{}{"a": float64(1)}, + }}, + Delim('}')}}, + {json: ` [{"a": 1} {"a": 2}] `, expTokens: []interface{}{ + Delim('['), + decodeThis{map[string]interface{}{"a": float64(1)}}, + decodeThis{&SyntaxError{"expected comma after array element", 0}}, + }}, + {json: `{ "a" 1 }`, expTokens: []interface{}{ + Delim('{'), "a", + decodeThis{&SyntaxError{"expected colon after object key", 0}}, + }}, +} + +func TestDecodeInStream(t *testing.T) { + + for ci, tcase := range tokenStreamCases { + + dec := NewDecoder(strings.NewReader(tcase.json)) + for i, etk := range tcase.expTokens { + + var tk interface{} + var err error + + if dt, ok := etk.(decodeThis); ok { + etk = dt.v + err = dec.Decode(&tk) + } else { + tk, err = dec.Token() + } + if experr, ok := etk.(error); ok { + if err == nil || err.Error() != experr.Error() { + t.Errorf("case %v: Expected error %v in %q, but was %v", ci, experr, tcase.json, err) + } + break + } else if err == io.EOF { + t.Errorf("case %v: Unexpected EOF in %q", ci, tcase.json) + break + } else if err != nil { + t.Errorf("case %v: Unexpected error '%v' in %q", ci, err, tcase.json) + break + } + if !reflect.DeepEqual(tk, etk) { + t.Errorf(`case %v: %q @ %v expected %T(%v) was %T(%v)`, ci, tcase.json, i, etk, etk, tk, tk) + break + } + } + } + +} + +// Test from golang.org/issue/11893 +func TestHTTPDecoding(t *testing.T) { + const raw = `{ "foo": "bar" }` + + ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(raw)) + })) + defer ts.Close() + res, err := http.Get(ts.URL) + if err != nil { + log.Fatalf("GET failed: %v", err) + } + defer res.Body.Close() + + foo := struct { + Foo string + }{} + + d := NewDecoder(res.Body) + err = d.Decode(&foo) + if err != nil { + t.Fatalf("Decode: %v", err) + } + if foo.Foo != "bar" { + t.Errorf("decoded %q; want \"bar\"", foo.Foo) + } + + // make sure we get the EOF the second time + err = d.Decode(&foo) + if err != io.EOF { + t.Errorf("err = %v; want io.EOF", err) + } +} diff --git a/libgo/go/encoding/json/tagkey_test.go b/libgo/go/encoding/json/tagkey_test.go index 23e71c7525a..85bb4ba8377 100644 --- a/libgo/go/encoding/json/tagkey_test.go +++ b/libgo/go/encoding/json/tagkey_test.go @@ -37,11 +37,11 @@ type miscPlaneTag struct { } type percentSlashTag struct { - V string `json:"text/html%"` // http://golang.org/issue/2718 + V string `json:"text/html%"` // https://golang.org/issue/2718 } type punctuationTag struct { - V string `json:"!#$%&()*+-./:<=>?@[]^_{|}~"` // http://golang.org/issue/3546 + V string `json:"!#$%&()*+-./:<=>?@[]^_{|}~"` // https://golang.org/issue/3546 } type emptyTag struct { diff --git a/libgo/go/encoding/pem/pem.go b/libgo/go/encoding/pem/pem.go index 8ff7ee8c33a..506196b1db9 100644 --- a/libgo/go/encoding/pem/pem.go +++ b/libgo/go/encoding/pem/pem.go @@ -10,8 +10,10 @@ package pem import ( "bytes" "encoding/base64" + "errors" "io" "sort" + "strings" ) // A Block represents a PEM encoded structure. @@ -110,27 +112,37 @@ func Decode(data []byte) (p *Block, rest []byte) { } // TODO(agl): need to cope with values that spread across lines. - key, val := line[0:i], line[i+1:] + key, val := line[:i], line[i+1:] key = bytes.TrimSpace(key) val = bytes.TrimSpace(val) p.Headers[string(key)] = string(val) rest = next } - i := bytes.Index(rest, pemEnd) - if i < 0 { + var endIndex int + // If there were no headers, the END line might occur + // immediately, without a leading newline. + if len(p.Headers) == 0 && bytes.HasPrefix(rest, pemEnd[1:]) { + endIndex = 0 + } else { + endIndex = bytes.Index(rest, pemEnd) + } + + if endIndex < 0 { return decodeError(data, rest) } - base64Data := removeWhitespace(rest[0:i]) + base64Data := removeWhitespace(rest[:endIndex]) p.Bytes = make([]byte, base64.StdEncoding.DecodedLen(len(base64Data))) n, err := base64.StdEncoding.Decode(p.Bytes, base64Data) if err != nil { return decodeError(data, rest) } - p.Bytes = p.Bytes[0:n] + p.Bytes = p.Bytes[:n] - _, rest = getLine(rest[i+len(pemEnd):]) + // the -1 is because we might have only matched pemEnd without the + // leading newline if the PEM block was empty. + _, rest = getLine(rest[endIndex+len(pemEnd)-1:]) return } @@ -171,6 +183,8 @@ type lineBreaker struct { out io.Writer } +var nl = []byte{'\n'} + func (l *lineBreaker) Write(b []byte) (n int, err error) { if l.used+len(b) < pemLineLength { copy(l.line[l.used:], b) @@ -190,7 +204,7 @@ func (l *lineBreaker) Write(b []byte) (n int, err error) { return } - n, err = l.out.Write([]byte{'\n'}) + n, err = l.out.Write(nl) if err != nil { return } @@ -204,7 +218,7 @@ func (l *lineBreaker) Close() (err error) { if err != nil { return } - _, err = l.out.Write([]byte{'\n'}) + _, err = l.out.Write(nl) } return @@ -244,11 +258,14 @@ func Encode(out io.Writer, b *Block) error { // For consistency of output, write other headers sorted by key. sort.Strings(h) for _, k := range h { + if strings.Contains(k, ":") { + return errors.New("pem: cannot encode a header key that contains a colon") + } if err := writeHeader(out, k, b.Headers[k]); err != nil { return err } } - if _, err := out.Write([]byte{'\n'}); err != nil { + if _, err := out.Write(nl); err != nil { return err } } diff --git a/libgo/go/encoding/pem/pem_test.go b/libgo/go/encoding/pem/pem_test.go index ccce42cf1ff..ab656c6261c 100644 --- a/libgo/go/encoding/pem/pem_test.go +++ b/libgo/go/encoding/pem/pem_test.go @@ -6,8 +6,11 @@ package pem import ( "bytes" + "io/ioutil" "reflect" + "strings" "testing" + "testing/quick" ) type GetLineTest struct { @@ -43,6 +46,32 @@ func TestDecode(t *testing.T) { if !reflect.DeepEqual(result, privateKey) { t.Errorf("#1 got:%#v want:%#v", result, privateKey) } + + isEmpty := func(block *Block) bool { + return block != nil && block.Type == "EMPTY" && len(block.Headers) == 0 && len(block.Bytes) == 0 + } + result, remainder = Decode(remainder) + if !isEmpty(result) { + t.Errorf("#2 should be empty but got:%#v", result) + } + result, remainder = Decode(remainder) + if !isEmpty(result) { + t.Errorf("#3 should be empty but got:%#v", result) + } + result, remainder = Decode(remainder) + if !isEmpty(result) { + t.Errorf("#4 should be empty but got:%#v", result) + } + + result, remainder = Decode(remainder) + if result == nil || result.Type != "HEADERS" || len(result.Headers) != 1 { + t.Errorf("#5 expected single header block but got :%v", result) + } + + if len(remainder) != 0 { + t.Errorf("expected nothing remaining of pemData, but found %s", string(remainder)) + } + result, _ = Decode([]byte(pemPrivateKey2)) if !reflect.DeepEqual(result, privateKey2) { t.Errorf("#2 got:%#v want:%#v", result, privateKey2) @@ -116,6 +145,62 @@ func TestLineBreaker(t *testing.T) { } } +func TestFuzz(t *testing.T) { + testRoundtrip := func(block Block) bool { + for key := range block.Headers { + if strings.Contains(key, ":") { + // Keys with colons cannot be encoded. + return true + } + } + + var buf bytes.Buffer + err := Encode(&buf, &block) + decoded, rest := Decode(buf.Bytes()) + + switch { + case err != nil: + t.Errorf("Encode of %#v resulted in error: %s", &block, err) + case !reflect.DeepEqual(&block, decoded): + t.Errorf("Encode of %#v decoded as %#v", &block, decoded) + case len(rest) != 0: + t.Errorf("Encode of %#v decoded correctly, but with %x left over", block, rest) + default: + return true + } + return false + } + + // Explicitly test the empty block. + if !testRoundtrip(Block{ + Type: "EMPTY", + Headers: make(map[string]string), + Bytes: []byte{}, + }) { + return + } + + quick.Check(testRoundtrip, nil) +} + +func BenchmarkEncode(b *testing.B) { + data := &Block{Bytes: make([]byte, 65536)} + b.SetBytes(int64(len(data.Bytes))) + for i := 0; i < b.N; i++ { + Encode(ioutil.Discard, data) + } +} + +func BenchmarkDecode(b *testing.B) { + block := &Block{Bytes: make([]byte, 65536)} + data := EncodeToMemory(block) + b.SetBytes(int64(len(data))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + Decode(data) + } +} + var pemData = `verify return:0 -----BEGIN CERTIFICATE----- sdlfkjskldfj @@ -169,7 +254,32 @@ BTiHcL3s3KrJu1vDVrshvxfnz71KTeNnZH8UbOqT5i7fPGyXtY1XJddcbI/Q6tXf wHFsZc20TzSdsVLBtwksUacpbDogcEVMctnNrB8FIrB3vZEv9Q0Z1VeY7nmTpF+6 a+z2P7acL7j6A6Pr3+q8P9CPiPC7zFonVzuVPyB8GchGR2hytyiOVpuD9+k8hcuw ZWAaUoVtWIQ52aKS0p19G99hhb+IVANC4akkdHV4SP8i7MVNZhfUmg== ------END RSA PRIVATE KEY-----` +-----END RSA PRIVATE KEY----- + + +-----BEGIN EMPTY----- +-----END EMPTY----- + +-----BEGIN EMPTY----- + +-----END EMPTY----- + +-----BEGIN EMPTY----- + + +-----END EMPTY----- + +# This shouldn't be recognised because of the missing newline after the +headers. +-----BEGIN HEADERS----- +Header: 1 +-----END HEADERS----- + +# This should be valid, however. +-----BEGIN HEADERS----- +Header: 1 + +-----END HEADERS-----` var certificate = &Block{Type: "CERTIFICATE", Headers: map[string]string{}, diff --git a/libgo/go/encoding/xml/marshal.go b/libgo/go/encoding/xml/marshal.go index 8c6342013d3..86d1422a5bd 100644 --- a/libgo/go/encoding/xml/marshal.go +++ b/libgo/go/encoding/xml/marshal.go @@ -173,6 +173,7 @@ func (enc *Encoder) EncodeElement(v interface{}, start StartElement) error { } var ( + begComment = []byte("") endProcInst = []byte("?>") endDirective = []byte(">") @@ -191,6 +192,7 @@ var ( // EncodeToken allows writing a ProcInst with Target set to "xml" only as the first token // in the stream. func (enc *Encoder) EncodeToken(t Token) error { + p := &enc.p switch t := t.(type) { case StartElement: @@ -202,7 +204,7 @@ func (enc *Encoder) EncodeToken(t Token) error { return err } case CharData: - EscapeText(p, t) + escapeText(p, t, false) case Comment: if bytes.Contains(t, endComment) { return fmt.Errorf("xml: EncodeToken of Comment containing --> marker") @@ -231,16 +233,59 @@ func (enc *Encoder) EncodeToken(t Token) error { } p.WriteString("?>") case Directive: - if bytes.Contains(t, endDirective) { - return fmt.Errorf("xml: EncodeToken of Directive containing > marker") + if !isValidDirective(t) { + return fmt.Errorf("xml: EncodeToken of Directive containing wrong < or > markers") } p.WriteString("") + default: + return fmt.Errorf("xml: EncodeToken of invalid token type") + } return p.cachedWriteError() } +// isValidDirective reports whether dir is a valid directive text, +// meaning angle brackets are matched, ignoring comments and strings. +func isValidDirective(dir Directive) bool { + var ( + depth int + inquote uint8 + incomment bool + ) + for i, c := range dir { + switch { + case incomment: + if c == '>' { + if n := 1 + i - len(endComment); n >= 0 && bytes.Equal(dir[n:i+1], endComment) { + incomment = false + } + } + // Just ignore anything in comment + case inquote != 0: + if c == inquote { + inquote = 0 + } + // Just ignore anything within quotes + case c == '\'' || c == '"': + inquote = c + case c == '<': + if i+len(begComment) < len(dir) && bytes.Equal(dir[i:i+len(begComment)], begComment) { + incomment = true + } else { + depth++ + } + case c == '>': + if depth == 0 { + return false + } + depth-- + } + } + return depth == 0 && inquote == 0 && !incomment +} + // Flush flushes any buffered XML to the underlying writer. // See the EncodeToken documentation for details about when it is necessary. func (enc *Encoder) Flush() error { @@ -724,6 +769,9 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error { switch finfo.flags & fMode { case fCharData: + if err := s.trim(finfo.parents); err != nil { + return err + } if vf.CanInterface() && vf.Type().Implements(textMarshalerType) { data, err := vf.Interface().(encoding.TextMarshaler).MarshalText() if err != nil { @@ -767,6 +815,9 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error { continue case fComment: + if err := s.trim(finfo.parents); err != nil { + return err + } k := vf.Kind() if !(k == reflect.String || k == reflect.Slice && vf.Type().Elem().Kind() == reflect.Uint8) { return fmt.Errorf("xml: bad type for comment field of %s", val.Type()) @@ -894,7 +945,7 @@ func (s *parentStack) trim(parents []string) error { return err } } - s.stack = parents[:split] + s.stack = s.stack[:split] return nil } diff --git a/libgo/go/encoding/xml/marshal_test.go b/libgo/go/encoding/xml/marshal_test.go index 14f73a75d5f..66675d7abc4 100644 --- a/libgo/go/encoding/xml/marshal_test.go +++ b/libgo/go/encoding/xml/marshal_test.go @@ -12,6 +12,7 @@ import ( "reflect" "strconv" "strings" + "sync" "testing" "time" ) @@ -339,6 +340,16 @@ type OuterOuterStruct struct { OuterStruct } +type NestedAndChardata struct { + AB []string `xml:"A>B"` + Chardata string `xml:",chardata"` +} + +type NestedAndComment struct { + AB []string `xml:"A>B"` + Comment string `xml:",comment"` +} + func ifaceptr(x interface{}) interface{} { return &x } @@ -617,6 +628,69 @@ var marshalTests = []struct { ``, MarshalOnly: true, }, + { + Value: &struct { + XMLName struct{} `xml:"space top"` + A string `xml:"x>a"` + B string `xml:"x>b"` + C string `xml:"space x>c"` + C1 string `xml:"space1 x>c"` + D1 string `xml:"space1 x>d"` + }{ + A: "a", + B: "b", + C: "c", + C1: "c1", + D1: "d1", + }, + ExpectXML: `` + + `abc` + + `c1` + + `d1` + + `` + + ``, + }, + { + Value: &struct { + XMLName Name + A string `xml:"x>a"` + B string `xml:"x>b"` + C string `xml:"space x>c"` + C1 string `xml:"space1 x>c"` + D1 string `xml:"space1 x>d"` + }{ + XMLName: Name{ + Space: "space0", + Local: "top", + }, + A: "a", + B: "b", + C: "c", + C1: "c1", + D1: "d1", + }, + ExpectXML: `` + + `ab` + + `c` + + `c1` + + `d1` + + `` + + ``, + }, + { + Value: &struct { + XMLName struct{} `xml:"top"` + B string `xml:"space x>b"` + B1 string `xml:"space1 x>b"` + }{ + B: "b", + B1: "b1", + }, + ExpectXML: `` + + `b` + + `b1` + + ``, + }, // Test struct embedding { @@ -924,6 +998,14 @@ var marshalTests = []struct { ExpectXML: ``, Value: &OuterOuterStruct{OuterStruct{IntAttr: 10}}, }, + { + ExpectXML: `test`, + Value: &NestedAndChardata{AB: make([]string, 2), Chardata: "test"}, + }, + { + ExpectXML: ``, + Value: &NestedAndComment{AB: make([]string, 2), Comment: "test"}, + }, } func TestMarshal(t *testing.T) { @@ -933,7 +1015,7 @@ func TestMarshal(t *testing.T) { } data, err := Marshal(test.Value) if err != nil { - t.Errorf("#%d: Error: %s", idx, err) + t.Errorf("#%d: marshal(%#v): %s", idx, test.Value, err) continue } if got, want := string(data), test.ExpectXML; got != want { @@ -1037,6 +1119,14 @@ func TestUnmarshal(t *testing.T) { if _, ok := test.Value.(*Plain); ok { continue } + if test.ExpectXML == ``+ + `b`+ + `b1`+ + `` { + // TODO(rogpeppe): re-enable this test in + // https://go-review.googlesource.com/#/c/5910/ + continue + } vt := reflect.TypeOf(test.Value) dest := reflect.New(vt.Elem()).Interface() @@ -1148,12 +1238,14 @@ func TestMarshalFlush(t *testing.T) { } func BenchmarkMarshal(b *testing.B) { + b.ReportAllocs() for i := 0; i < b.N; i++ { Marshal(atomValue) } } func BenchmarkUnmarshal(b *testing.B) { + b.ReportAllocs() xml := []byte(atomXml) for i := 0; i < b.N; i++ { Unmarshal(xml, &Feed{}) @@ -1192,41 +1284,369 @@ func TestStructPointerMarshal(t *testing.T) { } var encodeTokenTests = []struct { - tok Token + desc string + toks []Token want string - ok bool -}{ - {StartElement{Name{"space", "local"}, nil}, "", true}, - {StartElement{Name{"space", ""}, nil}, "", false}, - {EndElement{Name{"space", ""}}, "", false}, - {CharData("foo"), "foo", true}, - {Comment("foo"), "", true}, - {Comment("foo-->"), "", false}, - {ProcInst{"Target", []byte("Instruction")}, "", true}, - {ProcInst{"", []byte("Instruction")}, "", false}, - {ProcInst{"Target", []byte("Instruction?>")}, "", false}, - {Directive("foo"), "", true}, - {Directive("foo>"), "", false}, -} + err string +}{{ + desc: "start element with name space", + toks: []Token{ + StartElement{Name{"space", "local"}, nil}, + }, + want: ``, +}, { + desc: "start element with no name", + toks: []Token{ + StartElement{Name{"space", ""}, nil}, + }, + err: "xml: start tag with no name", +}, { + desc: "end element with no name", + toks: []Token{ + EndElement{Name{"space", ""}}, + }, + err: "xml: end tag with no name", +}, { + desc: "char data", + toks: []Token{ + CharData("foo"), + }, + want: `foo`, +}, { + desc: "char data with escaped chars", + toks: []Token{ + CharData(" \t\n"), + }, + want: " \n", +}, { + desc: "comment", + toks: []Token{ + Comment("foo"), + }, + want: ``, +}, { + desc: "comment with invalid content", + toks: []Token{ + Comment("foo-->"), + }, + err: "xml: EncodeToken of Comment containing --> marker", +}, { + desc: "proc instruction", + toks: []Token{ + ProcInst{"Target", []byte("Instruction")}, + }, + want: ``, +}, { + desc: "proc instruction with empty target", + toks: []Token{ + ProcInst{"", []byte("Instruction")}, + }, + err: "xml: EncodeToken of ProcInst with invalid Target", +}, { + desc: "proc instruction with bad content", + toks: []Token{ + ProcInst{"", []byte("Instruction?>")}, + }, + err: "xml: EncodeToken of ProcInst with invalid Target", +}, { + desc: "directive", + toks: []Token{ + Directive("foo"), + }, + want: ``, +}, { + desc: "more complex directive", + toks: []Token{ + Directive("DOCTYPE doc [ '> ]"), + }, + want: `'> ]>`, +}, { + desc: "directive instruction with bad name", + toks: []Token{ + Directive("foo>"), + }, + err: "xml: EncodeToken of Directive containing wrong < or > markers", +}, { + desc: "end tag without start tag", + toks: []Token{ + EndElement{Name{"foo", "bar"}}, + }, + err: "xml: end tag without start tag", +}, { + desc: "mismatching end tag local name", + toks: []Token{ + StartElement{Name{"", "foo"}, nil}, + EndElement{Name{"", "bar"}}, + }, + err: "xml: end tag does not match start tag ", + want: ``, +}, { + desc: "mismatching end tag namespace", + toks: []Token{ + StartElement{Name{"space", "foo"}, nil}, + EndElement{Name{"another", "foo"}}, + }, + err: "xml: end tag in namespace another does not match start tag in namespace space", + want: ``, +}, { + desc: "start element with explicit namespace", + toks: []Token{ + StartElement{Name{"space", "local"}, []Attr{ + {Name{"xmlns", "x"}, "space"}, + {Name{"space", "foo"}, "value"}, + }}, + }, + want: ``, +}, { + desc: "start element with explicit namespace and colliding prefix", + toks: []Token{ + StartElement{Name{"space", "local"}, []Attr{ + {Name{"xmlns", "x"}, "space"}, + {Name{"space", "foo"}, "value"}, + {Name{"x", "bar"}, "other"}, + }}, + }, + want: ``, +}, { + desc: "start element using previously defined namespace", + toks: []Token{ + StartElement{Name{"", "local"}, []Attr{ + {Name{"xmlns", "x"}, "space"}, + }}, + StartElement{Name{"space", "foo"}, []Attr{ + {Name{"space", "x"}, "y"}, + }}, + }, + want: ``, +}, { + desc: "nested name space with same prefix", + toks: []Token{ + StartElement{Name{"", "foo"}, []Attr{ + {Name{"xmlns", "x"}, "space1"}, + }}, + StartElement{Name{"", "foo"}, []Attr{ + {Name{"xmlns", "x"}, "space2"}, + }}, + StartElement{Name{"", "foo"}, []Attr{ + {Name{"space1", "a"}, "space1 value"}, + {Name{"space2", "b"}, "space2 value"}, + }}, + EndElement{Name{"", "foo"}}, + EndElement{Name{"", "foo"}}, + StartElement{Name{"", "foo"}, []Attr{ + {Name{"space1", "a"}, "space1 value"}, + {Name{"space2", "b"}, "space2 value"}, + }}, + }, + want: ``, +}, { + desc: "start element defining several prefixes for the same name space", + toks: []Token{ + StartElement{Name{"space", "foo"}, []Attr{ + {Name{"xmlns", "a"}, "space"}, + {Name{"xmlns", "b"}, "space"}, + {Name{"space", "x"}, "value"}, + }}, + }, + want: ``, +}, { + desc: "nested element redefines name space", + toks: []Token{ + StartElement{Name{"", "foo"}, []Attr{ + {Name{"xmlns", "x"}, "space"}, + }}, + StartElement{Name{"space", "foo"}, []Attr{ + {Name{"xmlns", "y"}, "space"}, + {Name{"space", "a"}, "value"}, + }}, + }, + want: ``, +}, { + desc: "nested element creates alias for default name space", + toks: []Token{ + StartElement{Name{"space", "foo"}, []Attr{ + {Name{"", "xmlns"}, "space"}, + }}, + StartElement{Name{"space", "foo"}, []Attr{ + {Name{"xmlns", "y"}, "space"}, + {Name{"space", "a"}, "value"}, + }}, + }, + want: ``, +}, { + desc: "nested element defines default name space with existing prefix", + toks: []Token{ + StartElement{Name{"", "foo"}, []Attr{ + {Name{"xmlns", "x"}, "space"}, + }}, + StartElement{Name{"space", "foo"}, []Attr{ + {Name{"", "xmlns"}, "space"}, + {Name{"space", "a"}, "value"}, + }}, + }, + want: ``, +}, { + desc: "nested element uses empty attribute name space when default ns defined", + toks: []Token{ + StartElement{Name{"space", "foo"}, []Attr{ + {Name{"", "xmlns"}, "space"}, + }}, + StartElement{Name{"space", "foo"}, []Attr{ + {Name{"", "attr"}, "value"}, + }}, + }, + want: ``, +}, { + desc: "redefine xmlns", + toks: []Token{ + StartElement{Name{"", "foo"}, []Attr{ + {Name{"foo", "xmlns"}, "space"}, + }}, + }, + want: ``, +}, { + desc: "xmlns with explicit name space #1", + toks: []Token{ + StartElement{Name{"space", "foo"}, []Attr{ + {Name{"xml", "xmlns"}, "space"}, + }}, + }, + want: ``, +}, { + desc: "xmlns with explicit name space #2", + toks: []Token{ + StartElement{Name{"space", "foo"}, []Attr{ + {Name{xmlURL, "xmlns"}, "space"}, + }}, + }, + want: ``, +}, { + desc: "empty name space declaration is ignored", + toks: []Token{ + StartElement{Name{"", "foo"}, []Attr{ + {Name{"xmlns", "foo"}, ""}, + }}, + }, + want: ``, +}, { + desc: "attribute with no name is ignored", + toks: []Token{ + StartElement{Name{"", "foo"}, []Attr{ + {Name{"", ""}, "value"}, + }}, + }, + want: ``, +}, { + desc: "namespace URL with non-valid name", + toks: []Token{ + StartElement{Name{"/34", "foo"}, []Attr{ + {Name{"/34", "x"}, "value"}, + }}, + }, + want: ``, +}, { + desc: "nested element resets default namespace to empty", + toks: []Token{ + StartElement{Name{"space", "foo"}, []Attr{ + {Name{"", "xmlns"}, "space"}, + }}, + StartElement{Name{"", "foo"}, []Attr{ + {Name{"", "xmlns"}, ""}, + {Name{"", "x"}, "value"}, + {Name{"space", "x"}, "value"}, + }}, + }, + want: ``, +}, { + desc: "nested element requires empty default name space", + toks: []Token{ + StartElement{Name{"space", "foo"}, []Attr{ + {Name{"", "xmlns"}, "space"}, + }}, + StartElement{Name{"", "foo"}, nil}, + }, + want: ``, +}, { + desc: "attribute uses name space from xmlns", + toks: []Token{ + StartElement{Name{"some/space", "foo"}, []Attr{ + {Name{"", "attr"}, "value"}, + {Name{"some/space", "other"}, "other value"}, + }}, + }, + want: ``, +}, { + desc: "default name space should not be used by attributes", + toks: []Token{ + StartElement{Name{"space", "foo"}, []Attr{ + {Name{"", "xmlns"}, "space"}, + {Name{"xmlns", "bar"}, "space"}, + {Name{"space", "baz"}, "foo"}, + }}, + StartElement{Name{"space", "baz"}, nil}, + EndElement{Name{"space", "baz"}}, + EndElement{Name{"space", "foo"}}, + }, + want: ``, +}, { + desc: "default name space not used by attributes, not explicitly defined", + toks: []Token{ + StartElement{Name{"space", "foo"}, []Attr{ + {Name{"", "xmlns"}, "space"}, + {Name{"space", "baz"}, "foo"}, + }}, + StartElement{Name{"space", "baz"}, nil}, + EndElement{Name{"space", "baz"}}, + EndElement{Name{"space", "foo"}}, + }, + want: ``, +}, { + desc: "impossible xmlns declaration", + toks: []Token{ + StartElement{Name{"", "foo"}, []Attr{ + {Name{"", "xmlns"}, "space"}, + }}, + StartElement{Name{"space", "bar"}, []Attr{ + {Name{"space", "attr"}, "value"}, + }}, + }, + want: ``, +}} func TestEncodeToken(t *testing.T) { - for _, tt := range encodeTokenTests { +loop: + for i, tt := range encodeTokenTests { var buf bytes.Buffer enc := NewEncoder(&buf) - err := enc.EncodeToken(tt.tok) + var err error + for j, tok := range tt.toks { + err = enc.EncodeToken(tok) + if err != nil && j < len(tt.toks)-1 { + t.Errorf("#%d %s token #%d: %v", i, tt.desc, j, err) + continue loop + } + } + errorf := func(f string, a ...interface{}) { + t.Errorf("#%d %s token #%d:%s", i, tt.desc, len(tt.toks)-1, fmt.Sprintf(f, a...)) + } switch { - case !tt.ok && err == nil: - t.Errorf("enc.EncodeToken(%#v): expected error; got none", tt.tok) - case tt.ok && err != nil: - t.Fatalf("enc.EncodeToken: %v", err) - case !tt.ok && err != nil: - // expected error, got one + case tt.err != "" && err == nil: + errorf(" expected error; got none") + continue + case tt.err == "" && err != nil: + errorf(" got error: %v", err) + continue + case tt.err != "" && err != nil && tt.err != err.Error(): + errorf(" error mismatch; got %v, want %v", err, tt.err) + continue } if err := enc.Flush(); err != nil { - t.Fatalf("enc.EncodeToken: %v", err) + errorf(" %v", err) + continue } if got := buf.String(); got != tt.want { - t.Errorf("enc.EncodeToken = %s; want: %s", got, tt.want) + errorf("\ngot %v\nwant %v", got, tt.want) + continue } } } @@ -1264,3 +1684,83 @@ func TestDecodeEncode(t *testing.T) { } } } + +// Issue 9796. Used to fail with GORACE="halt_on_error=1" -race. +func TestRace9796(t *testing.T) { + type A struct{} + type B struct { + C []A `xml:"X>Y"` + } + var wg sync.WaitGroup + for i := 0; i < 2; i++ { + wg.Add(1) + go func() { + Marshal(B{[]A{A{}}}) + wg.Done() + }() + } + wg.Wait() +} + +func TestIsValidDirective(t *testing.T) { + testOK := []string{ + "<>", + "< < > >", + "' '>' >", + " ]>", + " '<' ' doc ANY> ]>", + ">>> a < comment --> [ ] >", + } + testKO := []string{ + "<", + ">", + "", + "< > > < < >", + " -->", + "", + "'", + "", + } + for _, s := range testOK { + if !isValidDirective(Directive(s)) { + t.Errorf("Directive %q is expected to be valid", s) + } + } + for _, s := range testKO { + if isValidDirective(Directive(s)) { + t.Errorf("Directive %q is expected to be invalid", s) + } + } +} + +// Issue 11719. EncodeToken used to silently eat tokens with an invalid type. +func TestSimpleUseOfEncodeToken(t *testing.T) { + var buf bytes.Buffer + enc := NewEncoder(&buf) + if err := enc.EncodeToken(&StartElement{Name: Name{"", "object1"}}); err == nil { + t.Errorf("enc.EncodeToken: pointer type should be rejected") + } + if err := enc.EncodeToken(&EndElement{Name: Name{"", "object1"}}); err == nil { + t.Errorf("enc.EncodeToken: pointer type should be rejected") + } + if err := enc.EncodeToken(StartElement{Name: Name{"", "object2"}}); err != nil { + t.Errorf("enc.EncodeToken: StartElement %s", err) + } + if err := enc.EncodeToken(EndElement{Name: Name{"", "object2"}}); err != nil { + t.Errorf("enc.EncodeToken: EndElement %s", err) + } + if err := enc.EncodeToken(Universe{}); err == nil { + t.Errorf("enc.EncodeToken: invalid type not caught") + } + if err := enc.Flush(); err != nil { + t.Errorf("enc.Flush: %s", err) + } + if buf.Len() == 0 { + t.Errorf("enc.EncodeToken: empty buffer") + } + want := "" + if buf.String() != want { + t.Errorf("enc.EncodeToken: expected %q; got %q", want, buf.String()) + } +} diff --git a/libgo/go/encoding/xml/read_test.go b/libgo/go/encoding/xml/read_test.go index 01f55d0dd00..7d004dc488c 100644 --- a/libgo/go/encoding/xml/read_test.go +++ b/libgo/go/encoding/xml/read_test.go @@ -694,7 +694,7 @@ type Pod struct { Pea interface{} `xml:"Pea"` } -// https://code.google.com/p/go/issues/detail?id=6836 +// https://golang.org/issue/6836 func TestUnmarshalIntoInterface(t *testing.T) { pod := new(Pod) pod.Pea = new(Pea) diff --git a/libgo/go/encoding/xml/xml.go b/libgo/go/encoding/xml/xml.go index 8c15b98c3a9..0a21c930531 100644 --- a/libgo/go/encoding/xml/xml.go +++ b/libgo/go/encoding/xml/xml.go @@ -549,7 +549,6 @@ func (d *Decoder) rawToken() (Token, error) { case '?': // if target == "xml" { - enc := procInstEncoding(string(data)) + content := string(data) + ver := procInst("version", content) + if ver != "" && ver != "1.0" { + d.err = fmt.Errorf("xml: unsupported version %q; only version 1.0 is supported", ver) + return nil, d.err + } + enc := procInst("encoding", content) if enc != "" && enc != "utf-8" && enc != "UTF-8" { if d.CharsetReader == nil { d.err = fmt.Errorf("xml: encoding %q declared but Decoder.CharsetReader is nil", enc) @@ -723,7 +728,7 @@ func (d *Decoder) rawToken() (Token, error) { return nil, d.err } - attr = make([]Attr, 0, 4) + attr = []Attr{} for { d.space() if b, ok = d.mustgetc(); !ok { @@ -747,7 +752,11 @@ func (d *Decoder) rawToken() (Token, error) { n := len(attr) if n >= cap(attr) { - nattr := make([]Attr, n, 2*cap(attr)) + nCap := 2 * cap(attr) + if nCap == 0 { + nCap = 4 + } + nattr := make([]Attr, n, nCap) copy(nattr, attr) attr = nattr } @@ -1119,12 +1128,12 @@ func (d *Decoder) name() (s string, ok bool) { } // Now we check the characters. - s = d.buf.String() - if !isName([]byte(s)) { - d.err = d.syntaxError("invalid XML name: " + s) + b := d.buf.Bytes() + if !isName(b) { + d.err = d.syntaxError("invalid XML name: " + string(b)) return "", false } - return s, true + return string(b), true } // Read a name and append its bytes to d.buf. @@ -1832,6 +1841,13 @@ var ( // EscapeText writes to w the properly escaped XML equivalent // of the plain text data s. func EscapeText(w io.Writer, s []byte) error { + return escapeText(w, s, true) +} + +// escapeText writes to w the properly escaped XML equivalent +// of the plain text data s. If escapeNewline is true, newline +// characters will be escaped. +func escapeText(w io.Writer, s []byte, escapeNewline bool) error { var esc []byte last := 0 for i := 0; i < len(s); { @@ -1851,6 +1867,9 @@ func EscapeText(w io.Writer, s []byte) error { case '\t': esc = esc_tab case '\n': + if !escapeNewline { + continue + } esc = esc_nl case '\r': esc = esc_cr @@ -1921,16 +1940,17 @@ func Escape(w io.Writer, s []byte) { EscapeText(w, s) } -// procInstEncoding parses the `encoding="..."` or `encoding='...'` +// procInst parses the `param="..."` or `param='...'` // value out of the provided string, returning "" if not found. -func procInstEncoding(s string) string { +func procInst(param, s string) string { // TODO: this parsing is somewhat lame and not exact. // It works for all actual cases, though. - idx := strings.Index(s, "encoding=") + param = param + "=" + idx := strings.Index(s, param) if idx == -1 { return "" } - v := s[idx+len("encoding="):] + v := s[idx+len(param):] if v == "" { return "" } diff --git a/libgo/go/encoding/xml/xml_test.go b/libgo/go/encoding/xml/xml_test.go index be995c0d52c..312a7c98a5c 100644 --- a/libgo/go/encoding/xml/xml_test.go +++ b/libgo/go/encoding/xml/xml_test.go @@ -657,20 +657,23 @@ type procInstEncodingTest struct { } var procInstTests = []struct { - input, expect string + input string + expect [2]string }{ - {`version="1.0" encoding="utf-8"`, "utf-8"}, - {`version="1.0" encoding='utf-8'`, "utf-8"}, - {`version="1.0" encoding='utf-8' `, "utf-8"}, - {`version="1.0" encoding=utf-8`, ""}, - {`encoding="FOO" `, "FOO"}, + {`version="1.0" encoding="utf-8"`, [2]string{"1.0", "utf-8"}}, + {`version="1.0" encoding='utf-8'`, [2]string{"1.0", "utf-8"}}, + {`version="1.0" encoding='utf-8' `, [2]string{"1.0", "utf-8"}}, + {`version="1.0" encoding=utf-8`, [2]string{"1.0", ""}}, + {`encoding="FOO" `, [2]string{"", "FOO"}}, } func TestProcInstEncoding(t *testing.T) { for _, test := range procInstTests { - got := procInstEncoding(test.input) - if got != test.expect { - t.Errorf("procInstEncoding(%q) = %q; want %q", test.input, got, test.expect) + if got := procInst("version", test.input); got != test.expect[0] { + t.Errorf("procInst(version, %q) = %q; want %q", test.input, got, test.expect[0]) + } + if got := procInst("encoding", test.input); got != test.expect[1] { + t.Errorf("procInst(encoding, %q) = %q; want %q", test.input, got, test.expect[1]) } } } diff --git a/libgo/go/expvar/expvar.go b/libgo/go/expvar/expvar.go index 9b6dab487cb..24c2d6b29ab 100644 --- a/libgo/go/expvar/expvar.go +++ b/libgo/go/expvar/expvar.go @@ -26,12 +26,14 @@ import ( "encoding/json" "fmt" "log" + "math" "net/http" "os" "runtime" "sort" "strconv" "sync" + "sync/atomic" ) // Var is an abstract type for all exported variables. @@ -41,52 +43,47 @@ type Var interface { // Int is a 64-bit integer variable that satisfies the Var interface. type Int struct { - mu sync.RWMutex - i int64 + i int64 } func (v *Int) String() string { - v.mu.RLock() - defer v.mu.RUnlock() - return strconv.FormatInt(v.i, 10) + return strconv.FormatInt(atomic.LoadInt64(&v.i), 10) } func (v *Int) Add(delta int64) { - v.mu.Lock() - defer v.mu.Unlock() - v.i += delta + atomic.AddInt64(&v.i, delta) } func (v *Int) Set(value int64) { - v.mu.Lock() - defer v.mu.Unlock() - v.i = value + atomic.StoreInt64(&v.i, value) } // Float is a 64-bit float variable that satisfies the Var interface. type Float struct { - mu sync.RWMutex - f float64 + f uint64 } func (v *Float) String() string { - v.mu.RLock() - defer v.mu.RUnlock() - return strconv.FormatFloat(v.f, 'g', -1, 64) + return strconv.FormatFloat( + math.Float64frombits(atomic.LoadUint64(&v.f)), 'g', -1, 64) } // Add adds delta to v. func (v *Float) Add(delta float64) { - v.mu.Lock() - defer v.mu.Unlock() - v.f += delta + for { + cur := atomic.LoadUint64(&v.f) + curVal := math.Float64frombits(cur) + nxtVal := curVal + delta + nxt := math.Float64bits(nxtVal) + if atomic.CompareAndSwapUint64(&v.f, cur, nxt) { + return + } + } } // Set sets v to value. func (v *Float) Set(value float64) { - v.mu.Lock() - defer v.mu.Unlock() - v.f = value + atomic.StoreUint64(&v.f, math.Float64bits(value)) } // Map is a string-to-Var map variable that satisfies the Var interface. diff --git a/libgo/go/expvar/expvar_test.go b/libgo/go/expvar/expvar_test.go index 765e3b757e9..8bc633e4a97 100644 --- a/libgo/go/expvar/expvar_test.go +++ b/libgo/go/expvar/expvar_test.go @@ -7,8 +7,13 @@ package expvar import ( "bytes" "encoding/json" + "math" + "net" "net/http/httptest" + "runtime" "strconv" + "sync" + "sync/atomic" "testing" ) @@ -47,6 +52,30 @@ func TestInt(t *testing.T) { } } +func BenchmarkIntAdd(b *testing.B) { + var v Int + + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + v.Add(1) + } + }) +} + +func BenchmarkIntSet(b *testing.B) { + var v Int + + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + v.Set(1) + } + }) +} + +func (v *Float) val() float64 { + return math.Float64frombits(atomic.LoadUint64(&v.f)) +} + func TestFloat(t *testing.T) { RemoveAll() reqs := NewFloat("requests-float") @@ -59,8 +88,8 @@ func TestFloat(t *testing.T) { reqs.Add(1.5) reqs.Add(1.25) - if reqs.f != 2.75 { - t.Errorf("reqs.f = %v, want 2.75", reqs.f) + if v := reqs.val(); v != 2.75 { + t.Errorf("reqs.val() = %v, want 2.75", v) } if s := reqs.String(); s != "2.75" { @@ -68,11 +97,31 @@ func TestFloat(t *testing.T) { } reqs.Add(-2) - if reqs.f != 0.75 { - t.Errorf("reqs.f = %v, want 0.75", reqs.f) + if v := reqs.val(); v != 0.75 { + t.Errorf("reqs.val() = %v, want 0.75", v) } } +func BenchmarkFloatAdd(b *testing.B) { + var f Float + + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + f.Add(1.0) + } + }) +} + +func BenchmarkFloatSet(b *testing.B) { + var f Float + + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + f.Set(1.0) + } + }) +} + func TestString(t *testing.T) { RemoveAll() name := NewString("my-name") @@ -90,6 +139,16 @@ func TestString(t *testing.T) { } } +func BenchmarkStringSet(b *testing.B) { + var s String + + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + s.Set("red") + } + }) +} + func TestMapCounter(t *testing.T) { RemoveAll() colors := NewMap("bike-shed-colors") @@ -104,8 +163,8 @@ func TestMapCounter(t *testing.T) { if x := colors.m["blue"].(*Int).i; x != 4 { t.Errorf("colors.m[\"blue\"] = %v, want 4", x) } - if x := colors.m[`green "midori"`].(*Float).f; x != 4.125 { - t.Errorf("colors.m[`green \"midori\"] = %v, want 3.14", x) + if x := colors.m[`green "midori"`].(*Float).val(); x != 4.125 { + t.Errorf("colors.m[`green \"midori\"] = %v, want 4.125", x) } // colors.String() should be '{"red":3, "blue":4}', @@ -130,6 +189,38 @@ func TestMapCounter(t *testing.T) { } } +func BenchmarkMapSet(b *testing.B) { + m := new(Map).Init() + + v := new(Int) + + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + m.Set("red", v) + } + }) +} + +func BenchmarkMapAddSame(b *testing.B) { + for i := 0; i < b.N; i++ { + m := new(Map).Init() + m.Add("red", 1) + m.Add("red", 1) + m.Add("red", 1) + m.Add("red", 1) + } +} + +func BenchmarkMapAddDifferent(b *testing.B) { + for i := 0; i < b.N; i++ { + m := new(Map).Init() + m.Add("red", 1) + m.Add("blue", 1) + m.Add("green", 1) + m.Add("yellow", 1) + } +} + func TestFunc(t *testing.T) { RemoveAll() var x interface{} = []string{"a", "b"} @@ -165,3 +256,135 @@ func TestHandler(t *testing.T) { t.Errorf("HTTP handler wrote:\n%s\nWant:\n%s", got, want) } } + +func BenchmarkRealworldExpvarUsage(b *testing.B) { + var ( + bytesSent Int + bytesRead Int + ) + + // The benchmark creates GOMAXPROCS client/server pairs. + // Each pair creates 4 goroutines: client reader/writer and server reader/writer. + // The benchmark stresses concurrent reading and writing to the same connection. + // Such pattern is used in net/http and net/rpc. + + b.StopTimer() + + P := runtime.GOMAXPROCS(0) + N := b.N / P + W := 1000 + + // Setup P client/server connections. + clients := make([]net.Conn, P) + servers := make([]net.Conn, P) + ln, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + b.Fatalf("Listen failed: %v", err) + } + defer ln.Close() + done := make(chan bool) + go func() { + for p := 0; p < P; p++ { + s, err := ln.Accept() + if err != nil { + b.Errorf("Accept failed: %v", err) + return + } + servers[p] = s + } + done <- true + }() + for p := 0; p < P; p++ { + c, err := net.Dial("tcp", ln.Addr().String()) + if err != nil { + b.Fatalf("Dial failed: %v", err) + } + clients[p] = c + } + <-done + + b.StartTimer() + + var wg sync.WaitGroup + wg.Add(4 * P) + for p := 0; p < P; p++ { + // Client writer. + go func(c net.Conn) { + defer wg.Done() + var buf [1]byte + for i := 0; i < N; i++ { + v := byte(i) + for w := 0; w < W; w++ { + v *= v + } + buf[0] = v + n, err := c.Write(buf[:]) + if err != nil { + b.Errorf("Write failed: %v", err) + return + } + + bytesSent.Add(int64(n)) + } + }(clients[p]) + + // Pipe between server reader and server writer. + pipe := make(chan byte, 128) + + // Server reader. + go func(s net.Conn) { + defer wg.Done() + var buf [1]byte + for i := 0; i < N; i++ { + n, err := s.Read(buf[:]) + + if err != nil { + b.Errorf("Read failed: %v", err) + return + } + + bytesRead.Add(int64(n)) + pipe <- buf[0] + } + }(servers[p]) + + // Server writer. + go func(s net.Conn) { + defer wg.Done() + var buf [1]byte + for i := 0; i < N; i++ { + v := <-pipe + for w := 0; w < W; w++ { + v *= v + } + buf[0] = v + n, err := s.Write(buf[:]) + if err != nil { + b.Errorf("Write failed: %v", err) + return + } + + bytesSent.Add(int64(n)) + } + s.Close() + }(servers[p]) + + // Client reader. + go func(c net.Conn) { + defer wg.Done() + var buf [1]byte + for i := 0; i < N; i++ { + n, err := c.Read(buf[:]) + + if err != nil { + b.Errorf("Read failed: %v", err) + return + } + + bytesRead.Add(int64(n)) + } + c.Close() + }(clients[p]) + } + wg.Wait() +} diff --git a/libgo/go/flag/flag.go b/libgo/go/flag/flag.go index 60aef5d806c..3abc80e9c67 100644 --- a/libgo/go/flag/flag.go +++ b/libgo/go/flag/flag.go @@ -31,7 +31,7 @@ fmt.Println("ip has value ", *ip) fmt.Println("flagvar has value ", flagvar) - After parsing, the arguments after the flag are available as the + After parsing, the arguments following the flags are available as the slice flag.Args() or individually as flag.Arg(i). The arguments are indexed from 0 through flag.NArg()-1. @@ -235,6 +235,8 @@ func (d *durationValue) String() string { return (*time.Duration)(d).String() } // If a Value has an IsBoolFlag() bool method returning true, // the command-line parser makes -name equivalent to -name=true // rather than using the next command-line argument. +// +// Set is called once, in command line order, for each flag present. type Value interface { String() string Set(string) error @@ -249,13 +251,14 @@ type Getter interface { Get() interface{} } -// ErrorHandling defines how to handle flag parsing errors. +// ErrorHandling defines how FlagSet.Parse behaves if the parse fails. type ErrorHandling int +// These constants cause FlagSet.Parse to behave as described if the parse fails. const ( - ContinueOnError ErrorHandling = iota - ExitOnError - PanicOnError + ContinueOnError ErrorHandling = iota // Return a descriptive error. + ExitOnError // Call os.Exit(2). + PanicOnError // Call panic with a descriptive error. ) // A FlagSet represents a set of defined flags. The zero value of a FlagSet @@ -373,20 +376,110 @@ func Set(name, value string) error { return CommandLine.Set(name, value) } -// PrintDefaults prints, to standard error unless configured -// otherwise, the default values of all defined flags in the set. +// isZeroValue guesses whether the string represents the zero +// value for a flag. It is not accurate but in practice works OK. +func isZeroValue(value string) bool { + switch value { + case "false": + return true + case "": + return true + case "0": + return true + } + return false +} + +// UnquoteUsage extracts a back-quoted name from the usage +// string for a flag and returns it and the un-quoted usage. +// Given "a `name` to show" it returns ("name", "a name to show"). +// If there are no back quotes, the name is an educated guess of the +// type of the flag's value, or the empty string if the flag is boolean. +func UnquoteUsage(flag *Flag) (name string, usage string) { + // Look for a back-quoted name, but avoid the strings package. + usage = flag.Usage + for i := 0; i < len(usage); i++ { + if usage[i] == '`' { + for j := i + 1; j < len(usage); j++ { + if usage[j] == '`' { + name = usage[i+1 : j] + usage = usage[:i] + name + usage[j+1:] + return name, usage + } + } + break // Only one back quote; use type name. + } + } + // No explicit name, so use type if we can find one. + name = "value" + switch flag.Value.(type) { + case boolFlag: + name = "" + case *durationValue: + name = "duration" + case *float64Value: + name = "float" + case *intValue, *int64Value: + name = "int" + case *stringValue: + name = "string" + case *uintValue, *uint64Value: + name = "uint" + } + return +} + +// PrintDefaults prints to standard error the default values of all +// defined command-line flags in the set. See the documentation for +// the global function PrintDefaults for more information. func (f *FlagSet) PrintDefaults() { f.VisitAll(func(flag *Flag) { - format := " -%s=%s: %s\n" - if _, ok := flag.Value.(*stringValue); ok { - // put quotes on the value - format = " -%s=%q: %s\n" + s := fmt.Sprintf(" -%s", flag.Name) // Two spaces before -; see next two comments. + name, usage := UnquoteUsage(flag) + if len(name) > 0 { + s += " " + name + } + // Boolean flags of one ASCII letter are so common we + // treat them specially, putting their usage on the same line. + if len(s) <= 4 { // space, space, '-', 'x'. + s += "\t" + } else { + // Four spaces before the tab triggers good alignment + // for both 4- and 8-space tab stops. + s += "\n \t" } - fmt.Fprintf(f.out(), format, flag.Name, flag.DefValue, flag.Usage) + s += usage + if !isZeroValue(flag.DefValue) { + if _, ok := flag.Value.(*stringValue); ok { + // put quotes on the value + s += fmt.Sprintf(" (default %q)", flag.DefValue) + } else { + s += fmt.Sprintf(" (default %v)", flag.DefValue) + } + } + fmt.Fprint(f.out(), s, "\n") }) } -// PrintDefaults prints to standard error the default values of all defined command-line flags. +// PrintDefaults prints, to standard error unless configured otherwise, +// a usage message showing the default settings of all defined +// command-line flags. +// For an integer valued flag x, the default output has the form +// -x int +// usage-message-for-x (default 7) +// The usage message will appear on a separate line for anything but +// a bool flag with a one-byte name. For bool flags, the type is +// omitted and if the flag name is one byte the usage message appears +// on the same line. The parenthetical default is omitted if the +// default is the zero value for the type. The listed type, here int, +// can be changed by placing a back-quoted name in the flag's usage +// string; the first such item in the message is taken to be a parameter +// name to show in the message and the back quotes are stripped from +// the message when displayed. For instance, given +// flag.String("I", "", "search `directory` for include files") +// the output will be +// -I directory +// search directory for include files. func PrintDefaults() { CommandLine.PrintDefaults() } @@ -408,6 +501,8 @@ func defaultUsage(f *FlagSet) { // Usage prints to standard error a usage message documenting all defined command-line flags. // It is called when an error occurs while parsing flags. // The function is a variable that may be changed to point to a custom function. +// By default it prints a simple header and calls PrintDefaults; for details about the +// format of the output and how to control it, see the documentation for PrintDefaults. var Usage = func() { fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0]) PrintDefaults() @@ -420,7 +515,8 @@ func (f *FlagSet) NFlag() int { return len(f.actual) } func NFlag() int { return len(CommandLine.actual) } // Arg returns the i'th argument. Arg(0) is the first remaining argument -// after flags have been processed. +// after flags have been processed. Arg returns an empty string if the +// requested element does not exist. func (f *FlagSet) Arg(i int) string { if i < 0 || i >= len(f.args) { return "" @@ -429,7 +525,8 @@ func (f *FlagSet) Arg(i int) string { } // Arg returns the i'th command-line argument. Arg(0) is the first remaining argument -// after flags have been processed. +// after flags have been processed. Arg returns an empty string if the +// requested element does not exist. func Arg(i int) string { return CommandLine.Arg(i) } @@ -726,27 +823,27 @@ func (f *FlagSet) parseOne() (bool, error) { if len(s) == 0 || s[0] != '-' || len(s) == 1 { return false, nil } - num_minuses := 1 + numMinuses := 1 if s[1] == '-' { - num_minuses++ + numMinuses++ if len(s) == 2 { // "--" terminates the flags f.args = f.args[1:] return false, nil } } - name := s[num_minuses:] + name := s[numMinuses:] if len(name) == 0 || name[0] == '-' || name[0] == '=' { return false, f.failf("bad flag syntax: %s", s) } // it's a flag. does it have an argument? f.args = f.args[1:] - has_value := false + hasValue := false value := "" for i := 1; i < len(name); i++ { // equals cannot be first if name[i] == '=' { value = name[i+1:] - has_value = true + hasValue = true name = name[0:i] break } @@ -762,21 +859,23 @@ func (f *FlagSet) parseOne() (bool, error) { } if fv, ok := flag.Value.(boolFlag); ok && fv.IsBoolFlag() { // special case: doesn't need an arg - if has_value { + if hasValue { if err := fv.Set(value); err != nil { return false, f.failf("invalid boolean value %q for -%s: %v", value, name, err) } } else { - fv.Set("true") + if err := fv.Set("true"); err != nil { + return false, f.failf("invalid boolean flag %s: %v", name, err) + } } } else { // It must have a value, which might be the next argument. - if !has_value && len(f.args) > 0 { + if !hasValue && len(f.args) > 0 { // value is the next arg - has_value = true + hasValue = true value, f.args = f.args[0], f.args[1:] } - if !has_value { + if !hasValue { return false, f.failf("flag needs an argument: -%s", name) } if err := flag.Value.Set(value); err != nil { @@ -829,7 +928,7 @@ func Parse() { CommandLine.Parse(os.Args[1:]) } -// Parsed returns true if the command-line flags have been parsed. +// Parsed reports whether the command-line flags have been parsed. func Parsed() bool { return CommandLine.Parsed() } diff --git a/libgo/go/flag/flag_test.go b/libgo/go/flag/flag_test.go index 8c88c8c2744..e2319ec94c8 100644 --- a/libgo/go/flag/flag_test.go +++ b/libgo/go/flag/flag_test.go @@ -377,3 +377,41 @@ func TestHelp(t *testing.T) { t.Fatal("help was called; should not have been for defined help flag") } } + +const defaultOutput = ` -A for bootstrapping, allow 'any' type + -Alongflagname + disable bounds checking + -C a boolean defaulting to true (default true) + -D path + set relative path for local imports + -F number + a non-zero number (default 2.7) + -G float + a float that defaults to zero + -N int + a non-zero int (default 27) + -Z int + an int that defaults to zero + -maxT timeout + set timeout for dial +` + +func TestPrintDefaults(t *testing.T) { + fs := NewFlagSet("print defaults test", ContinueOnError) + var buf bytes.Buffer + fs.SetOutput(&buf) + fs.Bool("A", false, "for bootstrapping, allow 'any' type") + fs.Bool("Alongflagname", false, "disable bounds checking") + fs.Bool("C", true, "a boolean defaulting to true") + fs.String("D", "", "set relative `path` for local imports") + fs.Float64("F", 2.7, "a non-zero `number`") + fs.Float64("G", 0, "a float that defaults to zero") + fs.Int("N", 27, "a non-zero int") + fs.Int("Z", 0, "an int that defaults to zero") + fs.Duration("maxT", 0, "set `timeout` for dial") + fs.PrintDefaults() + got := buf.String() + if got != defaultOutput { + t.Errorf("got %q want %q\n", got, defaultOutput) + } +} diff --git a/libgo/go/fmt/doc.go b/libgo/go/fmt/doc.go index ee54463e275..ef91368ef08 100644 --- a/libgo/go/fmt/doc.go +++ b/libgo/go/fmt/doc.go @@ -40,7 +40,7 @@ %F synonym for %f %g %e for large exponents, %f otherwise %G %E for large exponents, %F otherwise - String and slice of bytes: + String and slice of bytes (treated equivalently with these verbs): %s the uninterpreted bytes of the string or slice %q a double-quoted string safely escaped with Go syntax %x base 16, lower-case, two characters per byte @@ -66,13 +66,13 @@ maps: map[key1:value1 key2:value2] pointer to above: &{}, &[], &map[] - Width is specified by an optional decimal number immediately following the verb. + Width is specified by an optional decimal number immediately preceding the verb. If absent, the width is whatever is necessary to represent the value. Precision is specified after the (optional) width by a period followed by a decimal number. If no period is present, a default precision is used. A period with no following number specifies a precision of zero. Examples: - %f: default width, default precision + %f default width, default precision %9f width 9, default precision %.2f default width, precision 2 %9.2f width 9, precision 2 @@ -138,20 +138,23 @@ formatting considerations apply for operands that implement certain interfaces. In order of application: - 1. If an operand implements the Formatter interface, it will + 1. If the operand is a reflect.Value, the concrete value it + holds is printed as if it was the operand. + + 2. If an operand implements the Formatter interface, it will be invoked. Formatter provides fine control of formatting. - 2. If the %v verb is used with the # flag (%#v) and the operand + 3. If the %v verb is used with the # flag (%#v) and the operand implements the GoStringer interface, that will be invoked. If the format (which is implicitly %v for Println etc.) is valid for a string (%s %q %v %x %X), the following two rules apply: - 3. If an operand implements the error interface, the Error method + 4. If an operand implements the error interface, the Error method will be invoked to convert the object to a string, which will then be formatted as required by the verb (if any). - 4. If an operand implements method String() string, that method + 5. If an operand implements method String() string, that method will be invoked to convert the object to a string, which will then be formatted as required by the verb (if any). @@ -161,6 +164,9 @@ of strings, and %6.2f will control formatting for each element of a floating-point array. + However, when printing a byte slice with a string-like verb + (%s %q %x %X), it is treated identically to a string, as a single item. + To avoid recursion in cases such as type X string func (x X) String() string { return Sprintf("<%s>", x) } @@ -178,8 +184,8 @@ However, the notation [n] immediately before the verb indicates that the nth one-indexed argument is to be formatted instead. The same notation before a '*' for a width or precision selects the argument index holding - the value. After processing a bracketed expression [n], arguments n+1, - n+2, etc. will be processed unless otherwise directed. + the value. After processing a bracketed expression [n], subsequent verbs + will use arguments n+1, n+2, etc. unless otherwise directed. For example, fmt.Sprintf("%[2]d %[1]d\n", 11, 22) @@ -225,18 +231,33 @@ %!s(PANIC=bad) The %!s just shows the print verb in use when the failure - occurred. + occurred. If the panic is caused by a nil receiver to an Error + or String method, however, the output is the undecorated + string, "". Scanning An analogous set of functions scans formatted text to yield values. Scan, Scanf and Scanln read from os.Stdin; Fscan, Fscanf and Fscanln read from a specified io.Reader; Sscan, - Sscanf and Sscanln read from an argument string. Scanln, - Fscanln and Sscanln stop scanning at a newline and require that - the items be followed by one; Scanf, Fscanf and Sscanf require - newlines in the input to match newlines in the format; the other - routines treat newlines as spaces. + Sscanf and Sscanln read from an argument string. + + Scan, Fscan, Sscan treat newlines in the input as spaces. + + Scanln, Fscanln and Sscanln stop scanning at a newline and + require that the items be followed by a newline or EOF. + + Scanf, Fscanf and Sscanf require that (after skipping spaces) + newlines in the format are matched by newlines in the input + and vice versa. This behavior differs from the corresponding + routines in C, which uniformly treat newlines as spaces. + + When scanning with Scanf, Fscanf, and Sscanf, all non-empty + runs of space characters (except newline) are equivalent + to a single space in both the format and the input. With + that proviso, text in the format string must match the input + text; scanning stops if it does not, with the return value + of the function indicating the number of arguments scanned. Scanf, Fscanf, and Sscanf parse the arguments according to a format string, analogous to that of Printf. For example, %x @@ -253,20 +274,18 @@ Flags # and + are not implemented. The familiar base-setting prefixes 0 (octal) and 0x - (hexadecimal) are accepted when scanning integers without a - format or with the %v verb. - - Width is interpreted in the input text (%5s means at most - five runes of input will be read to scan a string) but there - is no syntax for scanning with a precision (no %5.2f, just - %5f). - - When scanning with a format, all non-empty runs of space - characters (except newline) are equivalent to a single - space in both the format and the input. With that proviso, - text in the format string must match the input text; scanning - stops if it does not, with the return value of the function - indicating the number of arguments scanned. + (hexadecimal) are accepted when scanning integers without + a format or with the %v verb. + + Width is interpreted in the input text but there is no + syntax for scanning with a precision (no %5.2f, just %5f). + If width is provided, it applies after leading spaces are + trimmed and specifies the maximum number of runes to read + to satisfy the verb. For example, + Sscanf(" 1234567 ", "%5s%d", &s, &i) + will set s to "12345" and i to 67 while + Sscanf(" 12 34 567 ", "%5s%d", &s, &i) + will set s to "12" and i to 34. In all the scanning functions, a carriage return followed immediately by a newline is treated as a plain newline diff --git a/libgo/go/fmt/fmt_test.go b/libgo/go/fmt/fmt_test.go index ccd80904771..8f3587b5505 100644 --- a/libgo/go/fmt/fmt_test.go +++ b/libgo/go/fmt/fmt_test.go @@ -9,6 +9,7 @@ import ( . "fmt" "io" "math" + "reflect" "runtime" "strings" "testing" @@ -135,27 +136,33 @@ var fmtTests = []struct { // basic string {"%s", "abc", "abc"}, + {"%q", "abc", `"abc"`}, {"%x", "abc", "616263"}, + {"%x", "\xff\xf0\x0f\xff", "fff00fff"}, + {"%X", "\xff\xf0\x0f\xff", "FFF00FFF"}, {"%x", "xyz", "78797a"}, {"%X", "xyz", "78797A"}, - {"%q", "abc", `"abc"`}, - {"%#x", []byte("abc\xff"), "0x616263ff"}, - {"%#X", []byte("abc\xff"), "0X616263FF"}, - {"%# x", []byte("abc\xff"), "0x61 0x62 0x63 0xff"}, - {"%# X", []byte("abc\xff"), "0X61 0X62 0X63 0XFF"}, + {"% x", "xyz", "78 79 7a"}, + {"% X", "xyz", "78 79 7A"}, + {"%#x", "xyz", "0x78797a"}, + {"%#X", "xyz", "0X78797A"}, + {"%# x", "xyz", "0x78 0x79 0x7a"}, + {"%# X", "xyz", "0X78 0X79 0X7A"}, // basic bytes {"%s", []byte("abc"), "abc"}, + {"%q", []byte("abc"), `"abc"`}, {"%x", []byte("abc"), "616263"}, - {"% x", []byte("abc\xff"), "61 62 63 ff"}, - {"%#x", []byte("abc\xff"), "0x616263ff"}, - {"%#X", []byte("abc\xff"), "0X616263FF"}, - {"%# x", []byte("abc\xff"), "0x61 0x62 0x63 0xff"}, - {"%# X", []byte("abc\xff"), "0X61 0X62 0X63 0XFF"}, - {"% X", []byte("abc\xff"), "61 62 63 FF"}, + {"%x", []byte("\xff\xf0\x0f\xff"), "fff00fff"}, + {"%X", []byte("\xff\xf0\x0f\xff"), "FFF00FFF"}, {"%x", []byte("xyz"), "78797a"}, {"%X", []byte("xyz"), "78797A"}, - {"%q", []byte("abc"), `"abc"`}, + {"% x", []byte("xyz"), "78 79 7a"}, + {"% X", []byte("xyz"), "78 79 7A"}, + {"%#x", []byte("xyz"), "0x78797a"}, + {"%#X", []byte("xyz"), "0X78797A"}, + {"%# x", []byte("xyz"), "0x78 0x79 0x7a"}, + {"%# X", []byte("xyz"), "0X78 0X79 0X7A"}, // escaped strings {"%#q", `abc`, "`abc`"}, @@ -388,6 +395,8 @@ var fmtTests = []struct { {"%v", &slice, "&[1 2 3 4 5]"}, {"%v", &islice, "&[1 hello 2.5 ]"}, {"%v", &bslice, "&[1 2 3 4 5]"}, + {"%v", []byte{1}, "[1]"}, + {"%v", []byte{}, "[]"}, // complexes with %v {"%v", 1 + 2i, "(1+2i)"}, @@ -441,6 +450,32 @@ var fmtTests = []struct { {"%d", []int{1, 2, 15}, `[1 2 15]`}, {"%d", []byte{1, 2, 15}, `[1 2 15]`}, {"%q", []string{"a", "b"}, `["a" "b"]`}, + {"% 02x", []byte{1}, "01"}, + {"% 02x", []byte{1, 2, 3}, "01 02 03"}, + // Padding with byte slices. + {"%x", []byte{}, ""}, + {"%02x", []byte{}, "00"}, + {"% 02x", []byte{}, "00"}, + {"%08x", []byte{0xab}, "000000ab"}, + {"% 08x", []byte{0xab}, "000000ab"}, + {"%08x", []byte{0xab, 0xcd}, "0000abcd"}, + {"% 08x", []byte{0xab, 0xcd}, "000ab cd"}, + {"%8x", []byte{0xab}, " ab"}, + {"% 8x", []byte{0xab}, " ab"}, + {"%8x", []byte{0xab, 0xcd}, " abcd"}, + {"% 8x", []byte{0xab, 0xcd}, " ab cd"}, + // Same for strings + {"%x", "", ""}, + {"%02x", "", "00"}, + {"% 02x", "", "00"}, + {"%08x", "\xab", "000000ab"}, + {"% 08x", "\xab", "000000ab"}, + {"%08x", "\xab\xcd", "0000abcd"}, + {"% 08x", "\xab\xcd", "000ab cd"}, + {"%8x", "\xab", " ab"}, + {"% 8x", "\xab", " ab"}, + {"%8x", "\xab\xcd", " abcd"}, + {"% 8x", "\xab\xcd", " ab cd"}, // renamings {"%v", renamedBool(true), "true"}, @@ -522,6 +557,8 @@ var fmtTests = []struct { {"%s", nil, "%!s()"}, {"%T", nil, ""}, {"%-1", 100, "%!(NOVERB)%!(EXTRA int=100)"}, + {"%017091901790959340919092959340919017929593813360", 0, "%!(NOVERB)%!(EXTRA int=0)"}, + {"%184467440737095516170v", 0, "%!(NOVERB)%!(EXTRA int=0)"}, // The "" show up because maps are printed by // first obtaining a list of keys and then looking up @@ -540,6 +577,15 @@ var fmtTests = []struct { {"%0.100f", 1.0, zeroFill("1.", 100, "")}, {"%0.100f", -1.0, zeroFill("-1.", 100, "")}, + // Used to panic: integer function didn't look at f.prec, f.unicode, f.width or sign. + {"%#.80x", 42, "0x0000000000000000000000000000000000000000000000000000000000000000000000000000002a"}, + {"%.80U", 42, "U+0000000000000000000000000000000000000000000000000000000000000000000000000000002A"}, + {"%#.80U", '日', "U+000000000000000000000000000000000000000000000000000000000000000000000000000065E5 '日'"}, + {"%.65d", -44, "-00000000000000000000000000000000000000000000000000000000000000044"}, + {"%+.65d", 44, "+00000000000000000000000000000000000000000000000000000000000000044"}, + {"% .65d", 44, " 00000000000000000000000000000000000000000000000000000000000000044"}, + {"% +.65d", 44, "+00000000000000000000000000000000000000000000000000000000000000044"}, + // Comparison of padding rules with C printf. /* C program: @@ -665,6 +711,20 @@ var fmtTests = []struct { {"%x", byteFormatterSlice, "61626364"}, // This next case seems wrong, but the docs say the Formatter wins here. {"%#v", byteFormatterSlice, "[]fmt_test.byteFormatter{X, X, X, X}"}, + + // reflect.Value handled specially in Go 1.5, making it possible to + // see inside non-exported fields (which cannot be accessed with Interface()). + // Issue 8965. + {"%v", reflect.ValueOf(A{}).Field(0).String(), ""}, // Equivalent to the old way. + {"%v", reflect.ValueOf(A{}).Field(0), "0"}, // Sees inside the field. + + // verbs apply to the extracted value too. + {"%s", reflect.ValueOf("hello"), "hello"}, + {"%q", reflect.ValueOf("hello"), `"hello"`}, + {"%#04x", reflect.ValueOf(256), "0x0100"}, + + // invalid reflect.Value doesn't crash. + {"%v", reflect.Value{}, ""}, } // zeroFill generates zero-filled strings of the specified width. The length @@ -791,6 +851,11 @@ var reorderTests = []struct { {"%d %d %d %#[1]o %#o %#o %#o", SE{11, 12, 13}, "11 12 13 013 014 015 %!o(MISSING)"}, {"%[5]d %[2]d %d", SE{1, 2, 3}, "%!d(BADINDEX) 2 3"}, {"%d %[3]d %d", SE{1, 2}, "1 %!d(BADINDEX) 2"}, // Erroneous index does not affect sequence. + {"%.[]", SE{}, "%!](BADINDEX)"}, // Issue 10675 + {"%.-3d", SE{42}, "%!-(int=42)3d"}, // TODO: Should this set return better error messages? + {"%2147483648d", SE{42}, "%!(NOVERB)%!(EXTRA int=42)"}, + {"%-2147483648d", SE{42}, "%!(NOVERB)%!(EXTRA int=42)"}, + {"%.2147483648d", SE{42}, "%!(NOVERB)%!(EXTRA int=42)"}, } func TestReorder(t *testing.T) { @@ -869,6 +934,15 @@ func BenchmarkFprintInt(b *testing.B) { } } +func BenchmarkFprintfBytes(b *testing.B) { + data := []byte(string("0123456789")) + var buf bytes.Buffer + for i := 0; i < b.N; i++ { + buf.Reset() + Fprintf(&buf, "%s", data) + } +} + func BenchmarkFprintIntNoAlloc(b *testing.B) { var x interface{} = 123456 var buf bytes.Buffer @@ -905,11 +979,13 @@ var mallocTest = []struct { var _ bytes.Buffer func TestCountMallocs(t *testing.T) { - if testing.Short() { + switch { + case testing.Short(): t.Skip("skipping malloc count in short mode") - } - if runtime.GOMAXPROCS(0) > 1 { + case runtime.GOMAXPROCS(0) > 1: t.Skip("skipping; GOMAXPROCS>1") + case raceenabled: + t.Skip("skipping malloc count under race detector") } for _, mt := range mallocTest { mallocs := testing.AllocsPerRun(100, mt.fn) @@ -1108,14 +1184,20 @@ var startests = []struct { out string }{ {"%*d", args(4, 42), " 42"}, + {"%-*d", args(4, 42), "42 "}, + {"%*d", args(-4, 42), "42 "}, + {"%-*d", args(-4, 42), "42 "}, {"%.*d", args(4, 42), "0042"}, {"%*.*d", args(8, 4, 42), " 0042"}, {"%0*d", args(4, 42), "0042"}, - {"%-*d", args(4, 42), "42 "}, // erroneous {"%*d", args(nil, 42), "%!(BADWIDTH)42"}, + {"%*d", args(int(1e7), 42), "%!(BADWIDTH)42"}, + {"%*d", args(int(-1e7), 42), "%!(BADWIDTH)42"}, {"%.*d", args(nil, 42), "%!(BADPREC)42"}, + {"%.*d", args(-1, 42), "%!(BADPREC)42"}, + {"%.*d", args(int(1e7), 42), "%!(BADPREC)42"}, {"%*d", args(5, "foo"), "%!d(string= foo)"}, {"%*% %d", args(20, 5), "% 5"}, {"%*", args(4), "%!(NOVERB)"}, @@ -1233,7 +1315,7 @@ func TestNilDoesNotBecomeTyped(t *testing.T) { type B struct{} var a *A = nil var b B = B{} - got := Sprintf("%s %s %s %s %s", nil, a, nil, b, nil) + got := Sprintf("%s %s %s %s %s", nil, a, nil, b, nil) // go vet should complain about this line. const expect = "%!s() %!s(*fmt_test.A=) %!s() {} %!s()" if got != expect { t.Errorf("expected:\n\t%q\ngot:\n\t%q", expect, got) diff --git a/libgo/go/fmt/format.go b/libgo/go/fmt/format.go index 4d97d1443ed..517b18f7d43 100644 --- a/libgo/go/fmt/format.go +++ b/libgo/go/fmt/format.go @@ -162,24 +162,35 @@ func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) { return } + negative := signedness == signed && a < 0 + if negative { + a = -a + } + var buf []byte = f.intbuf[0:] - if f.widPresent { - width := f.wid + if f.widPresent || f.precPresent || f.plus || f.space { + width := f.wid + f.prec // Only one will be set, both are positive; this provides the maximum. if base == 16 && f.sharp { // Also adds "0x". width += 2 } + if f.unicode { + // Also adds "U+". + width += 2 + if f.uniQuote { + // Also adds " 'x'". + width += 1 + 1 + utf8.UTFMax + 1 + } + } + if negative || f.plus || f.space { + width++ + } if width > nByte { // We're going to need a bigger boat. buf = make([]byte, width) } } - negative := signedness == signed && a < 0 - if negative { - a = -a - } - // two ways to ask for extra leading zero digits: %.3d or %03d. // apparently the first cancels the second. prec := 0 diff --git a/libgo/go/fmt/norace_test.go b/libgo/go/fmt/norace_test.go new file mode 100644 index 00000000000..1267cc34ee3 --- /dev/null +++ b/libgo/go/fmt/norace_test.go @@ -0,0 +1,9 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !race + +package fmt_test + +const raceenabled = false diff --git a/libgo/go/fmt/print.go b/libgo/go/fmt/print.go index 59a30d221e9..8d3e97c3ab1 100644 --- a/libgo/go/fmt/print.go +++ b/libgo/go/fmt/print.go @@ -285,12 +285,22 @@ func getField(v reflect.Value, i int) reflect.Value { return val } +// tooLarge reports whether the magnitude of the integer is +// too large to be used as a formatting width or precision. +func tooLarge(x int) bool { + const max int = 1e6 + return x > max || x < -max +} + // parsenum converts ASCII to integer. num is 0 (and isnum is false) if no number present. func parsenum(s string, start, end int) (num int, isnum bool, newi int) { if start >= end { return 0, false, end } for newi = start; newi < end && '0' <= s[newi] && s[newi] <= '9'; newi++ { + if tooLarge(num) { + return 0, false, end // Overflow; crazy long number most likely. + } num = num*10 + int(s[newi]-'0') isnum = true } @@ -789,6 +799,8 @@ func (p *pp) printArg(arg interface{}, verb rune, depth int) (wasString bool) { case []byte: p.fmtBytes(f, verb, nil, depth) wasString = verb == 's' + case reflect.Value: + return p.printReflectValue(f, verb, depth) default: // If the type is not simple, it might have methods. if handled := p.handleMethods(verb, depth); handled { @@ -845,6 +857,8 @@ func (p *pp) printReflectValue(value reflect.Value, verb rune, depth int) (wasSt p.value = value BigSwitch: switch f := value; f.Kind() { + case reflect.Invalid: + p.buf.WriteString("") case reflect.Bool: p.fmtBool(f.Bool(), verb) case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: @@ -1016,6 +1030,10 @@ func intFromArg(a []interface{}, argNum int) (num int, isInt bool, newArgNum int if argNum < len(a) { num, isInt = a[argNum].(int) newArgNum = argNum + 1 + if tooLarge(num) { + num = 0 + isInt = false + } } return } @@ -1027,6 +1045,11 @@ func intFromArg(a []interface{}, argNum int) (num int, isInt bool, newArgNum int // up to the closing paren, if present, and whether the number parsed // ok. The bytes to consume will be 1 if no closing paren is present. func parseArgNumber(format string) (index int, wid int, ok bool) { + // There must be at least 3 bytes: [n]. + if len(format) < 3 { + return 0, 1, false + } + // Find closing bracket. for i := 1; i < len(format); i++ { if format[i] == ']' { @@ -1053,7 +1076,7 @@ func (p *pp) argNumber(argNum int, format string, i int, numArgs int) (newArgNum return index, i + wid, true } p.goodArgNum = false - return argNum, i + wid, true + return argNum, i + wid, ok } func (p *pp) doPrintf(format string, a []interface{}) { @@ -1105,9 +1128,17 @@ func (p *pp) doPrintf(format string, a []interface{}) { if i < end && format[i] == '*' { i++ p.fmt.wid, p.fmt.widPresent, argNum = intFromArg(a, argNum) + if !p.fmt.widPresent { p.buf.Write(badWidthBytes) } + + // We have a negative width, so take its value and ensure + // that the minus flag is set + if p.fmt.wid < 0 { + p.fmt.wid = -p.fmt.wid + p.fmt.minus = true + } afterIndex = false } else { p.fmt.wid, p.fmt.widPresent, i = parsenum(format, i, end) @@ -1123,9 +1154,14 @@ func (p *pp) doPrintf(format string, a []interface{}) { p.goodArgNum = false } argNum, i, afterIndex = p.argNumber(argNum, format, i, len(a)) - if format[i] == '*' { + if i < end && format[i] == '*' { i++ p.fmt.prec, p.fmt.precPresent, argNum = intFromArg(a, argNum) + // Negative precision arguments don't make sense + if p.fmt.prec < 0 { + p.fmt.prec = 0 + p.fmt.precPresent = false + } if !p.fmt.precPresent { p.buf.Write(badPrecBytes) } diff --git a/libgo/go/fmt/race_test.go b/libgo/go/fmt/race_test.go new file mode 100644 index 00000000000..ae3147a5b00 --- /dev/null +++ b/libgo/go/fmt/race_test.go @@ -0,0 +1,9 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build race + +package fmt_test + +const raceenabled = true diff --git a/libgo/go/fmt/scan.go b/libgo/go/fmt/scan.go index d7befeae43e..5b9b516353b 100644 --- a/libgo/go/fmt/scan.go +++ b/libgo/go/fmt/scan.go @@ -34,16 +34,16 @@ type ScanState interface { ReadRune() (r rune, size int, err error) // UnreadRune causes the next call to ReadRune to return the same rune. UnreadRune() error - // SkipSpace skips space in the input. Newlines are treated as space - // unless the scan operation is Scanln, Fscanln or Sscanln, in which case - // a newline is treated as EOF. + // SkipSpace skips space in the input. Newlines are treated appropriately + // for the operation being performed; see the package documentation + // for more information. SkipSpace() // Token skips space in the input if skipSpace is true, then returns the // run of Unicode code points c satisfying f(c). If f is nil, // !unicode.IsSpace(c) is used; that is, the token will hold non-space - // characters. Newlines are treated as space unless the scan operation - // is Scanln, Fscanln or Sscanln, in which case a newline is treated as - // EOF. The returned slice points to shared data that may be overwritten + // characters. Newlines are treated appropriately for the operation being + // performed; see the package documentation for more information. + // The returned slice points to shared data that may be overwritten // by the next call to Token, a call to a Scan function using the ScanState // as input, or when the calling Scan method returns. Token(skipSpace bool, f func(rune) bool) (token []byte, err error) @@ -81,6 +81,8 @@ func Scanln(a ...interface{}) (n int, err error) { // Scanf scans text read from standard input, storing successive // space-separated values into successive arguments as determined by // the format. It returns the number of items successfully scanned. +// If that is less than the number of arguments, err will report why. +// Newlines in the input must match newlines in the format. func Scanf(format string, a ...interface{}) (n int, err error) { return Fscanf(os.Stdin, format, a...) } @@ -113,6 +115,7 @@ func Sscanln(str string, a ...interface{}) (n int, err error) { // 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. +// Newlines in the input must match newlines in the format. func Sscanf(str string, format string, a ...interface{}) (n int, err error) { return Fscanf((*stringReader)(&str), format, a...) } @@ -140,6 +143,7 @@ func Fscanln(r io.Reader, a ...interface{}) (n int, err error) { // Fscanf scans text read from r, storing successive space-separated // values into successive arguments as determined by the format. It // returns the number of items successfully parsed. +// Newlines in the input must match newlines in the format. func Fscanf(r io.Reader, format string, a ...interface{}) (n int, err error) { s, old := newScanState(r, false, false) n, err = s.doScanf(format, a) @@ -387,17 +391,6 @@ var ssFree = sync.Pool{ // newScanState allocates a new ss struct or grab a cached one. func newScanState(r io.Reader, nlIsSpace, nlIsEnd bool) (s *ss, old ssave) { - // If the reader is a *ss, then we've got a recursive - // call to Scan, so re-use the scan state. - s, ok := r.(*ss) - if ok { - old = s.ssave - s.limit = s.argLimit - s.nlIsEnd = nlIsEnd || s.nlIsEnd - s.nlIsSpace = nlIsSpace - return - } - s = ssFree.Get().(*ss) if rr, ok := r.(io.RuneReader); ok { s.rr = rr @@ -875,34 +868,39 @@ func (s *ss) quotedString() string { return "" } -// hexDigit returns the value of the hexadecimal digit -func (s *ss) hexDigit(d rune) int { +// hexDigit returns the value of the hexadecimal digit. +func hexDigit(d rune) (int, bool) { digit := int(d) switch digit { case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': - return digit - '0' + return digit - '0', true case 'a', 'b', 'c', 'd', 'e', 'f': - return 10 + digit - 'a' + return 10 + digit - 'a', true case 'A', 'B', 'C', 'D', 'E', 'F': - return 10 + digit - 'A' + return 10 + digit - 'A', true } - s.errorString("illegal hex digit") - return 0 + return -1, false } // hexByte returns the next hex-encoded (two-character) byte from the input. -// There must be either two hexadecimal digits or a space character in the input. +// It returns ok==false if the next bytes in the input do not encode a hex byte. +// If the first byte is hex and the second is not, processing stops. func (s *ss) hexByte() (b byte, ok bool) { rune1 := s.getRune() if rune1 == eof { return } - if isSpace(rune1) { + value1, ok := hexDigit(rune1) + if !ok { s.UnreadRune() return } - rune2 := s.mustReadRune() - return byte(s.hexDigit(rune1)<<4 | s.hexDigit(rune2)), true + value2, ok := hexDigit(s.mustReadRune()) + if !ok { + s.errorString("illegal hex digit") + return + } + return byte(value1<<4 | value2), true } // hexString returns the space-delimited hexpair-encoded string. @@ -1050,8 +1048,8 @@ func (s *ss) doScan(a []interface{}) (numProcessed int, err error) { s.scanOne('v', arg) numProcessed++ } - // Check for newline if required. - if !s.nlIsSpace { + // Check for newline (or EOF) if required (Scanln etc.). + if s.nlIsEnd { for { r := s.getRune() if r == '\n' || r == eof { @@ -1067,12 +1065,13 @@ func (s *ss) doScan(a []interface{}) (numProcessed int, err error) { } // advance determines whether the next characters in the input match -// those of the format. It returns the number of bytes (sic) consumed -// in the format. Newlines included, all runs of space characters in -// either input or format behave as a single space. This routine also -// handles the %% case. If the return value is zero, either format -// starts with a % (with no following %) or the input is empty. -// If it is negative, the input did not match the string. +// those of the format. It returns the number of bytes (sic) consumed +// in the format. All runs of space characters in either input or +// format behave as a single space. Newlines are special, though: +// newlines in the format must match those in the input and vice versa. +// This routine also handles the %% case. If the return value is zero, +// either format starts with a % (with no following %) or the input +// is empty. If it is negative, the input did not match the string. func (s *ss) advance(format string) (i int) { for i < len(format) { fmtc, w := utf8.DecodeRuneInString(format[i:]) @@ -1085,24 +1084,45 @@ func (s *ss) advance(format string) (i int) { i += w // skip the first % } sawSpace := false + wasNewline := false + // Skip spaces in format but absorb at most one newline. for isSpace(fmtc) && i < len(format) { + if fmtc == '\n' { + if wasNewline { // Already saw one; stop here. + break + } + wasNewline = true + } sawSpace = true i += w fmtc, w = utf8.DecodeRuneInString(format[i:]) } if sawSpace { - // There was space in the format, so there should be space (EOF) + // There was space in the format, so there should be space // in the input. inputc := s.getRune() - if inputc == eof || inputc == '\n' { - // If we've reached a newline, stop now; don't read ahead. + if inputc == eof { return } if !isSpace(inputc) { - // Space in format but not in input: error + // Space in format but not in input. s.errorString("expected space in input to match format") } - s.skipSpace(true) + // Skip spaces but stop at newline. + for inputc != '\n' && isSpace(inputc) { + inputc = s.getRune() + } + if inputc == '\n' { + if !wasNewline { + s.errorString("newline in input does not match format") + } + // We've reached a newline, stop now; don't read further. + return + } + s.UnreadRune() + if wasNewline { + s.errorString("newline in format does not match input") + } continue } inputc := s.mustReadRune() @@ -1144,6 +1164,7 @@ func (s *ss) doScanf(format string, a []interface{}) (numProcessed int, err erro if !widPresent { s.maxWid = hugeWid } + s.SkipSpace() s.argLimit = s.limit if f := s.count + s.maxWid; f < s.argLimit { s.argLimit = f diff --git a/libgo/go/fmt/scan_test.go b/libgo/go/fmt/scan_test.go index 541e12df210..a3784364e63 100644 --- a/libgo/go/fmt/scan_test.go +++ b/libgo/go/fmt/scan_test.go @@ -340,6 +340,8 @@ var multiTests = []ScanfMultiTest{ {"%6vX=%3fY", "3+2iX=2.5Y", args(&c, &f), args((3 + 2i), 2.5), ""}, {"%d%s", "123abc", args(&i, &s), args(123, "abc"), ""}, {"%c%c%c", "2\u50c2X", args(&r1, &r2, &r3), args('2', '\u50c2', 'X'), ""}, + {"%5s%d", " 1234567 ", args(&s, &i), args("12345", 67), ""}, + {"%5s%d", " 12 34 567 ", args(&s, &i), args("12", 34), ""}, // Custom scanners. {"%e%f", "eefffff", args(&x, &y), args(Xs("ee"), Xs("fffff")), ""}, @@ -864,7 +866,7 @@ func TestScanStateCount(t *testing.T) { t.Fatal(err) } if n != 3 { - t.Fatalf("expected 3 items consumed, got %d") + t.Fatalf("expected 3 items consumed, got %d", n) } if a.rune != '1' || b.rune != '2' || c.rune != '➂' { t.Errorf("bad scan rune: %q %q %q should be '1' '2' '➂'", a.rune, b.rune, c.rune) @@ -990,3 +992,167 @@ func BenchmarkScanRecursiveInt(b *testing.B) { b.StopTimer() } } + +// Issue 9124. +// %x on bytes couldn't handle non-space bytes terminating the scan. +func TestHexBytes(t *testing.T) { + var a, b []byte + n, err := Sscanf("00010203", "%x", &a) + if n != 1 || err != nil { + t.Errorf("simple: got count, err = %d, %v; expected 1, nil", n, err) + } + check := func(msg string, x []byte) { + if len(x) != 4 { + t.Errorf("%s: bad length %d", msg, len(x)) + } + for i, b := range x { + if int(b) != i { + t.Errorf("%s: bad x[%d] = %x", msg, i, x[i]) + } + } + } + check("simple", a) + a = nil + + n, err = Sscanf("00010203 00010203", "%x %x", &a, &b) + if n != 2 || err != nil { + t.Errorf("simple pair: got count, err = %d, %v; expected 2, nil", n, err) + } + check("simple pair a", a) + check("simple pair b", b) + a = nil + b = nil + + n, err = Sscanf("00010203:", "%x", &a) + if n != 1 || err != nil { + t.Errorf("colon: got count, err = %d, %v; expected 1, nil", n, err) + } + check("colon", a) + a = nil + + n, err = Sscanf("00010203:00010203", "%x:%x", &a, &b) + if n != 2 || err != nil { + t.Errorf("colon pair: got count, err = %d, %v; expected 2, nil", n, err) + } + check("colon pair a", a) + check("colon pair b", b) + a = nil + b = nil + + // This one fails because there is a hex byte after the data, + // that is, an odd number of hex input bytes. + n, err = Sscanf("000102034:", "%x", &a) + if n != 0 || err == nil { + t.Errorf("odd count: got count, err = %d, %v; expected 0, error", n, err) + } +} + +func TestScanNewlinesAreSpaces(t *testing.T) { + var a, b int + var tests = []struct { + name string + text string + count int + }{ + {"newlines", "1\n2\n", 2}, + {"no final newline", "1\n2", 2}, + {"newlines with spaces ", "1 \n 2 \n", 2}, + {"no final newline with spaces", "1 \n 2", 2}, + } + for _, test := range tests { + n, err := Sscan(test.text, &a, &b) + if n != test.count { + t.Errorf("%s: expected to scan %d item(s), scanned %d", test.name, test.count, n) + } + if err != nil { + t.Errorf("%s: unexpected error: %s", test.name, err) + } + } +} + +func TestScanlnNewlinesTerminate(t *testing.T) { + var a, b int + var tests = []struct { + name string + text string + count int + ok bool + }{ + {"one line one item", "1\n", 1, false}, + {"one line two items with spaces ", " 1 2 \n", 2, true}, + {"one line two items no newline", " 1 2", 2, true}, + {"two lines two items", "1\n2\n", 1, false}, + } + for _, test := range tests { + n, err := Sscanln(test.text, &a, &b) + if n != test.count { + t.Errorf("%s: expected to scan %d item(s), scanned %d", test.name, test.count, n) + } + if test.ok && err != nil { + t.Errorf("%s: unexpected error: %s", test.name, err) + } + if !test.ok && err == nil { + t.Errorf("%s: expected error; got none", test.name) + } + } +} + +func TestScanfNewlineMatchFormat(t *testing.T) { + var a, b int + var tests = []struct { + name string + text string + format string + count int + ok bool + }{ + {"newline in both", "1\n2", "%d\n%d\n", 2, true}, + {"newline in input", "1\n2", "%d %d", 1, false}, + {"space-newline in input", "1 \n2", "%d %d", 1, false}, + {"newline in format", "1 2", "%d\n%d", 1, false}, + {"space-newline in format", "1 2", "%d \n%d", 1, false}, + {"space-newline in both", "1 \n2", "%d \n%d", 2, true}, + {"extra space in format", "1\n2", "%d\n %d", 2, true}, + {"two extra spaces in format", "1\n2", "%d \n %d", 2, true}, + } + for _, test := range tests { + n, err := Sscanf(test.text, test.format, &a, &b) + if n != test.count { + t.Errorf("%s: expected to scan %d item(s), scanned %d", test.name, test.count, n) + } + if test.ok && err != nil { + t.Errorf("%s: unexpected error: %s", test.name, err) + } + if !test.ok && err == nil { + t.Errorf("%s: expected error; got none", test.name) + } + } +} + +// Test for issue 12090: Was unreading at EOF, double-scanning a byte. + +type hexBytes [2]byte + +func (h *hexBytes) Scan(ss ScanState, verb rune) error { + var b []byte + _, err := Fscanf(ss, "%4x", &b) + if err != nil { + panic(err) // Really shouldn't happen. + } + copy((*h)[:], b) + return err +} + +func TestHexByte(t *testing.T) { + var h hexBytes + n, err := Sscanln("0123\n", &h) + if err != nil { + t.Fatal(err) + } + if n != 1 { + t.Fatalf("expected 1 item; scanned %d", n) + } + if h[0] != 0x01 || h[1] != 0x23 { + t.Fatalf("expected 0123 got %x", h) + } +} diff --git a/libgo/go/go/ast/ast.go b/libgo/go/go/ast/ast.go index 312e3d1b989..5ab4283826b 100644 --- a/libgo/go/go/ast/ast.go +++ b/libgo/go/go/ast/ast.go @@ -486,7 +486,7 @@ func (x *MapType) End() token.Pos { return x.Value.End() } func (x *ChanType) End() token.Pos { return x.Value.End() } // exprNode() ensures that only expression/type nodes can be -// assigned to an ExprNode. +// assigned to an Expr. // func (*BadExpr) exprNode() {} func (*Ident) exprNode() {} @@ -562,10 +562,11 @@ type ( // An EmptyStmt node represents an empty statement. // The "position" of the empty statement is the position - // of the immediately preceding semicolon. + // of the immediately following (explicit or implicit) semicolon. // EmptyStmt struct { - Semicolon token.Pos // position of preceding ";" + Semicolon token.Pos // position of following ";" + Implicit bool // if set, ";" was omitted in the source } // A LabeledStmt node represents a labeled statement. @@ -734,6 +735,9 @@ func (s *RangeStmt) Pos() token.Pos { return s.For } func (s *BadStmt) End() token.Pos { return s.To } func (s *DeclStmt) End() token.Pos { return s.Decl.End() } func (s *EmptyStmt) End() token.Pos { + if s.Implicit { + return s.Semicolon + } return s.Semicolon + 1 /* len(";") */ } func (s *LabeledStmt) End() token.Pos { return s.Stmt.End() } @@ -783,7 +787,7 @@ func (s *ForStmt) End() token.Pos { return s.Body.End() } func (s *RangeStmt) End() token.Pos { return s.Body.End() } // stmtNode() ensures that only statement nodes can be -// assigned to a StmtNode. +// assigned to a Stmt. // func (*BadStmt) stmtNode() {} func (*DeclStmt) stmtNode() {} @@ -947,7 +951,7 @@ func (d *FuncDecl) End() token.Pos { } // declNode() ensures that only declaration nodes can be -// assigned to a DeclNode. +// assigned to a Decl. // func (*BadDecl) declNode() {} func (*GenDecl) declNode() {} diff --git a/libgo/go/go/ast/filter.go b/libgo/go/go/ast/filter.go index fc3eeb4a1db..bb571166f47 100644 --- a/libgo/go/go/ast/filter.go +++ b/libgo/go/go/ast/filter.go @@ -23,8 +23,7 @@ func exportFilter(name string) bool { // body) are removed. Non-exported fields and methods of exported types are // stripped. The File.Comments list is not changed. // -// FileExports returns true if there are exported declarations; -// it returns false otherwise. +// FileExports reports whether there are exported declarations. // func FileExports(src *File) bool { return filterFile(src, exportFilter, true) @@ -34,7 +33,7 @@ func FileExports(src *File) bool { // only exported nodes remain. The pkg.Files list is not changed, so that // file names and top-level package comments don't get lost. // -// PackageExports returns true if there are exported declarations; +// PackageExports reports whether there are exported declarations; // it returns false otherwise. // func PackageExports(pkg *Package) bool { @@ -199,8 +198,8 @@ func filterSpecList(list []Spec, f Filter, export bool) []Spec { // all names (including struct field and interface method names, but // not from parameter lists) that don't pass through the filter f. // -// FilterDecl returns true if there are any declared names left after -// filtering; it returns false otherwise. +// FilterDecl reports whether there are any declared names left after +// filtering. // func FilterDecl(decl Decl, f Filter) bool { return filterDecl(decl, f, false) @@ -221,11 +220,11 @@ func filterDecl(decl Decl, f Filter, export bool) bool { // names from top-level declarations (including struct field and // interface method names, but not from parameter lists) that don't // pass through the filter f. If the declaration is empty afterwards, -// the declaration is removed from the AST. The File.Comments list -// is not changed. +// the declaration is removed from the AST. Import declarations are +// always removed. The File.Comments list is not changed. // -// FilterFile returns true if there are any top-level declarations -// left after filtering; it returns false otherwise. +// FilterFile reports whether there are any top-level declarations +// left after filtering. // func FilterFile(src *File, f Filter) bool { return filterFile(src, f, false) @@ -251,8 +250,8 @@ func filterFile(src *File, f Filter, export bool) bool { // changed, so that file names and top-level package comments don't get // lost. // -// FilterPackage returns true if there are any top-level declarations -// left after filtering; it returns false otherwise. +// FilterPackage reports whether there are any top-level declarations +// left after filtering. // func FilterPackage(pkg *Package, f Filter) bool { return filterPackage(pkg, f, false) diff --git a/libgo/go/go/ast/scope.go b/libgo/go/go/ast/scope.go index df1529d1819..1ce5e2e84b5 100644 --- a/libgo/go/go/ast/scope.go +++ b/libgo/go/go/ast/scope.go @@ -38,7 +38,7 @@ func (s *Scope) Lookup(name string) *Object { // Insert attempts to insert a named object obj into the scope s. // If the scope already contains an object alt with the same name, // Insert leaves the scope unchanged and returns alt. Otherwise -// it inserts obj and returns nil." +// it inserts obj and returns nil. // func (s *Scope) Insert(obj *Object) (alt *Object) { if alt = s.Objects[obj.Name]; alt == nil { diff --git a/libgo/go/go/ast/walk.go b/libgo/go/go/ast/walk.go index 73ac38647a2..8ca21959b11 100644 --- a/libgo/go/go/ast/walk.go +++ b/libgo/go/go/ast/walk.go @@ -361,8 +361,7 @@ func Walk(v Visitor, node Node) { } default: - fmt.Printf("ast.Walk: unexpected node type %T", n) - panic("ast.Walk") + panic(fmt.Sprintf("ast.Walk: unexpected node type %T", n)) } v.Visit(nil) @@ -379,7 +378,8 @@ func (f inspector) Visit(node Node) Visitor { // Inspect traverses an AST in depth-first order: It starts by calling // f(node); node must not be nil. If f returns true, Inspect invokes f -// for all the non-nil children of node, recursively. +// recursively for each of the non-nil children of node, followed by a +// call of f(nil). // func Inspect(node Node, f func(Node) bool) { Walk(inspector(f), node) diff --git a/libgo/go/go/build/build.go b/libgo/go/go/build/build.go index e9247274b6e..42f11655b39 100644 --- a/libgo/go/go/build/build.go +++ b/libgo/go/go/build/build.go @@ -256,10 +256,12 @@ func (ctxt *Context) SrcDirs() []string { // if set, or else the compiled code's GOARCH, GOOS, and GOROOT. var Default Context = defaultContext() +// Also known to cmd/dist/build.go. var cgoEnabled = map[string]bool{ "darwin/386": true, "darwin/amd64": true, - "dragonfly/386": true, + "darwin/arm": true, + "darwin/arm64": true, "dragonfly/amd64": true, "freebsd/386": true, "freebsd/amd64": true, @@ -282,6 +284,7 @@ var cgoEnabled = map[string]bool{ "netbsd/arm": true, "openbsd/386": true, "openbsd/amd64": true, + "solaris/amd64": true, "windows/386": true, "windows/amd64": true, } @@ -300,11 +303,7 @@ func defaultContext() Context { // in all releases >= Go 1.x. Code that requires Go 1.x or later should // say "+build go1.x", and code that should only be built before Go 1.x // (perhaps it is the stub to use in that case) should say "+build !go1.x". - // - // When we reach Go 1.5 the line will read - // c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3", "go1.4", "go1.5"} - // and so on. - c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3", "go1.4"} + c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3", "go1.4", "go1.5"} switch os.Getenv("CGO_ENABLED") { case "1": @@ -361,6 +360,7 @@ type Package struct { Root string // root of Go tree where this package lives SrcRoot string // package source root directory ("" if unknown) PkgRoot string // package install root directory ("" if unknown) + PkgTargetRoot string // architecture dependent install root directory ("" if unknown) BinDir string // command install directory ("" if unknown) Goroot bool // package found in Go root PkgObj string // installed .a file @@ -469,18 +469,21 @@ func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Packa return p, fmt.Errorf("import %q: invalid import path", path) } + var pkgtargetroot string var pkga string var pkgerr error + suffix := "" + if ctxt.InstallSuffix != "" { + suffix = "_" + ctxt.InstallSuffix + } switch ctxt.Compiler { case "gccgo": + pkgtargetroot = "pkg/gccgo_" + ctxt.GOOS + "_" + ctxt.GOARCH + suffix dir, elem := pathpkg.Split(p.ImportPath) - pkga = "pkg/gccgo_" + ctxt.GOOS + "_" + ctxt.GOARCH + "/" + dir + "lib" + elem + ".a" + pkga = pkgtargetroot + "/" + dir + "lib" + elem + ".a" case "gc": - suffix := "" - if ctxt.InstallSuffix != "" { - suffix = "_" + ctxt.InstallSuffix - } - pkga = "pkg/" + ctxt.GOOS + "_" + ctxt.GOARCH + suffix + "/" + p.ImportPath + ".a" + pkgtargetroot = "pkg/" + ctxt.GOOS + "_" + ctxt.GOARCH + suffix + pkga = pkgtargetroot + "/" + p.ImportPath + ".a" default: // Save error for end of function. pkgerr = fmt.Errorf("import %q: unknown compiler %q", path, ctxt.Compiler) @@ -496,9 +499,13 @@ func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Packa p.Dir = ctxt.joinPath(srcDir, path) } // Determine canonical import path, if any. + // Exclude results where the import path would include /testdata/. + inTestdata := func(sub string) bool { + return strings.Contains(sub, "/testdata/") || strings.HasSuffix(sub, "/testdata") || strings.HasPrefix(sub, "testdata/") || sub == "testdata" + } if ctxt.GOROOT != "" { root := ctxt.joinPath(ctxt.GOROOT, "src") - if sub, ok := ctxt.hasSubdir(root, p.Dir); ok { + if sub, ok := ctxt.hasSubdir(root, p.Dir); ok && !inTestdata(sub) { p.Goroot = true p.ImportPath = sub p.Root = ctxt.GOROOT @@ -508,7 +515,7 @@ func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Packa all := ctxt.gopath() for i, root := range all { rootsrc := ctxt.joinPath(root, "src") - if sub, ok := ctxt.hasSubdir(rootsrc, p.Dir); ok { + if sub, ok := ctxt.hasSubdir(rootsrc, p.Dir); ok && !inTestdata(sub) { // We found a potential import path for dir, // but check that using it wouldn't find something // else first. @@ -597,6 +604,7 @@ Found: p.PkgRoot = ctxt.joinPath(p.Root, "pkg") p.BinDir = ctxt.joinPath(p.Root, "bin") if pkga != "" { + p.PkgTargetRoot = ctxt.joinPath(p.Root, pkgtargetroot) p.PkgObj = ctxt.joinPath(p.Root, pkga) } } @@ -695,7 +703,11 @@ Found: p.Name = pkg firstFile = name } else if pkg != p.Name { - return p, &MultiplePackageError{p.Dir, []string{firstFile, name}, []string{p.Name, pkg}} + return p, &MultiplePackageError{ + Dir: p.Dir, + Packages: []string{p.Name, pkg}, + Files: []string{firstFile, name}, + } } if pf.Doc != nil && p.Doc == "" { p.Doc = doc.Synopsis(pf.Doc.Text()) @@ -962,7 +974,7 @@ func (ctxt *Context) matchFile(dir, name string, returnImports bool, allTags map } if strings.HasSuffix(filename, ".go") { - data, err = readImports(f, false) + data, err = readImports(f, false, nil) } else { data, err = readComments(f) } @@ -1075,9 +1087,6 @@ func (ctxt *Context) shouldBuild(content []byte, allTags map[string]bool) bool { // saveCgo saves the information from the #cgo lines in the import "C" comment. // These lines set CFLAGS, CPPFLAGS, CXXFLAGS and LDFLAGS and pkg-config directives // that affect the way cgo's C code is built. -// -// TODO(rsc): This duplicates code in cgo. -// Once the dust settles, remove this code from cgo. func (ctxt *Context) saveCgo(filename string, di *Package, cg *ast.CommentGroup) error { text := cg.Text() for _, line := range strings.Split(text, "\n") { @@ -1123,10 +1132,12 @@ func (ctxt *Context) saveCgo(filename string, di *Package, cg *ast.CommentGroup) if err != nil { return fmt.Errorf("%s: invalid #cgo line: %s", filename, orig) } - for _, arg := range args { + for i, arg := range args { + arg = expandSrcDir(arg, di.Dir) if !safeCgoName(arg) { return fmt.Errorf("%s: malformed #cgo argument: %s", filename, arg) } + args[i] = arg } switch verb { @@ -1147,6 +1158,14 @@ func (ctxt *Context) saveCgo(filename string, di *Package, cg *ast.CommentGroup) return nil } +func expandSrcDir(str string, srcdir string) string { + // "\" delimited paths cause safeCgoName to fail + // so convert native paths with a different delimeter + // to "/" before starting (eg: on windows) + srcdir = filepath.ToSlash(srcdir) + return strings.Replace(str, "${SRCDIR}", srcdir, -1) +} + // NOTE: $ is not safe for the shell, but it is allowed here because of linker options like -Wl,$ORIGIN. // We never pass these arguments to a shell (just to programs we construct argv for), so this should be okay. // See golang.org/issue/6038. @@ -1225,7 +1244,7 @@ func splitQuoted(s string) (r []string, err error) { return args, err } -// match returns true if the name is one of: +// match reports whether the name is one of: // // $GOOS // $GOARCH @@ -1316,7 +1335,7 @@ func (ctxt *Context) goodOSArchFile(name string, allTags map[string]bool) bool { // build tag "linux" in that file. For Go 1.4 and beyond, we require this // auto-tagging to apply only to files with a non-empty prefix, so // "foo_linux.go" is tagged but "linux.go" is not. This allows new operating - // sytems, such as android, to arrive without breaking existing code with + // systems, such as android, to arrive without breaking existing code with // innocuous source code in "android.go". The easiest fix: cut everything // in the name before the initial _. i := strings.Index(name, "_") @@ -1390,20 +1409,11 @@ func IsLocalImport(path string) bool { strings.HasPrefix(path, "./") || strings.HasPrefix(path, "../") } -// ArchChar returns the architecture character for the given goarch. -// For example, ArchChar("amd64") returns "6". +// ArchChar returns "?" and an error. +// In earlier versions of Go, the returned string was used to derive +// the compiler and linker tool names, the default object file suffix, +// and the default linker output name. As of Go 1.5, those strings +// no longer vary by architecture; they are compile, link, .o, and a.out, respectively. func ArchChar(goarch string) (string, error) { - switch goarch { - case "386": - return "8", nil - case "amd64", "amd64p32": - return "6", nil - case "arm": - return "5", nil - case "arm64": - return "7", nil - case "ppc64", "ppc64le": - return "9", nil - } - return "", errors.New("unsupported GOARCH " + goarch) + return "?", errors.New("architecture letter no longer used") } diff --git a/libgo/go/go/build/build_test.go b/libgo/go/go/build/build_test.go index a40def0fa0e..2709ca34f54 100644 --- a/libgo/go/go/build/build_test.go +++ b/libgo/go/go/build/build_test.go @@ -94,12 +94,29 @@ func TestEmptyFolderImport(t *testing.T) { func TestMultiplePackageImport(t *testing.T) { _, err := Import(".", "testdata/multi", 0) - if _, ok := err.(*MultiplePackageError); !ok { + mpe, ok := err.(*MultiplePackageError) + if !ok { t.Fatal(`Import("testdata/multi") did not return MultiplePackageError.`) } + want := &MultiplePackageError{ + Dir: filepath.FromSlash("testdata/multi"), + Packages: []string{"main", "test_package"}, + Files: []string{"file.go", "file_appengine.go"}, + } + if !reflect.DeepEqual(mpe, want) { + t.Errorf("got %#v; want %#v", mpe, want) + } } func TestLocalDirectory(t *testing.T) { + t.Skip("does not work with gccgo") + if runtime.GOOS == "darwin" { + switch runtime.GOARCH { + case "arm", "arm64": + t.Skipf("skipping on %s/%s, no valid GOROOT", runtime.GOOS, runtime.GOARCH) + } + } + cwd, err := os.Getwd() if err != nil { t.Fatal(err) @@ -214,6 +231,14 @@ func TestMatchFile(t *testing.T) { } func TestImportCmd(t *testing.T) { + t.Skip("does not work with gccgo") + if runtime.GOOS == "darwin" { + switch runtime.GOARCH { + case "arm", "arm64": + t.Skipf("skipping on %s/%s, no valid GOROOT", runtime.GOOS, runtime.GOARCH) + } + } + p, err := Import("cmd/internal/objfile", "", 0) if err != nil { t.Fatal(err) @@ -222,3 +247,33 @@ func TestImportCmd(t *testing.T) { t.Fatalf("Import cmd/internal/objfile returned Dir=%q, want %q", filepath.ToSlash(p.Dir), ".../src/cmd/internal/objfile") } } + +var ( + expandSrcDirPath = filepath.Join(string(filepath.Separator)+"projects", "src", "add") +) + +var expandSrcDirTests = []struct { + input, expected string +}{ + {"-L ${SRCDIR}/libs -ladd", "-L /projects/src/add/libs -ladd"}, + {"${SRCDIR}/add_linux_386.a -pthread -lstdc++", "/projects/src/add/add_linux_386.a -pthread -lstdc++"}, + {"Nothing to expand here!", "Nothing to expand here!"}, + {"$", "$"}, + {"$$", "$$"}, + {"${", "${"}, + {"$}", "$}"}, + {"$FOO ${BAR}", "$FOO ${BAR}"}, + {"Find me the $SRCDIRECTORY.", "Find me the $SRCDIRECTORY."}, + {"$SRCDIR is missing braces", "$SRCDIR is missing braces"}, +} + +func TestExpandSrcDir(t *testing.T) { + for _, test := range expandSrcDirTests { + output := expandSrcDir(test.input, expandSrcDirPath) + if output != test.expected { + t.Errorf("%q expands to %q with SRCDIR=%q when %q is expected", test.input, output, expandSrcDirPath, test.expected) + } else { + t.Logf("%q expands to %q with SRCDIR=%q", test.input, output, expandSrcDirPath) + } + } +} diff --git a/libgo/go/go/build/deps_test.go b/libgo/go/go/build/deps_test.go index a335effec3a..68969bbcf86 100644 --- a/libgo/go/go/build/deps_test.go +++ b/libgo/go/go/build/deps_test.go @@ -8,8 +8,15 @@ package build import ( + "bytes" + "fmt" + "io/ioutil" + "os" + "path/filepath" "runtime" "sort" + "strconv" + "strings" "testing" ) @@ -121,9 +128,12 @@ var pkgDeps = map[string][]string{ // End of linear dependency definitions. // Operating system access. - "syscall": {"L0", "unicode/utf16"}, - "time": {"L0", "syscall"}, - "os": {"L1", "os", "syscall", "time"}, + "syscall": {"L0", "unicode/utf16"}, + "internal/syscall/unix": {"L0", "syscall"}, + "internal/syscall/windows": {"L0", "syscall"}, + "internal/syscall/windows/registry": {"L0", "syscall", "unicode/utf16"}, + "time": {"L0", "syscall", "internal/syscall/windows/registry"}, + "os": {"L1", "os", "syscall", "time", "internal/syscall/windows"}, "path/filepath": {"L2", "os", "syscall"}, "io/ioutil": {"L2", "os", "path/filepath", "time"}, "os/exec": {"L2", "os", "path/filepath", "syscall"}, @@ -148,11 +158,13 @@ var pkgDeps = map[string][]string{ "regexp/syntax": {"L2"}, "runtime/debug": {"L2", "fmt", "io/ioutil", "os", "time"}, "runtime/pprof": {"L2", "fmt", "text/tabwriter"}, + "runtime/trace": {"L0"}, "text/tabwriter": {"L2"}, - "testing": {"L2", "flag", "fmt", "os", "runtime/pprof", "time"}, - "testing/iotest": {"L2", "log"}, - "testing/quick": {"L2", "flag", "fmt", "reflect"}, + "testing": {"L2", "flag", "fmt", "os", "runtime/pprof", "runtime/trace", "time"}, + "testing/iotest": {"L2", "log"}, + "testing/quick": {"L2", "flag", "fmt", "reflect"}, + "internal/testenv": {"L2", "os", "testing"}, // 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. @@ -180,43 +192,60 @@ var pkgDeps = map[string][]string{ "go/token", }, + "go/format": {"L4", "GOPARSER", "internal/format"}, + "internal/format": {"L4", "GOPARSER"}, + + // Go type checking. + "go/constant": {"L4", "go/token", "math/big"}, + "go/importer": {"L4", "go/internal/gcimporter", "go/internal/gccgoimporter", "go/types"}, + "go/internal/gcimporter": {"L4", "OS", "go/build", "go/constant", "go/token", "go/types", "text/scanner"}, + "go/internal/gccgoimporter": {"L4", "OS", "debug/elf", "go/constant", "go/token", "go/types", "text/scanner"}, + "go/types": {"L4", "GOPARSER", "container/heap", "go/constant"}, + // One of a kind. - "archive/tar": {"L4", "OS", "syscall"}, - "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", "container/list", "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": {"L4"}, - "encoding/ascii85": {"L4"}, - "encoding/asn1": {"L4", "math/big"}, - "encoding/csv": {"L4"}, - "encoding/gob": {"L4", "OS", "encoding"}, - "encoding/hex": {"L4"}, - "encoding/json": {"L4", "encoding"}, - "encoding/pem": {"L4"}, - "encoding/xml": {"L4", "encoding"}, - "flag": {"L4", "OS"}, - "go/build": {"L4", "OS", "GOPARSER"}, - "html": {"L4"}, - "image/draw": {"L4"}, - "image/gif": {"L4", "compress/lzw", "image/color/palette", "image/draw"}, - "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"}, + "archive/tar": {"L4", "OS", "syscall"}, + "archive/zip": {"L4", "OS", "compress/flate"}, + "container/heap": {"sort"}, + "compress/bzip2": {"L4"}, + "compress/flate": {"L4"}, + "compress/gzip": {"L4", "compress/flate"}, + "compress/lzw": {"L4"}, + "compress/zlib": {"L4", "compress/flate"}, + "database/sql": {"L4", "container/list", "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"}, + "debug/plan9obj": {"L4", "OS"}, + "encoding": {"L4"}, + "encoding/ascii85": {"L4"}, + "encoding/asn1": {"L4", "math/big"}, + "encoding/csv": {"L4"}, + "encoding/gob": {"L4", "OS", "encoding"}, + "encoding/hex": {"L4"}, + "encoding/json": {"L4", "encoding"}, + "encoding/pem": {"L4"}, + "encoding/xml": {"L4", "encoding"}, + "flag": {"L4", "OS"}, + "go/build": {"L4", "OS", "GOPARSER"}, + "html": {"L4"}, + "image/draw": {"L4", "image/internal/imageutil"}, + "image/gif": {"L4", "compress/lzw", "image/color/palette", "image/draw"}, + "image/internal/imageutil": {"L4"}, + "image/jpeg": {"L4", "image/internal/imageutil"}, + "image/png": {"L4", "compress/zlib"}, + "index/suffixarray": {"L4", "regexp"}, + "internal/singleflight": {"sync"}, + "internal/trace": {"L4", "OS"}, + "math/big": {"L4"}, + "mime": {"L4", "OS", "syscall", "internal/syscall/windows/registry"}, + "mime/quotedprintable": {"L4"}, + "net/internal/socktest": {"L4", "OS", "syscall"}, + "net/url": {"L4"}, + "text/scanner": {"L4", "OS"}, + "text/template/parse": {"L4"}, "html/template": { "L4", "OS", "encoding/json", "html", "text/template", @@ -234,13 +263,16 @@ var pkgDeps = map[string][]string{ // that shows up in programs that use cgo. "C": {}, + // Race detector uses cgo. + "runtime/race": {"C"}, + // Plan 9 alone needs io/ioutil and os. "os/user": {"L4", "CGO", "io/ioutil", "os", "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": {"L1", "CGO", "os", "syscall", "time", "internal/syscall/windows", "internal/singleflight"}, // NET enables use of basic network-related packages. "NET": { @@ -252,7 +284,7 @@ var pkgDeps = map[string][]string{ // Uses of networking. "log/syslog": {"L4", "OS", "net"}, - "net/mail": {"L4", "NET", "OS"}, + "net/mail": {"L4", "NET", "OS", "mime"}, "net/textproto": {"L4", "OS", "net"}, // Core crypto. @@ -279,7 +311,7 @@ var pkgDeps = map[string][]string{ // 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", "internal/syscall"}, + "crypto/rand": {"L4", "CRYPTO", "OS", "math/big", "syscall", "internal/syscall/unix"}, // Mathematical crypto: dependencies on fmt (L4) and math/big. // We could avoid some of the fmt, but math/big imports fmt anyway. @@ -311,7 +343,7 @@ var pkgDeps = map[string][]string{ "crypto/x509/pkix": {"L4", "CRYPTO-MATH"}, // Simple net+crypto-aware packages. - "mime/multipart": {"L4", "OS", "mime", "crypto/rand", "net/textproto"}, + "mime/multipart": {"L4", "OS", "mime", "crypto/rand", "net/textproto", "mime/quotedprintable"}, "net/smtp": {"L4", "CRYPTO", "NET", "crypto/tls"}, // HTTP, kingpin of dependencies. @@ -320,16 +352,18 @@ var pkgDeps = map[string][]string{ "compress/gzip", "crypto/tls", "mime/multipart", "runtime/debug", "net/http/internal", }, + "net/http/internal": {"L4"}, // 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/internal"}, - "net/http/pprof": {"L4", "OS", "html/template", "net/http", "runtime/pprof"}, - "net/rpc": {"L4", "NET", "encoding/gob", "html/template", "net/http"}, - "net/rpc/jsonrpc": {"L4", "NET", "encoding/json", "net/rpc"}, + "expvar": {"L4", "OS", "encoding/json", "net/http"}, + "net/http/cgi": {"L4", "NET", "OS", "crypto/tls", "net/http", "regexp"}, + "net/http/cookiejar": {"L4", "NET", "net/http"}, + "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/internal"}, + "net/http/pprof": {"L4", "OS", "html/template", "net/http", "runtime/pprof", "runtime/trace"}, + "net/rpc": {"L4", "NET", "encoding/gob", "html/template", "net/http"}, + "net/rpc/jsonrpc": {"L4", "NET", "encoding/json", "net/rpc"}, } // isMacro reports whether p is a package dependency macro @@ -375,69 +409,112 @@ var allowedErrors = map[osPkg]bool{ osPkg{"plan9", "log/syslog"}: true, } +// listStdPkgs returns the same list of packages as "go list std". +func listStdPkgs(goroot string) ([]string, error) { + // Based on cmd/go's matchPackages function. + var pkgs []string + + src := filepath.Join(goroot, "src") + string(filepath.Separator) + walkFn := func(path string, fi os.FileInfo, err error) error { + if err != nil || !fi.IsDir() || path == src { + return nil + } + + base := filepath.Base(path) + if strings.HasPrefix(base, ".") || strings.HasPrefix(base, "_") || base == "testdata" { + return filepath.SkipDir + } + + name := filepath.ToSlash(path[len(src):]) + if name == "builtin" || name == "cmd" || strings.Contains(name, ".") { + return filepath.SkipDir + } + + pkgs = append(pkgs, name) + return nil + } + if err := filepath.Walk(src, walkFn); err != nil { + return nil, err + } + return pkgs, nil +} + func TestDependencies(t *testing.T) { - if runtime.GOOS == "nacl" { - // NaCl tests run in a limited file system and we do not + iOS := runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") + if runtime.GOOS == "nacl" || iOS { + // Tests run in a limited file system and we do not // provide access to every source file. - t.Skip("skipping on NaCl") + t.Skipf("skipping on %s/%s, missing full GOROOT", runtime.GOOS, runtime.GOARCH) } - var all []string - for k := range pkgDeps { - all = append(all, k) + ctxt := Default + all, err := listStdPkgs(ctxt.GOROOT) + if err != nil { + t.Fatal(err) } sort.Strings(all) - ctxt := Default test := func(mustImport bool) { for _, pkg := range all { - if isMacro(pkg) { - continue - } - if pkg == "runtime/cgo" && !ctxt.CgoEnabled { - continue - } - p, err := ctxt.Import(pkg, "", 0) + imports, err := findImports(pkg) if err != nil { - if allowedErrors[osPkg{ctxt.GOOS, pkg}] { - continue - } - if !ctxt.CgoEnabled && pkg == "runtime/cgo" { - 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) + t.Error(err) continue } ok := allowed(pkg) var bad []string - for _, imp := range p.Imports { + for _, imp := range 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) + t.Errorf("unexpected dependency: %s imports %v", pkg, bad) } } } test(true) +} - if testing.Short() { - t.Logf("skipping other systems") - return - } +var buildIgnore = []byte("\n// +build ignore") - for _, ctxt.GOOS = range geese { - for _, ctxt.GOARCH = range goarches { - for _, ctxt.CgoEnabled = range bools { - test(false) +func findImports(pkg string) ([]string, error) { + dir := filepath.Join(Default.GOROOT, "src", pkg) + files, err := ioutil.ReadDir(dir) + if err != nil { + return nil, err + } + var imports []string + var haveImport = map[string]bool{} + for _, file := range files { + name := file.Name() + if !strings.HasSuffix(name, ".go") || strings.HasSuffix(name, "_test.go") { + continue + } + f, err := os.Open(filepath.Join(dir, name)) + if err != nil { + return nil, err + } + var imp []string + data, err := readImports(f, false, &imp) + f.Close() + if err != nil { + return nil, fmt.Errorf("reading %v: %v", name, err) + } + if bytes.Contains(data, buildIgnore) { + continue + } + for _, quoted := range imp { + path, err := strconv.Unquote(quoted) + if err != nil { + continue + } + if !haveImport[path] { + haveImport[path] = true + imports = append(imports, path) } } } + sort.Strings(imports) + return imports, nil } diff --git a/libgo/go/go/build/doc.go b/libgo/go/go/build/doc.go index 75a827bb91f..233f8b989d5 100644 --- a/libgo/go/go/build/doc.go +++ b/libgo/go/go/build/doc.go @@ -101,6 +101,7 @@ // - "go1.2", from Go version 1.2 onward // - "go1.3", from Go version 1.3 onward // - "go1.4", from Go version 1.4 onward +// - "go1.5", from Go version 1.5 onward // - any additional words listed in ctxt.BuildTags // // If a file's name, after stripping the extension and a possible _test suffix, @@ -111,7 +112,7 @@ // (example: source_windows_amd64.go) where GOOS and GOARCH represent // any known operating system and architecture values respectively, then // the file is considered to have an implicit build constraint requiring -// those terms. +// those terms (in addition to any explicit constraints in the file). // // To keep a file from being considered for the build: // diff --git a/libgo/go/go/build/read.go b/libgo/go/go/build/read.go index c8079dfd15d..1049ac50d94 100644 --- a/libgo/go/go/build/read.go +++ b/libgo/go/go/build/read.go @@ -146,11 +146,15 @@ func (r *importReader) readIdent() { // readString reads a quoted string literal from the input. // If an identifier is not present, readString records a syntax error. -func (r *importReader) readString() { +func (r *importReader) readString(save *[]string) { switch r.nextByte(true) { case '`': + start := len(r.buf) - 1 for r.err == nil { if r.nextByte(false) == '`' { + if save != nil { + *save = append(*save, string(r.buf[start:])) + } break } if r.eof { @@ -158,9 +162,13 @@ func (r *importReader) readString() { } } case '"': + start := len(r.buf) - 1 for r.err == nil { c := r.nextByte(false) if c == '"' { + if save != nil { + *save = append(*save, string(r.buf[start:])) + } break } if r.eof || c == '\n' { @@ -177,14 +185,14 @@ func (r *importReader) readString() { // readImport reads an import clause - optional identifier followed by quoted string - // from the input. -func (r *importReader) readImport() { +func (r *importReader) readImport(imports *[]string) { c := r.peekByte(true) if c == '.' { r.peek = 0 } else if isIdent(c) { r.readIdent() } - r.readString() + r.readString(imports) } // readComments is like ioutil.ReadAll, except that it only reads the leading @@ -201,7 +209,7 @@ func readComments(f io.Reader) ([]byte, error) { // readImports is like ioutil.ReadAll, except that it expects a Go file as input // and stops reading the input once the imports have completed. -func readImports(f io.Reader, reportSyntaxError bool) ([]byte, error) { +func readImports(f io.Reader, reportSyntaxError bool, imports *[]string) ([]byte, error) { r := &importReader{b: bufio.NewReader(f)} r.readKeyword("package") @@ -211,11 +219,11 @@ func readImports(f io.Reader, reportSyntaxError bool) ([]byte, error) { if r.peekByte(true) == '(' { r.nextByte(false) for r.peekByte(true) != ')' && r.err == nil { - r.readImport() + r.readImport(imports) } r.nextByte(false) } else { - r.readImport() + r.readImport(imports) } } diff --git a/libgo/go/go/build/read_test.go b/libgo/go/go/build/read_test.go index 2dcc1208f71..326960bdc91 100644 --- a/libgo/go/go/build/read_test.go +++ b/libgo/go/go/build/read_test.go @@ -131,7 +131,7 @@ func testRead(t *testing.T, tests []readTest, read func(io.Reader) ([]byte, erro } func TestReadImports(t *testing.T) { - testRead(t, readImportsTests, func(r io.Reader) ([]byte, error) { return readImports(r, true) }) + testRead(t, readImportsTests, func(r io.Reader) ([]byte, error) { return readImports(r, true, nil) }) } func TestReadComments(t *testing.T) { @@ -207,7 +207,7 @@ var readFailuresTests = []readTest{ func TestReadFailures(t *testing.T) { // Errors should be reported (true arg to readImports). - testRead(t, readFailuresTests, func(r io.Reader) ([]byte, error) { return readImports(r, true) }) + testRead(t, readFailuresTests, func(r io.Reader) ([]byte, error) { return readImports(r, true, nil) }) } func TestReadFailuresIgnored(t *testing.T) { @@ -222,5 +222,5 @@ func TestReadFailuresIgnored(t *testing.T) { tt.err = "" } } - testRead(t, tests, func(r io.Reader) ([]byte, error) { return readImports(r, false) }) + testRead(t, tests, func(r io.Reader) ([]byte, error) { return readImports(r, false, nil) }) } diff --git a/libgo/go/go/build/syslist.go b/libgo/go/go/build/syslist.go index 0bf4b1573c9..d800a78f0a1 100644 --- a/libgo/go/go/build/syslist.go +++ b/libgo/go/go/build/syslist.go @@ -5,4 +5,4 @@ package build const goosList = "android darwin dragonfly freebsd linux nacl netbsd openbsd plan9 solaris windows " -const goarchList = "386 amd64 amd64p32 arm arm64 alpha m68k mipso32 mipsn32 mipsn64 mipso64 ppc ppc64 ppc64le s390 s390x sparc sparc64 " +const goarchList = "386 amd64 amd64p32 arm armbe arm64 arm64be alpha m68k ppc64 ppc64le mips mipsle mips64 mips64le mips64p32 mips64p32le mipso32 mipsn32 mipsn64 mipso64 ppc s390 s390x sparc sparc64 " diff --git a/libgo/go/go/build/testdata/empty/dummy b/libgo/go/go/build/testdata/empty/dummy new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libgo/go/go/constant/go13.go b/libgo/go/go/constant/go13.go new file mode 100644 index 00000000000..a4a838a2908 --- /dev/null +++ b/libgo/go/go/constant/go13.go @@ -0,0 +1,24 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !go1.4 + +package constant + +import ( + "math" + "math/big" +) + +func ratToFloat32(x *big.Rat) (float32, bool) { + // Before 1.4, there's no Rat.Float32. + // Emulate it, albeit at the cost of + // imprecision in corner cases. + x64, exact := x.Float64() + x32 := float32(x64) + if math.IsInf(float64(x32), 0) { + exact = false + } + return x32, exact +} diff --git a/libgo/go/go/constant/go14.go b/libgo/go/go/constant/go14.go new file mode 100644 index 00000000000..2ab6da02f67 --- /dev/null +++ b/libgo/go/go/constant/go14.go @@ -0,0 +1,13 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build go1.4 + +package constant + +import "math/big" + +func ratToFloat32(x *big.Rat) (float32, bool) { + return x.Float32() +} diff --git a/libgo/go/go/constant/value.go b/libgo/go/go/constant/value.go new file mode 100644 index 00000000000..79a80af1ab1 --- /dev/null +++ b/libgo/go/go/constant/value.go @@ -0,0 +1,925 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package constant implements Values representing untyped +// Go constants and the corresponding operations. Values +// and operations may have arbitrary or unlimited precision. +// +// A special Unknown value may be used when a value +// is unknown due to an error. Operations on unknown +// values produce unknown values unless specified +// otherwise. +// +package constant // import "go/constant" + +import ( + "fmt" + "go/token" + "math/big" + "strconv" +) + +// Kind specifies the kind of value represented by a Value. +type Kind int + +// Implementation note: Kinds must be enumerated in +// order of increasing "complexity" (used by match). + +const ( + // unknown values + Unknown Kind = iota + + // non-numeric values + Bool + String + + // numeric values + Int + Float + Complex +) + +// A Value represents a mathematically exact value of a given Kind. +type Value interface { + // Kind returns the value kind; it is always the smallest + // kind in which the value can be represented exactly. + Kind() Kind + + // String returns a human-readable form of the value. + String() string + + // Prevent external implementations. + implementsValue() +} + +// ---------------------------------------------------------------------------- +// Implementations + +type ( + unknownVal struct{} + boolVal bool + stringVal string + int64Val int64 + intVal struct{ val *big.Int } + floatVal struct{ val *big.Rat } + complexVal struct{ re, im *big.Rat } +) + +func (unknownVal) Kind() Kind { return Unknown } +func (boolVal) Kind() Kind { return Bool } +func (stringVal) Kind() Kind { return String } +func (int64Val) Kind() Kind { return Int } +func (intVal) Kind() Kind { return Int } +func (floatVal) Kind() Kind { return Float } +func (complexVal) Kind() Kind { return Complex } + +func (unknownVal) String() string { return "unknown" } +func (x boolVal) String() string { return fmt.Sprintf("%v", bool(x)) } +func (x stringVal) String() string { return strconv.Quote(string(x)) } +func (x int64Val) String() string { return strconv.FormatInt(int64(x), 10) } +func (x intVal) String() string { return x.val.String() } +func (x floatVal) String() string { return x.val.String() } +func (x complexVal) String() string { return fmt.Sprintf("(%s + %si)", x.re, x.im) } + +func (unknownVal) implementsValue() {} +func (boolVal) implementsValue() {} +func (stringVal) implementsValue() {} +func (int64Val) implementsValue() {} +func (intVal) implementsValue() {} +func (floatVal) implementsValue() {} +func (complexVal) implementsValue() {} + +// int64 bounds +var ( + minInt64 = big.NewInt(-1 << 63) + maxInt64 = big.NewInt(1<<63 - 1) +) + +func normInt(x *big.Int) Value { + if minInt64.Cmp(x) <= 0 && x.Cmp(maxInt64) <= 0 { + return int64Val(x.Int64()) + } + return intVal{x} +} + +func normFloat(x *big.Rat) Value { + if x.IsInt() { + return normInt(x.Num()) + } + return floatVal{x} +} + +func normComplex(re, im *big.Rat) Value { + if im.Sign() == 0 { + return normFloat(re) + } + return complexVal{re, im} +} + +// ---------------------------------------------------------------------------- +// Factories + +// MakeUnknown returns the Unknown value. +func MakeUnknown() Value { return unknownVal{} } + +// MakeBool returns the Bool value for x. +func MakeBool(b bool) Value { return boolVal(b) } + +// MakeString returns the String value for x. +func MakeString(s string) Value { return stringVal(s) } + +// MakeInt64 returns the Int value for x. +func MakeInt64(x int64) Value { return int64Val(x) } + +// MakeUint64 returns the Int value for x. +func MakeUint64(x uint64) Value { return normInt(new(big.Int).SetUint64(x)) } + +// MakeFloat64 returns the numeric value for x. +// If x is not finite, the result is unknown. +func MakeFloat64(x float64) Value { + if f := new(big.Rat).SetFloat64(x); f != nil { + return normFloat(f) + } + return unknownVal{} +} + +// MakeFromLiteral returns the corresponding integer, floating-point, +// imaginary, character, or string value for a Go literal string. +// If prec > 0, prec specifies an upper limit for the precision of +// a numeric value. If the literal string is invalid, the result is +// nil. +// BUG(gri) Only prec == 0 is supported at the moment. +func MakeFromLiteral(lit string, tok token.Token, prec uint) Value { + if prec != 0 { + panic("limited precision not supported") + } + switch tok { + case token.INT: + if x, err := strconv.ParseInt(lit, 0, 64); err == nil { + return int64Val(x) + } + if x, ok := new(big.Int).SetString(lit, 0); ok { + return intVal{x} + } + + case token.FLOAT: + if x, ok := new(big.Rat).SetString(lit); ok { + return normFloat(x) + } + + case token.IMAG: + if n := len(lit); n > 0 && lit[n-1] == 'i' { + if im, ok := new(big.Rat).SetString(lit[0 : n-1]); ok { + return normComplex(big.NewRat(0, 1), im) + } + } + + case token.CHAR: + if n := len(lit); n >= 2 { + if code, _, _, err := strconv.UnquoteChar(lit[1:n-1], '\''); err == nil { + return int64Val(code) + } + } + + case token.STRING: + if s, err := strconv.Unquote(lit); err == nil { + return stringVal(s) + } + } + + return nil +} + +// ---------------------------------------------------------------------------- +// Accessors +// +// For unknown arguments the result is the zero value for the respective +// accessor type, except for Sign, where the result is 1. + +// BoolVal returns the Go boolean value of x, which must be a Bool or an Unknown. +// If x is Unknown, the result is false. +func BoolVal(x Value) bool { + switch x := x.(type) { + case boolVal: + return bool(x) + case unknownVal: + return false + } + panic(fmt.Sprintf("%v not a Bool", x)) +} + +// StringVal returns the Go string value of x, which must be a String or an Unknown. +// If x is Unknown, the result is "". +func StringVal(x Value) string { + switch x := x.(type) { + case stringVal: + return string(x) + case unknownVal: + return "" + } + panic(fmt.Sprintf("%v not a String", x)) +} + +// Int64Val returns the Go int64 value of x and whether the result is exact; +// x must be an Int or an Unknown. If the result is not exact, its value is undefined. +// If x is Unknown, the result is (0, false). +func Int64Val(x Value) (int64, bool) { + switch x := x.(type) { + case int64Val: + return int64(x), true + case intVal: + return x.val.Int64(), x.val.BitLen() <= 63 + case unknownVal: + return 0, false + } + panic(fmt.Sprintf("%v not an Int", x)) +} + +// Uint64Val returns the Go uint64 value of x and whether the result is exact; +// x must be an Int or an Unknown. If the result is not exact, its value is undefined. +// If x is Unknown, the result is (0, false). +func Uint64Val(x Value) (uint64, bool) { + switch x := x.(type) { + case int64Val: + return uint64(x), x >= 0 + case intVal: + return x.val.Uint64(), x.val.Sign() >= 0 && x.val.BitLen() <= 64 + case unknownVal: + return 0, false + } + panic(fmt.Sprintf("%v not an Int", x)) +} + +// Float32Val is like Float64Val but for float32 instead of float64. +func Float32Val(x Value) (float32, bool) { + switch x := x.(type) { + case int64Val: + f := float32(x) + return f, int64Val(f) == x + case intVal: + return ratToFloat32(new(big.Rat).SetFrac(x.val, int1)) + case floatVal: + return ratToFloat32(x.val) + case unknownVal: + return 0, false + } + panic(fmt.Sprintf("%v not a Float", x)) +} + +// Float64Val returns the nearest Go float64 value of x and whether the result is exact; +// x must be numeric but not Complex, or Unknown. For values too small (too close to 0) +// to represent as float64, Float64Val silently underflows to 0. The result sign always +// matches the sign of x, even for 0. +// If x is Unknown, the result is (0, false). +func Float64Val(x Value) (float64, bool) { + switch x := x.(type) { + case int64Val: + f := float64(int64(x)) + return f, int64Val(f) == x + case intVal: + return new(big.Rat).SetFrac(x.val, int1).Float64() + case floatVal: + return x.val.Float64() + case unknownVal: + return 0, false + } + panic(fmt.Sprintf("%v not a Float", x)) +} + +// BitLen returns the number of bits required to represent +// the absolute value x in binary representation; x must be an Int or an Unknown. +// If x is Unknown, the result is 0. +func BitLen(x Value) int { + switch x := x.(type) { + case int64Val: + return new(big.Int).SetInt64(int64(x)).BitLen() + case intVal: + return x.val.BitLen() + case unknownVal: + return 0 + } + panic(fmt.Sprintf("%v not an Int", x)) +} + +// Sign returns -1, 0, or 1 depending on whether x < 0, x == 0, or x > 0; +// x must be numeric or Unknown. For complex values x, the sign is 0 if x == 0, +// otherwise it is != 0. If x is Unknown, the result is 1. +func Sign(x Value) int { + switch x := x.(type) { + case int64Val: + switch { + case x < 0: + return -1 + case x > 0: + return 1 + } + return 0 + case intVal: + return x.val.Sign() + case floatVal: + return x.val.Sign() + case complexVal: + return x.re.Sign() | x.im.Sign() + case unknownVal: + return 1 // avoid spurious division by zero errors + } + panic(fmt.Sprintf("%v not numeric", x)) +} + +// ---------------------------------------------------------------------------- +// Support for serializing/deserializing integers + +const ( + // Compute the size of a Word in bytes. + _m = ^big.Word(0) + _log = _m>>8&1 + _m>>16&1 + _m>>32&1 + wordSize = 1 << _log +) + +// Bytes returns the bytes for the absolute value of x in little- +// endian binary representation; x must be an Int. +func Bytes(x Value) []byte { + var val *big.Int + switch x := x.(type) { + case int64Val: + val = new(big.Int).SetInt64(int64(x)) + case intVal: + val = x.val + default: + panic(fmt.Sprintf("%v not an Int", x)) + } + + words := val.Bits() + bytes := make([]byte, len(words)*wordSize) + + i := 0 + for _, w := range words { + for j := 0; j < wordSize; j++ { + bytes[i] = byte(w) + w >>= 8 + i++ + } + } + // remove leading 0's + for i > 0 && bytes[i-1] == 0 { + i-- + } + + return bytes[:i] +} + +// MakeFromBytes returns the Int value given the bytes of its little-endian +// binary representation. An empty byte slice argument represents 0. +func MakeFromBytes(bytes []byte) Value { + words := make([]big.Word, (len(bytes)+(wordSize-1))/wordSize) + + i := 0 + var w big.Word + var s uint + for _, b := range bytes { + w |= big.Word(b) << s + if s += 8; s == wordSize*8 { + words[i] = w + i++ + w = 0 + s = 0 + } + } + // store last word + if i < len(words) { + words[i] = w + i++ + } + // remove leading 0's + for i > 0 && words[i-1] == 0 { + i-- + } + + return normInt(new(big.Int).SetBits(words[:i])) +} + +// ---------------------------------------------------------------------------- +// Support for disassembling fractions + +// Num returns the numerator of x; x must be Int, Float, or Unknown. +// If x is Unknown, the result is Unknown, otherwise it is an Int +// with the same sign as x. +func Num(x Value) Value { + switch x := x.(type) { + case unknownVal, int64Val, intVal: + return x + case floatVal: + return normInt(x.val.Num()) + } + panic(fmt.Sprintf("%v not Int or Float", x)) +} + +// Denom returns the denominator of x; x must be Int, Float, or Unknown. +// If x is Unknown, the result is Unknown, otherwise it is an Int >= 1. +func Denom(x Value) Value { + switch x := x.(type) { + case unknownVal: + return x + case int64Val, intVal: + return int64Val(1) + case floatVal: + return normInt(x.val.Denom()) + } + panic(fmt.Sprintf("%v not Int or Float", x)) +} + +// ---------------------------------------------------------------------------- +// Support for assembling/disassembling complex numbers + +// MakeImag returns the numeric value x*i (possibly 0); +// x must be Int, Float, or Unknown. +// If x is Unknown, the result is Unknown. +func MakeImag(x Value) Value { + var im *big.Rat + switch x := x.(type) { + case unknownVal: + return x + case int64Val: + im = big.NewRat(int64(x), 1) + case intVal: + im = new(big.Rat).SetFrac(x.val, int1) + case floatVal: + im = x.val + default: + panic(fmt.Sprintf("%v not Int or Float", x)) + } + return normComplex(rat0, im) +} + +// Real returns the real part of x, which must be a numeric or unknown value. +// If x is Unknown, the result is Unknown. +func Real(x Value) Value { + switch x := x.(type) { + case unknownVal, int64Val, intVal, floatVal: + return x + case complexVal: + return normFloat(x.re) + } + panic(fmt.Sprintf("%v not numeric", x)) +} + +// Imag returns the imaginary part of x, which must be a numeric or unknown value. +// If x is Unknown, the result is Unknown. +func Imag(x Value) Value { + switch x := x.(type) { + case unknownVal: + return x + case int64Val, intVal, floatVal: + return int64Val(0) + case complexVal: + return normFloat(x.im) + } + panic(fmt.Sprintf("%v not numeric", x)) +} + +// ---------------------------------------------------------------------------- +// Operations + +// is32bit reports whether x can be represented using 32 bits. +func is32bit(x int64) bool { + const s = 32 + return -1<<(s-1) <= x && x <= 1<<(s-1)-1 +} + +// is63bit reports whether x can be represented using 63 bits. +func is63bit(x int64) bool { + const s = 63 + return -1<<(s-1) <= x && x <= 1<<(s-1)-1 +} + +// UnaryOp returns the result of the unary expression op y. +// The operation must be defined for the operand. +// If prec > 0 it specifies the ^ (xor) result size in bits. +// If y is Unknown, the result is Unknown. +// +func UnaryOp(op token.Token, y Value, prec uint) Value { + switch op { + case token.ADD: + switch y.(type) { + case unknownVal, int64Val, intVal, floatVal, complexVal: + return y + } + + case token.SUB: + switch y := y.(type) { + case unknownVal: + return y + case int64Val: + if z := -y; z != y { + return z // no overflow + } + return normInt(new(big.Int).Neg(big.NewInt(int64(y)))) + case intVal: + return normInt(new(big.Int).Neg(y.val)) + case floatVal: + return normFloat(new(big.Rat).Neg(y.val)) + case complexVal: + return normComplex(new(big.Rat).Neg(y.re), new(big.Rat).Neg(y.im)) + } + + case token.XOR: + var z big.Int + switch y := y.(type) { + case unknownVal: + return y + case int64Val: + z.Not(big.NewInt(int64(y))) + case intVal: + z.Not(y.val) + default: + goto Error + } + // For unsigned types, the result will be negative and + // thus "too large": We must limit the result precision + // to the type's precision. + if prec > 0 { + z.AndNot(&z, new(big.Int).Lsh(big.NewInt(-1), prec)) // z &^= (-1)< ord(y) { + y, x = match(y, x) + return x, y + } + // ord(x) <= ord(y) + + switch x := x.(type) { + case unknownVal: + return x, x + + case boolVal, stringVal, complexVal: + return x, y + + case int64Val: + switch y := y.(type) { + case int64Val: + return x, y + case intVal: + return intVal{big.NewInt(int64(x))}, y + case floatVal: + return floatVal{big.NewRat(int64(x), 1)}, y + case complexVal: + return complexVal{big.NewRat(int64(x), 1), rat0}, y + } + + case intVal: + switch y := y.(type) { + case intVal: + return x, y + case floatVal: + return floatVal{new(big.Rat).SetFrac(x.val, int1)}, y + case complexVal: + return complexVal{new(big.Rat).SetFrac(x.val, int1), rat0}, y + } + + case floatVal: + switch y := y.(type) { + case floatVal: + return x, y + case complexVal: + return complexVal{x.val, rat0}, y + } + } + + panic("unreachable") +} + +// BinaryOp returns the result of the binary expression x op y. +// The operation must be defined for the operands. If one of the +// operands is Unknown, the result is Unknown. +// To force integer division of Int operands, use op == token.QUO_ASSIGN +// instead of token.QUO; the result is guaranteed to be Int in this case. +// Division by zero leads to a run-time panic. +// +func BinaryOp(x Value, op token.Token, y Value) Value { + x, y = match(x, y) + + switch x := x.(type) { + case unknownVal: + return x + + case boolVal: + y := y.(boolVal) + switch op { + case token.LAND: + return x && y + case token.LOR: + return x || y + } + + case int64Val: + a := int64(x) + b := int64(y.(int64Val)) + var c int64 + switch op { + case token.ADD: + if !is63bit(a) || !is63bit(b) { + return normInt(new(big.Int).Add(big.NewInt(a), big.NewInt(b))) + } + c = a + b + case token.SUB: + if !is63bit(a) || !is63bit(b) { + return normInt(new(big.Int).Sub(big.NewInt(a), big.NewInt(b))) + } + c = a - b + case token.MUL: + if !is32bit(a) || !is32bit(b) { + return normInt(new(big.Int).Mul(big.NewInt(a), big.NewInt(b))) + } + c = a * b + case token.QUO: + return normFloat(new(big.Rat).SetFrac(big.NewInt(a), big.NewInt(b))) + case token.QUO_ASSIGN: // force integer division + c = a / b + case token.REM: + c = a % b + case token.AND: + c = a & b + case token.OR: + c = a | b + case token.XOR: + c = a ^ b + case token.AND_NOT: + c = a &^ b + default: + goto Error + } + return int64Val(c) + + case intVal: + a := x.val + b := y.(intVal).val + var c big.Int + switch op { + case token.ADD: + c.Add(a, b) + case token.SUB: + c.Sub(a, b) + case token.MUL: + c.Mul(a, b) + case token.QUO: + return normFloat(new(big.Rat).SetFrac(a, b)) + case token.QUO_ASSIGN: // force integer division + c.Quo(a, b) + case token.REM: + c.Rem(a, b) + case token.AND: + c.And(a, b) + case token.OR: + c.Or(a, b) + case token.XOR: + c.Xor(a, b) + case token.AND_NOT: + c.AndNot(a, b) + default: + goto Error + } + return normInt(&c) + + case floatVal: + a := x.val + b := y.(floatVal).val + var c big.Rat + switch op { + case token.ADD: + c.Add(a, b) + case token.SUB: + c.Sub(a, b) + case token.MUL: + c.Mul(a, b) + case token.QUO: + c.Quo(a, b) + default: + goto Error + } + return normFloat(&c) + + case complexVal: + y := y.(complexVal) + a, b := x.re, x.im + c, d := y.re, y.im + var re, im big.Rat + switch op { + case token.ADD: + // (a+c) + i(b+d) + re.Add(a, c) + im.Add(b, d) + case token.SUB: + // (a-c) + i(b-d) + re.Sub(a, c) + im.Sub(b, d) + case token.MUL: + // (ac-bd) + i(bc+ad) + var ac, bd, bc, ad big.Rat + ac.Mul(a, c) + bd.Mul(b, d) + bc.Mul(b, c) + ad.Mul(a, d) + re.Sub(&ac, &bd) + im.Add(&bc, &ad) + case token.QUO: + // (ac+bd)/s + i(bc-ad)/s, with s = cc + dd + var ac, bd, bc, ad, s, cc, dd big.Rat + ac.Mul(a, c) + bd.Mul(b, d) + bc.Mul(b, c) + ad.Mul(a, d) + cc.Mul(c, c) + dd.Mul(d, d) + s.Add(&cc, &dd) + re.Add(&ac, &bd) + re.Quo(&re, &s) + im.Sub(&bc, &ad) + im.Quo(&im, &s) + default: + goto Error + } + return normComplex(&re, &im) + + case stringVal: + if op == token.ADD { + return x + y.(stringVal) + } + } + +Error: + panic(fmt.Sprintf("invalid binary operation %v %s %v", x, op, y)) +} + +// Shift returns the result of the shift expression x op s +// with op == token.SHL or token.SHR (<< or >>). x must be +// an Int or an Unknown. If x is Unknown, the result is x. +// +func Shift(x Value, op token.Token, s uint) Value { + switch x := x.(type) { + case unknownVal: + return x + + case int64Val: + if s == 0 { + return x + } + switch op { + case token.SHL: + z := big.NewInt(int64(x)) + return normInt(z.Lsh(z, s)) + case token.SHR: + return x >> s + } + + case intVal: + if s == 0 { + return x + } + var z big.Int + switch op { + case token.SHL: + return normInt(z.Lsh(x.val, s)) + case token.SHR: + return normInt(z.Rsh(x.val, s)) + } + } + + panic(fmt.Sprintf("invalid shift %v %s %d", x, op, s)) +} + +func cmpZero(x int, op token.Token) bool { + switch op { + case token.EQL: + return x == 0 + case token.NEQ: + return x != 0 + case token.LSS: + return x < 0 + case token.LEQ: + return x <= 0 + case token.GTR: + return x > 0 + case token.GEQ: + return x >= 0 + } + panic("unreachable") +} + +// Compare returns the result of the comparison x op y. +// The comparison must be defined for the operands. +// If one of the operands is Unknown, the result is +// false. +// +func Compare(x Value, op token.Token, y Value) bool { + x, y = match(x, y) + + switch x := x.(type) { + case unknownVal: + return false + + case boolVal: + y := y.(boolVal) + switch op { + case token.EQL: + return x == y + case token.NEQ: + return x != y + } + + case int64Val: + y := y.(int64Val) + switch op { + case token.EQL: + return x == y + case token.NEQ: + return x != y + case token.LSS: + return x < y + case token.LEQ: + return x <= y + case token.GTR: + return x > y + case token.GEQ: + return x >= y + } + + case intVal: + return cmpZero(x.val.Cmp(y.(intVal).val), op) + + case floatVal: + return cmpZero(x.val.Cmp(y.(floatVal).val), op) + + case complexVal: + y := y.(complexVal) + re := x.re.Cmp(y.re) + im := x.im.Cmp(y.im) + switch op { + case token.EQL: + return re == 0 && im == 0 + case token.NEQ: + return re != 0 || im != 0 + } + + case stringVal: + y := y.(stringVal) + switch op { + case token.EQL: + return x == y + case token.NEQ: + return x != y + case token.LSS: + return x < y + case token.LEQ: + return x <= y + case token.GTR: + return x > y + case token.GEQ: + return x >= y + } + } + + panic(fmt.Sprintf("invalid comparison %v %s %v", x, op, y)) +} diff --git a/libgo/go/go/constant/value_test.go b/libgo/go/go/constant/value_test.go new file mode 100644 index 00000000000..08cdd5e625c --- /dev/null +++ b/libgo/go/go/constant/value_test.go @@ -0,0 +1,375 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package constant + +import ( + "go/token" + "strings" + "testing" +) + +// TODO(gri) expand this test framework + +var opTests = []string{ + // unary operations + `+ 0 = 0`, + `+ ? = ?`, + `- 1 = -1`, + `- ? = ?`, + `^ 0 = -1`, + `^ ? = ?`, + + `! true = false`, + `! false = true`, + `! ? = ?`, + + // etc. + + // binary operations + `"" + "" = ""`, + `"foo" + "" = "foo"`, + `"" + "bar" = "bar"`, + `"foo" + "bar" = "foobar"`, + + `0 + 0 = 0`, + `0 + 0.1 = 0.1`, + `0 + 0.1i = 0.1i`, + `0.1 + 0.9 = 1`, + `1e100 + 1e100 = 2e100`, + `? + 0 = ?`, + `0 + ? = ?`, + + `0 - 0 = 0`, + `0 - 0.1 = -0.1`, + `0 - 0.1i = -0.1i`, + `1e100 - 1e100 = 0`, + `? - 0 = ?`, + `0 - ? = ?`, + + `0 * 0 = 0`, + `1 * 0.1 = 0.1`, + `1 * 0.1i = 0.1i`, + `1i * 1i = -1`, + `? * 0 = ?`, + `0 * ? = ?`, + + `0 / 0 = "division_by_zero"`, + `10 / 2 = 5`, + `5 / 3 = 5/3`, + `5i / 3i = 5/3`, + `? / 0 = ?`, + `0 / ? = ?`, + + `0 % 0 = "runtime_error:_integer_divide_by_zero"`, // TODO(gri) should be the same as for / + `10 % 3 = 1`, + `? % 0 = ?`, + `0 % ? = ?`, + + `0 & 0 = 0`, + `12345 & 0 = 0`, + `0xff & 0xf = 0xf`, + `? & 0 = ?`, + `0 & ? = ?`, + + `0 | 0 = 0`, + `12345 | 0 = 12345`, + `0xb | 0xa0 = 0xab`, + `? | 0 = ?`, + `0 | ? = ?`, + + `0 ^ 0 = 0`, + `1 ^ -1 = -2`, + `? ^ 0 = ?`, + `0 ^ ? = ?`, + + `0 &^ 0 = 0`, + `0xf &^ 1 = 0xe`, + `1 &^ 0xf = 0`, + // etc. + + // shifts + `0 << 0 = 0`, + `1 << 10 = 1024`, + `0 >> 0 = 0`, + `1024 >> 10 == 1`, + `? << 0 == ?`, + `? >> 10 == ?`, + // etc. + + // comparisons + `false == false = true`, + `false == true = false`, + `true == false = false`, + `true == true = true`, + + `false != false = false`, + `false != true = true`, + `true != false = true`, + `true != true = false`, + + `"foo" == "bar" = false`, + `"foo" != "bar" = true`, + `"foo" < "bar" = false`, + `"foo" <= "bar" = false`, + `"foo" > "bar" = true`, + `"foo" >= "bar" = true`, + + `0 == 0 = true`, + `0 != 0 = false`, + `0 < 10 = true`, + `10 <= 10 = true`, + `0 > 10 = false`, + `10 >= 10 = true`, + + `1/123456789 == 1/123456789 == true`, + `1/123456789 != 1/123456789 == false`, + `1/123456789 < 1/123456788 == true`, + `1/123456788 <= 1/123456789 == false`, + `0.11 > 0.11 = false`, + `0.11 >= 0.11 = true`, + + `? == 0 = false`, + `? != 0 = false`, + `? < 10 = false`, + `? <= 10 = false`, + `? > 10 = false`, + `? >= 10 = false`, + + `0 == ? = false`, + `0 != ? = false`, + `0 < ? = false`, + `10 <= ? = false`, + `0 > ? = false`, + `10 >= ? = false`, + + // etc. +} + +func TestOps(t *testing.T) { + for _, test := range opTests { + a := strings.Split(test, " ") + i := 0 // operator index + + var x, x0 Value + switch len(a) { + case 4: + // unary operation + case 5: + // binary operation + x, x0 = val(a[0]), val(a[0]) + i = 1 + default: + t.Errorf("invalid test case: %s", test) + continue + } + + op, ok := optab[a[i]] + if !ok { + panic("missing optab entry for " + a[i]) + } + + y, y0 := val(a[i+1]), val(a[i+1]) + + got := doOp(x, op, y) + want := val(a[i+3]) + if !eql(got, want) { + t.Errorf("%s: got %s; want %s", test, got, want) + } + if x0 != nil && !eql(x, x0) { + t.Errorf("%s: x changed to %s", test, x) + } + if !eql(y, y0) { + t.Errorf("%s: y changed to %s", test, y) + } + } +} + +func eql(x, y Value) bool { + _, ux := x.(unknownVal) + _, uy := y.(unknownVal) + if ux || uy { + return ux == uy + } + return Compare(x, token.EQL, y) +} + +// ---------------------------------------------------------------------------- +// Support functions + +func val(lit string) Value { + if len(lit) == 0 { + return MakeUnknown() + } + + switch lit { + case "?": + return MakeUnknown() + case "true": + return MakeBool(true) + case "false": + return MakeBool(false) + } + + tok := token.INT + switch first, last := lit[0], lit[len(lit)-1]; { + case first == '"' || first == '`': + tok = token.STRING + lit = strings.Replace(lit, "_", " ", -1) + case first == '\'': + tok = token.CHAR + case last == 'i': + tok = token.IMAG + default: + if !strings.HasPrefix(lit, "0x") && strings.ContainsAny(lit, "./Ee") { + tok = token.FLOAT + } + } + + return MakeFromLiteral(lit, tok, 0) +} + +var optab = map[string]token.Token{ + "!": token.NOT, + + "+": token.ADD, + "-": token.SUB, + "*": token.MUL, + "/": token.QUO, + "%": token.REM, + + "<<": token.SHL, + ">>": token.SHR, + + "&": token.AND, + "|": token.OR, + "^": token.XOR, + "&^": token.AND_NOT, + + "==": token.EQL, + "!=": token.NEQ, + "<": token.LSS, + "<=": token.LEQ, + ">": token.GTR, + ">=": token.GEQ, +} + +func panicHandler(v *Value) { + switch p := recover().(type) { + case nil: + // nothing to do + case string: + *v = MakeString(p) + case error: + *v = MakeString(p.Error()) + default: + panic(p) + } +} + +func doOp(x Value, op token.Token, y Value) (z Value) { + defer panicHandler(&z) + + if x == nil { + return UnaryOp(op, y, 0) + } + + switch op { + case token.EQL, token.NEQ, token.LSS, token.LEQ, token.GTR, token.GEQ: + return MakeBool(Compare(x, op, y)) + case token.SHL, token.SHR: + s, _ := Int64Val(y) + return Shift(x, op, uint(s)) + default: + return BinaryOp(x, op, y) + } +} + +// ---------------------------------------------------------------------------- +// Other tests + +var fracTests = []string{ + "0 0 1", + "1 1 1", + "-1 -1 1", + "1.2 6 5", + "-0.991 -991 1000", + "1e100 1e100 1", +} + +func TestFractions(t *testing.T) { + for _, test := range fracTests { + a := strings.Split(test, " ") + if len(a) != 3 { + t.Errorf("invalid test case: %s", test) + continue + } + + x := val(a[0]) + n := val(a[1]) + d := val(a[2]) + + if got := Num(x); !eql(got, n) { + t.Errorf("%s: got num = %s; want %s", test, got, n) + } + + if got := Denom(x); !eql(got, d) { + t.Errorf("%s: got denom = %s; want %s", test, got, d) + } + } +} + +var bytesTests = []string{ + "0", + "1", + "123456789", + "123456789012345678901234567890123456789012345678901234567890", +} + +func TestBytes(t *testing.T) { + for _, test := range bytesTests { + x := val(test) + bytes := Bytes(x) + + // special case 0 + if Sign(x) == 0 && len(bytes) != 0 { + t.Errorf("%s: got %v; want empty byte slice", test, bytes) + } + + if n := len(bytes); n > 0 && bytes[n-1] == 0 { + t.Errorf("%s: got %v; want no leading 0 byte", test, bytes) + } + + if got := MakeFromBytes(bytes); !eql(got, x) { + t.Errorf("%s: got %s; want %s (bytes = %v)", test, got, x, bytes) + } + } +} + +func TestUnknown(t *testing.T) { + u := MakeUnknown() + var values = []Value{ + u, + MakeBool(false), // token.ADD ok below, operation is never considered + MakeString(""), + MakeInt64(1), + MakeFromLiteral("-1234567890123456789012345678901234567890", token.INT, 0), + MakeFloat64(1.2), + MakeImag(MakeFloat64(1.2)), + } + for _, val := range values { + x, y := val, u + for i := range [2]int{} { + if i == 1 { + x, y = y, x + } + if got := BinaryOp(x, token.ADD, y); got.Kind() != Unknown { + t.Errorf("%s + %s: got %s; want %s", x, y, got, u) + } + if got := Compare(x, token.EQL, y); got { + t.Errorf("%s == %s: got true; want false", x, y) + } + } + } +} diff --git a/libgo/go/go/doc/doc.go b/libgo/go/go/doc/doc.go index 4264940a0cd..3c3e28d48fb 100644 --- a/libgo/go/go/doc/doc.go +++ b/libgo/go/go/doc/doc.go @@ -18,7 +18,8 @@ type Package struct { Imports []string Filenames []string Notes map[string][]*Note - // DEPRECATED. For backward compatibility Bugs is still populated, + + // Deprecated: For backward compatibility Bugs is still populated, // but all new code should use Notes instead. Bugs []string diff --git a/libgo/go/go/doc/exports.go b/libgo/go/go/doc/exports.go index 1d3b466d8c7..4a12b1e55f8 100644 --- a/libgo/go/go/doc/exports.go +++ b/libgo/go/go/doc/exports.go @@ -12,13 +12,12 @@ import ( ) // filterIdentList removes unexported names from list in place -// and returns the resulting list. If blankOk is set, blank -// identifiers are considered exported names. +// and returns the resulting list. // -func filterIdentList(list []*ast.Ident, blankOk bool) []*ast.Ident { +func filterIdentList(list []*ast.Ident) []*ast.Ident { j := 0 for _, x := range list { - if ast.IsExported(x.Name) || (blankOk && x.Name == "_") { + if ast.IsExported(x.Name) { list[j] = x j++ } @@ -26,6 +25,17 @@ func filterIdentList(list []*ast.Ident, blankOk bool) []*ast.Ident { return list[0:j] } +// hasExportedName reports whether list contains any exported names. +// +func hasExportedName(list []*ast.Ident) bool { + for _, x := range list { + if x.IsExported() { + return true + } + } + return false +} + // removeErrorField removes anonymous fields named "error" from an interface. // This is called when "error" has been determined to be a local name, // not the predeclared type. @@ -53,7 +63,7 @@ func removeErrorField(ityp *ast.InterfaceType) { } // filterFieldList removes unexported fields (field names) from the field list -// in place and returns true if fields were removed. Anonymous fields are +// in place and reports whether fields were removed. Anonymous fields are // recorded with the parent type. filterType is called with the types of // all remaining fields. // @@ -78,7 +88,7 @@ func (r *reader) filterFieldList(parent *namedType, fields *ast.FieldList, ityp r.remember(ityp) } } else { - field.Names = filterIdentList(field.Names, false) + field.Names = filterIdentList(field.Names) if len(field.Names) < n { removedFields = true } @@ -146,9 +156,7 @@ func (r *reader) filterSpec(spec ast.Spec, tok token.Token) bool { // always keep imports so we can collect them return true case *ast.ValueSpec: - // special case: consider blank constants as exported - // (work-around for issue 5397) - s.Names = filterIdentList(s.Names, tok == token.CONST) + s.Names = filterIdentList(s.Names) if len(s.Names) > 0 { r.filterType(nil, s.Type) return true @@ -165,7 +173,46 @@ func (r *reader) filterSpec(spec ast.Spec, tok token.Token) bool { return false } +// copyConstType returns a copy of typ with position pos. +// typ must be a valid constant type. +// In practice, only (possibly qualified) identifiers are possible. +// +func copyConstType(typ ast.Expr, pos token.Pos) ast.Expr { + switch typ := typ.(type) { + case *ast.Ident: + return &ast.Ident{Name: typ.Name, NamePos: pos} + case *ast.SelectorExpr: + if id, ok := typ.X.(*ast.Ident); ok { + // presumably a qualified identifier + return &ast.SelectorExpr{ + Sel: ast.NewIdent(typ.Sel.Name), + X: &ast.Ident{Name: id.Name, NamePos: pos}, + } + } + } + return nil // shouldn't happen, but be conservative and don't panic +} + func (r *reader) filterSpecList(list []ast.Spec, tok token.Token) []ast.Spec { + if tok == token.CONST { + // Propagate any type information that would get lost otherwise + // when unexported constants are filtered. + var prevType ast.Expr + for _, spec := range list { + spec := spec.(*ast.ValueSpec) + if spec.Type == nil && prevType != nil { + // provide current spec with an explicit type + spec.Type = copyConstType(prevType, spec.Pos()) + } + if hasExportedName(spec.Names) { + // exported names are preserved so there's no need to propagate the type + prevType = nil + } else { + prevType = spec.Type + } + } + } + j := 0 for _, s := range list { if r.filterSpec(s, tok) { diff --git a/libgo/go/go/doc/testdata/blank.0.golden b/libgo/go/go/doc/testdata/blank.0.golden index dae3ab2affa..c2987cf140e 100644 --- a/libgo/go/go/doc/testdata/blank.0.golden +++ b/libgo/go/go/doc/testdata/blank.0.golden @@ -4,14 +4,33 @@ PACKAGE blank IMPORTPATH testdata/blank +IMPORTS + os + FILENAMES testdata/blank.go CONSTANTS + // T constants counting from unexported constants. + const ( + C1 T + C2 + + C3 + + C4 int + ) + + // Constants with an imported type that needs to be propagated. + const ( + Default os.FileMode = 0644 + Useless = 0312 + WideOpen = 0777 + ) + // Package constants. const ( - _ int = iota - I1 + I1 int I2 ) @@ -28,10 +47,9 @@ TYPES // type T int - // T constants. + // T constants counting from a blank constant. const ( - _ T = iota - T1 + T1 T T2 ) diff --git a/libgo/go/go/doc/testdata/blank.1.golden b/libgo/go/go/doc/testdata/blank.1.golden index 333d7e5b040..ee5054a4ed6 100644 --- a/libgo/go/go/doc/testdata/blank.1.golden +++ b/libgo/go/go/doc/testdata/blank.1.golden @@ -4,10 +4,25 @@ PACKAGE blank IMPORTPATH testdata/blank +IMPORTS + os + FILENAMES testdata/blank.go CONSTANTS + // T constants counting from unexported constants. + const ( + tweedledee T = iota + tweedledum + C1 + C2 + alice + C3 + redQueen int = iota + C4 + ) + // Package constants. const ( _ int = iota @@ -15,6 +30,20 @@ CONSTANTS I2 ) + // Constants with an imported type that needs to be propagated. + const ( + zero os.FileMode = 0 + Default = 0644 + Useless = 0312 + WideOpen = 0777 + ) + + // Unexported constants counting from blank iota. See issue 9615. + const ( + _ = iota + one = iota + 1 + ) + VARIABLES // @@ -37,7 +66,7 @@ TYPES // type T int - // T constants. + // T constants counting from a blank constant. const ( _ T = iota T1 diff --git a/libgo/go/go/doc/testdata/blank.2.golden b/libgo/go/go/doc/testdata/blank.2.golden index dae3ab2affa..c2987cf140e 100644 --- a/libgo/go/go/doc/testdata/blank.2.golden +++ b/libgo/go/go/doc/testdata/blank.2.golden @@ -4,14 +4,33 @@ PACKAGE blank IMPORTPATH testdata/blank +IMPORTS + os + FILENAMES testdata/blank.go CONSTANTS + // T constants counting from unexported constants. + const ( + C1 T + C2 + + C3 + + C4 int + ) + + // Constants with an imported type that needs to be propagated. + const ( + Default os.FileMode = 0644 + Useless = 0312 + WideOpen = 0777 + ) + // Package constants. const ( - _ int = iota - I1 + I1 int I2 ) @@ -28,10 +47,9 @@ TYPES // type T int - // T constants. + // T constants counting from a blank constant. const ( - _ T = iota - T1 + T1 T T2 ) diff --git a/libgo/go/go/doc/testdata/blank.go b/libgo/go/go/doc/testdata/blank.go index f812c77b777..419a78f7d51 100644 --- a/libgo/go/go/doc/testdata/blank.go +++ b/libgo/go/go/doc/testdata/blank.go @@ -6,15 +6,37 @@ // See issue 5397. package blank +import "os" + type T int -// T constants. +// T constants counting from a blank constant. const ( _ T = iota T1 T2 ) +// T constants counting from unexported constants. +const ( + tweedledee T = iota + tweedledum + C1 + C2 + alice + C3 + redQueen int = iota + C4 +) + +// Constants with an imported type that needs to be propagated. +const ( + zero os.FileMode = 0 + Default = 0644 + Useless = 0312 + WideOpen = 0777 +) + // Package constants. const ( _ int = iota @@ -22,6 +44,13 @@ const ( I2 ) +// Unexported constants counting from blank iota. +// See issue 9615. +const ( + _ = iota + one = iota + 1 +) + // Blanks not in doc output: // S has a padding field. diff --git a/libgo/go/go/format/format.go b/libgo/go/go/format/format.go index 668a42df2df..1adfd7d45e8 100644 --- a/libgo/go/go/format/format.go +++ b/libgo/go/go/format/format.go @@ -12,8 +12,8 @@ import ( "go/parser" "go/printer" "go/token" + "internal/format" "io" - "strings" ) var config = printer.Config{Mode: printer.UseSpaces | printer.TabIndent, Tabwidth: 8} @@ -82,7 +82,7 @@ func Node(dst io.Writer, fset *token.FileSet, node interface{}) error { // func Source(src []byte) ([]byte, error) { fset := token.NewFileSet() - file, sourceAdj, indentAdj, err := parse(fset, "", src, true) + file, sourceAdj, indentAdj, err := format.Parse(fset, "", src, true) if err != nil { return nil, err } @@ -93,7 +93,7 @@ func Source(src []byte) ([]byte, error) { ast.SortImports(fset, file) } - return format(fset, file, sourceAdj, indentAdj, src, config) + return format.Format(fset, file, sourceAdj, indentAdj, src, config) } func hasUnsortedImports(file *ast.File) bool { @@ -113,154 +113,3 @@ func hasUnsortedImports(file *ast.File) bool { } return false } - -// ---------------------------------------------------------------------------- -// Support functions -// -// The functions parse, format, and isSpace below are identical to the -// respective functions in cmd/gofmt/gofmt.go - keep them in sync! -// -// TODO(gri) Factor out this functionality, eventually. - -// parse parses src, which was read from the named file, -// as a Go source file, declaration, or statement list. -func parse(fset *token.FileSet, filename string, src []byte, fragmentOk bool) ( - file *ast.File, - sourceAdj func(src []byte, indent int) []byte, - indentAdj int, - err error, -) { - // Try as whole source file. - file, err = parser.ParseFile(fset, filename, src, parserMode) - // If there's no error, return. If the error is that the source file didn't begin with a - // package line and source fragments are ok, fall through to - // try as a source fragment. Stop and return on any other error. - if err == nil || !fragmentOk || !strings.Contains(err.Error(), "expected 'package'") { - return - } - - // If this is a declaration list, make it a source file - // by inserting a package clause. - // Insert using a ;, not a newline, so that the line numbers - // in psrc match the ones in src. - psrc := append([]byte("package p;"), src...) - file, err = parser.ParseFile(fset, filename, psrc, parserMode) - if err == nil { - sourceAdj = func(src []byte, indent int) []byte { - // Remove the package clause. - // Gofmt has turned the ; into a \n. - src = src[indent+len("package p\n"):] - return bytes.TrimSpace(src) - } - return - } - // If the error is that the source file didn't begin with a - // declaration, fall through to try as a statement list. - // Stop and return on any other error. - if !strings.Contains(err.Error(), "expected declaration") { - return - } - - // If this is a statement list, make it a source file - // by inserting a package clause and turning the list - // into a function body. This handles expressions too. - // Insert using a ;, not a newline, so that the line numbers - // in fsrc match the ones in src. - fsrc := append(append([]byte("package p; func _() {"), src...), '\n', '}') - file, err = parser.ParseFile(fset, filename, fsrc, parserMode) - if err == nil { - sourceAdj = func(src []byte, indent int) []byte { - // Cap adjusted indent to zero. - if indent < 0 { - indent = 0 - } - // Remove the wrapping. - // Gofmt has turned the ; into a \n\n. - // There will be two non-blank lines with indent, hence 2*indent. - src = src[2*indent+len("package p\n\nfunc _() {"):] - src = src[:len(src)-(indent+len("\n}\n"))] - return bytes.TrimSpace(src) - } - // Gofmt has also indented the function body one level. - // Adjust that with indentAdj. - indentAdj = -1 - } - - // Succeeded, or out of options. - return -} - -// format formats the given package file originally obtained from src -// and adjusts the result based on the original source via sourceAdj -// and indentAdj. -func format( - fset *token.FileSet, - file *ast.File, - sourceAdj func(src []byte, indent int) []byte, - indentAdj int, - src []byte, - cfg printer.Config, -) ([]byte, error) { - if sourceAdj == nil { - // Complete source file. - var buf bytes.Buffer - err := cfg.Fprint(&buf, fset, file) - if err != nil { - return nil, err - } - return buf.Bytes(), nil - } - - // Partial source file. - // Determine and prepend leading space. - i, j := 0, 0 - for j < len(src) && isSpace(src[j]) { - if src[j] == '\n' { - i = j + 1 // byte offset of last line in leading space - } - j++ - } - var res []byte - res = append(res, src[:i]...) - - // Determine and prepend indentation of first code line. - // Spaces are ignored unless there are no tabs, - // in which case spaces count as one tab. - indent := 0 - hasSpace := false - for _, b := range src[i:j] { - switch b { - case ' ': - hasSpace = true - case '\t': - indent++ - } - } - if indent == 0 && hasSpace { - indent = 1 - } - for i := 0; i < indent; i++ { - res = append(res, '\t') - } - - // Format the source. - // Write it without any leading and trailing space. - cfg.Indent = indent + indentAdj - var buf bytes.Buffer - err := cfg.Fprint(&buf, fset, file) - if err != nil { - return nil, err - } - res = append(res, sourceAdj(buf.Bytes(), cfg.Indent)...) - - // Determine and append trailing space. - i = len(src) - for i > 0 && isSpace(src[i-1]) { - i-- - } - return append(res, src[i:]...), nil -} - -func isSpace(b byte) bool { - return b == ' ' || b == '\t' || b == '\n' || b == '\r' -} diff --git a/libgo/go/go/format/format_test.go b/libgo/go/go/format/format_test.go index d7846bec652..000c611aa25 100644 --- a/libgo/go/go/format/format_test.go +++ b/libgo/go/go/format/format_test.go @@ -91,7 +91,11 @@ var tests = []string{ "\n\t\t\n\n\t\t\tx := 0\n\t\t\tconst s = `\n\t\tfoo\n`\n\n\n", // no indentation removed inside raw strings // comments - "i := 5 /* Comment */", // Issue 5551. + "i := 5 /* Comment */", // Issue 5551. + "\ta()\n//line :1", // Issue 11276. + "\t//xxx\n\ta()\n//line :2", // Issue 11276. + "\ta() //line :1\n\tb()\n", // Issue 11276. + "x := 0\n//line :1\n//line :2", // Issue 11276. // erroneous programs "ERROR1 + 2 +", diff --git a/libgo/go/go/importer/importer.go b/libgo/go/go/importer/importer.go new file mode 100644 index 00000000000..4590ca30e60 --- /dev/null +++ b/libgo/go/go/importer/importer.go @@ -0,0 +1,69 @@ +// Copyright 2015 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 importer provides access to export data importers. +package importer + +import ( + "go/internal/gccgoimporter" + "go/internal/gcimporter" + "go/types" + "io" + "runtime" +) + +// A Lookup function returns a reader to access package data for +// a given import path, or an error if no matching package is found. +type Lookup func(path string) (io.ReadCloser, error) + +// For returns an Importer for the given compiler and lookup interface, +// or nil. Supported compilers are "gc", and "gccgo". If lookup is nil, +// the default package lookup mechanism for the given compiler is used. +func For(compiler string, lookup Lookup) types.Importer { + switch compiler { + case "gc": + if lookup == nil { + return make(gcimports) + } + panic("gc importer for custom import path lookup not yet implemented") + case "gccgo": + if lookup == nil { + var inst gccgoimporter.GccgoInstallation + if err := inst.InitFromDriver("gccgo"); err != nil { + return nil + } + return &gccgoimports{ + packages: make(map[string]*types.Package), + importer: inst.GetImporter(nil, nil), + } + } + panic("gccgo importer for custom import path lookup not yet implemented") + } + // compiler not supported + return nil +} + +// Default returns an Importer for the compiler that built the running binary. +func Default() types.Importer { + return For(runtime.Compiler, nil) +} + +// gc support + +type gcimports map[string]*types.Package + +func (m gcimports) Import(path string) (*types.Package, error) { + return gcimporter.Import(m, path) +} + +// gccgo support + +type gccgoimports struct { + packages map[string]*types.Package + importer gccgoimporter.Importer +} + +func (m *gccgoimports) Import(path string) (*types.Package, error) { + return m.importer(m.packages, path) +} diff --git a/libgo/go/go/internal/gccgoimporter/gccgoinstallation.go b/libgo/go/go/internal/gccgoimporter/gccgoinstallation.go new file mode 100644 index 00000000000..622dfc8b696 --- /dev/null +++ b/libgo/go/go/internal/gccgoimporter/gccgoinstallation.go @@ -0,0 +1,94 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package gccgoimporter + +import ( + "bufio" + "go/types" + "os" + "os/exec" + "path/filepath" + "strings" +) + +// Information about a specific installation of gccgo. +type GccgoInstallation struct { + // Version of gcc (e.g. 4.8.0). + GccVersion string + + // Target triple (e.g. x86_64-unknown-linux-gnu). + TargetTriple string + + // Built-in library paths used by this installation. + LibPaths []string +} + +// Ask the driver at the given path for information for this GccgoInstallation. +func (inst *GccgoInstallation) InitFromDriver(gccgoPath string) (err error) { + cmd := exec.Command(gccgoPath, "-###", "-S", "-x", "go", "-") + stderr, err := cmd.StderrPipe() + if err != nil { + return + } + + err = cmd.Start() + if err != nil { + return + } + + scanner := bufio.NewScanner(stderr) + for scanner.Scan() { + line := scanner.Text() + switch { + case strings.HasPrefix(line, "Target: "): + inst.TargetTriple = line[8:] + + case line[0] == ' ': + args := strings.Fields(line) + for _, arg := range args[1:] { + if strings.HasPrefix(arg, "-L") { + inst.LibPaths = append(inst.LibPaths, arg[2:]) + } + } + } + } + + stdout, err := exec.Command(gccgoPath, "-dumpversion").Output() + if err != nil { + return + } + inst.GccVersion = strings.TrimSpace(string(stdout)) + + return +} + +// Return the list of export search paths for this GccgoInstallation. +func (inst *GccgoInstallation) SearchPaths() (paths []string) { + for _, lpath := range inst.LibPaths { + spath := filepath.Join(lpath, "go", inst.GccVersion) + fi, err := os.Stat(spath) + if err != nil || !fi.IsDir() { + continue + } + paths = append(paths, spath) + + spath = filepath.Join(spath, inst.TargetTriple) + fi, err = os.Stat(spath) + if err != nil || !fi.IsDir() { + continue + } + paths = append(paths, spath) + } + + paths = append(paths, inst.LibPaths...) + + return +} + +// Return an importer that searches incpaths followed by the gcc installation's +// built-in search paths and the current directory. +func (inst *GccgoInstallation) GetImporter(incpaths []string, initmap map[*types.Package]InitData) Importer { + return GetImporter(append(append(incpaths, inst.SearchPaths()...), "."), initmap) +} diff --git a/libgo/go/go/internal/gccgoimporter/gccgoinstallation_test.go b/libgo/go/go/internal/gccgoimporter/gccgoinstallation_test.go new file mode 100644 index 00000000000..a2acaf7331a --- /dev/null +++ b/libgo/go/go/internal/gccgoimporter/gccgoinstallation_test.go @@ -0,0 +1,197 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package gccgoimporter + +import ( + "go/types" + "runtime" + "testing" +) + +var importablePackages = [...]string{ + "archive/tar", + "archive/zip", + "bufio", + "bytes", + "compress/bzip2", + "compress/flate", + "compress/gzip", + "compress/lzw", + "compress/zlib", + "container/heap", + "container/list", + "container/ring", + "crypto/aes", + "crypto/cipher", + "crypto/des", + "crypto/dsa", + "crypto/ecdsa", + "crypto/elliptic", + "crypto", + "crypto/hmac", + "crypto/md5", + "crypto/rand", + "crypto/rc4", + "crypto/rsa", + "crypto/sha1", + "crypto/sha256", + "crypto/sha512", + "crypto/subtle", + "crypto/tls", + "crypto/x509", + "crypto/x509/pkix", + "database/sql/driver", + "database/sql", + "debug/dwarf", + "debug/elf", + "debug/gosym", + "debug/macho", + "debug/pe", + "encoding/ascii85", + "encoding/asn1", + "encoding/base32", + "encoding/base64", + "encoding/binary", + "encoding/csv", + "encoding/gob", + "encoding", + "encoding/hex", + "encoding/json", + "encoding/pem", + "encoding/xml", + "errors", + "exp/proxy", + "exp/terminal", + "expvar", + "flag", + "fmt", + "go/ast", + "go/build", + "go/doc", + "go/format", + "go/parser", + "go/printer", + "go/scanner", + "go/token", + "hash/adler32", + "hash/crc32", + "hash/crc64", + "hash/fnv", + "hash", + "html", + "html/template", + "image/color", + "image/color/palette", + "image/draw", + "image/gif", + "image", + "image/jpeg", + "image/png", + "index/suffixarray", + "io", + "io/ioutil", + "log", + "log/syslog", + "math/big", + "math/cmplx", + "math", + "math/rand", + "mime", + "mime/multipart", + "net", + "net/http/cgi", + "net/http/cookiejar", + "net/http/fcgi", + "net/http", + "net/http/httptest", + "net/http/httputil", + "net/http/pprof", + "net/mail", + "net/rpc", + "net/rpc/jsonrpc", + "net/smtp", + "net/textproto", + "net/url", + "old/regexp", + "old/template", + "os/exec", + "os", + "os/signal", + "os/user", + "path/filepath", + "path", + "reflect", + "regexp", + "regexp/syntax", + "runtime/debug", + "runtime", + "runtime/pprof", + "sort", + "strconv", + "strings", + "sync/atomic", + "sync", + "syscall", + "testing", + "testing/iotest", + "testing/quick", + "text/scanner", + "text/tabwriter", + "text/template", + "text/template/parse", + "time", + "unicode", + "unicode/utf16", + "unicode/utf8", +} + +func TestInstallationImporter(t *testing.T) { + // This test relies on gccgo being around, which it most likely will be if we + // were compiled with gccgo. + if runtime.Compiler != "gccgo" { + t.Skip("This test needs gccgo") + return + } + + // Even when we have gccgo, this doesn't work while building + // gccgo itself. + t.Skip("gccgo is not necessarily available") + + var inst GccgoInstallation + err := inst.InitFromDriver("gccgo") + if err != nil { + t.Fatal(err) + } + imp := inst.GetImporter(nil, nil) + + // Ensure we don't regress the number of packages we can parse. First import + // all packages into the same map and then each individually. + pkgMap := make(map[string]*types.Package) + for _, pkg := range importablePackages { + _, err = imp(pkgMap, pkg) + if err != nil { + t.Error(err) + } + } + + for _, pkg := range importablePackages { + _, err = imp(make(map[string]*types.Package), pkg) + if err != nil { + t.Error(err) + } + } + + // Test for certain specific entities in the imported data. + for _, test := range [...]importerTest{ + {pkgpath: "io", name: "Reader", want: "type Reader interface{Read(p []uint8) (n int, err error)}"}, + {pkgpath: "io", name: "ReadWriter", want: "type ReadWriter interface{Reader; Writer}"}, + {pkgpath: "math", name: "Pi", want: "const Pi untyped float"}, + {pkgpath: "math", name: "Sin", want: "func Sin(x float64) float64"}, + {pkgpath: "sort", name: "Ints", want: "func Ints(a []int)"}, + {pkgpath: "unsafe", name: "Pointer", want: "type Pointer unsafe.Pointer"}, + } { + runImporterTest(t, imp, nil, &test) + } +} diff --git a/libgo/go/go/internal/gccgoimporter/importer.go b/libgo/go/go/internal/gccgoimporter/importer.go new file mode 100644 index 00000000000..aa0d01afdf3 --- /dev/null +++ b/libgo/go/go/internal/gccgoimporter/importer.go @@ -0,0 +1,212 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package gccgoimporter implements Import for gccgo-generated object files. +package gccgoimporter // import "go/internal/gccgoimporter" + +import ( + "bytes" + "debug/elf" + "fmt" + "go/types" + "io" + "os" + "os/exec" + "path/filepath" + "strings" +) + +// A PackageInit describes an imported package that needs initialization. +type PackageInit struct { + Name string // short package name + InitFunc string // name of init function + Priority int // priority of init function, see InitData.Priority +} + +// The gccgo-specific init data for a package. +type InitData struct { + // Initialization priority of this package relative to other packages. + // This is based on the maximum depth of the package's dependency graph; + // it is guaranteed to be greater than that of its dependencies. + Priority int + + // The list of packages which this package depends on to be initialized, + // including itself if needed. This is the subset of the transitive closure of + // the package's dependencies that need initialization. + Inits []PackageInit +} + +// Locate the file from which to read export data. +// This is intended to replicate the logic in gofrontend. +func findExportFile(searchpaths []string, pkgpath string) (string, error) { + for _, spath := range searchpaths { + pkgfullpath := filepath.Join(spath, pkgpath) + pkgdir, name := filepath.Split(pkgfullpath) + + for _, filepath := range [...]string{ + pkgfullpath, + pkgfullpath + ".gox", + pkgdir + "lib" + name + ".so", + pkgdir + "lib" + name + ".a", + pkgfullpath + ".o", + } { + fi, err := os.Stat(filepath) + if err == nil && !fi.IsDir() { + return filepath, nil + } + } + } + + return "", fmt.Errorf("%s: could not find export data (tried %s)", pkgpath, strings.Join(searchpaths, ":")) +} + +const ( + gccgov1Magic = "v1;\n" + goimporterMagic = "\n$$ " + archiveMagic = "! 0 { + initdata := initmap[pkg] + found := false + // Check that the package's own init function has the package's priority + for _, pkginit := range initdata.Inits { + if pkginit.InitFunc == test.wantinits[0] { + if initdata.Priority != pkginit.Priority { + t.Errorf("%s: got self priority %d; want %d", test.pkgpath, pkginit.Priority, initdata.Priority) + } + found = true + break + } + } + + if !found { + t.Errorf("%s: could not find expected function %q", test.pkgpath, test.wantinits[0]) + } + + // Each init function in the list other than the first one is a + // dependency of the function immediately before it. Check that + // the init functions appear in descending priority order. + priority := initdata.Priority + for _, wantdepinit := range test.wantinits[1:] { + found = false + for _, pkginit := range initdata.Inits { + if pkginit.InitFunc == wantdepinit { + if priority <= pkginit.Priority { + t.Errorf("%s: got dep priority %d; want less than %d", test.pkgpath, pkginit.Priority, priority) + } + found = true + priority = pkginit.Priority + break + } + } + + if !found { + t.Errorf("%s: could not find expected function %q", test.pkgpath, wantdepinit) + } + } + } +} + +var importerTests = [...]importerTest{ + {pkgpath: "pointer", name: "Int8Ptr", want: "type Int8Ptr *int8"}, + {pkgpath: "complexnums", name: "NN", want: "const NN untyped complex", wantval: "(-1/1 + -1/1i)"}, + {pkgpath: "complexnums", name: "NP", want: "const NP untyped complex", wantval: "(-1/1 + 1/1i)"}, + {pkgpath: "complexnums", name: "PN", want: "const PN untyped complex", wantval: "(1/1 + -1/1i)"}, + {pkgpath: "complexnums", name: "PP", want: "const PP untyped complex", wantval: "(1/1 + 1/1i)"}, + // TODO: enable this entry once bug has been tracked down + //{pkgpath: "imports", wantinits: []string{"imports..import", "fmt..import", "math..import"}}, +} + +func TestGoxImporter(t *testing.T) { + testenv.MustHaveGoBuild(t) + + initmap := make(map[*types.Package]InitData) + imp := GetImporter([]string{"testdata"}, initmap) + + for _, test := range importerTests { + runImporterTest(t, imp, initmap, &test) + } +} + +func TestObjImporter(t *testing.T) { + testenv.MustHaveGoBuild(t) + + // This test relies on gccgo being around, which it most likely will be if we + // were compiled with gccgo. + if runtime.Compiler != "gccgo" { + t.Skip("This test needs gccgo") + return + } + + tmpdir, err := ioutil.TempDir("", "") + if err != nil { + t.Fatal(err) + } + initmap := make(map[*types.Package]InitData) + imp := GetImporter([]string{tmpdir}, initmap) + + artmpdir, err := ioutil.TempDir("", "") + if err != nil { + t.Fatal(err) + } + arinitmap := make(map[*types.Package]InitData) + arimp := GetImporter([]string{artmpdir}, arinitmap) + + for _, test := range importerTests { + gofile := filepath.Join("testdata", test.pkgpath+".go") + ofile := filepath.Join(tmpdir, test.pkgpath+".o") + afile := filepath.Join(artmpdir, "lib"+test.pkgpath+".a") + + cmd := exec.Command("gccgo", "-fgo-pkgpath="+test.pkgpath, "-c", "-o", ofile, gofile) + out, err := cmd.CombinedOutput() + if err != nil { + t.Logf("%s", out) + t.Fatalf("gccgo %s failed: %s", gofile, err) + } + + runImporterTest(t, imp, initmap, &test) + + cmd = exec.Command("ar", "cr", afile, ofile) + out, err = cmd.CombinedOutput() + if err != nil { + t.Logf("%s", out) + t.Fatalf("ar cr %s %s failed: %s", afile, ofile, err) + } + + runImporterTest(t, arimp, arinitmap, &test) + + if err = os.Remove(ofile); err != nil { + t.Fatal(err) + } + if err = os.Remove(afile); err != nil { + t.Fatal(err) + } + } + + if err = os.Remove(tmpdir); err != nil { + t.Fatal(err) + } +} diff --git a/libgo/go/go/internal/gccgoimporter/parser.go b/libgo/go/go/internal/gccgoimporter/parser.go new file mode 100644 index 00000000000..c06cce435b1 --- /dev/null +++ b/libgo/go/go/internal/gccgoimporter/parser.go @@ -0,0 +1,855 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package gccgoimporter + +import ( + "bytes" + "errors" + "fmt" + "go/constant" + "go/token" + "go/types" + "io" + "strconv" + "strings" + "text/scanner" +) + +type parser struct { + scanner scanner.Scanner + tok rune // current token + lit string // literal string; only valid for Ident, Int, String tokens + pkgpath string // package path of imported package + pkgname string // name of imported package + pkg *types.Package // reference to imported package + imports map[string]*types.Package // package path -> package object + typeMap map[int]types.Type // type number -> type + initdata InitData // package init priority data +} + +func (p *parser) init(filename string, src io.Reader, imports map[string]*types.Package) { + p.scanner.Init(src) + p.scanner.Error = func(_ *scanner.Scanner, msg string) { p.error(msg) } + p.scanner.Mode = scanner.ScanIdents | scanner.ScanInts | scanner.ScanFloats | scanner.ScanStrings | scanner.ScanComments | scanner.SkipComments + p.scanner.Whitespace = 1<<'\t' | 1<<'\n' | 1<<' ' + p.scanner.Filename = filename // for good error messages + p.next() + p.imports = imports + p.typeMap = make(map[int]types.Type) +} + +type importError struct { + pos scanner.Position + err error +} + +func (e importError) Error() string { + return fmt.Sprintf("import error %s (byte offset = %d): %s", e.pos, e.pos.Offset, e.err) +} + +func (p *parser) error(err interface{}) { + if s, ok := err.(string); ok { + err = errors.New(s) + } + // panic with a runtime.Error if err is not an error + panic(importError{p.scanner.Pos(), err.(error)}) +} + +func (p *parser) errorf(format string, args ...interface{}) { + p.error(fmt.Errorf(format, args...)) +} + +func (p *parser) expect(tok rune) string { + lit := p.lit + if p.tok != tok { + p.errorf("expected %s, got %s (%s)", scanner.TokenString(tok), scanner.TokenString(p.tok), lit) + } + p.next() + return lit +} + +func (p *parser) expectKeyword(keyword string) { + lit := p.expect(scanner.Ident) + if lit != keyword { + p.errorf("expected keyword %s, got %q", keyword, lit) + } +} + +func (p *parser) parseString() string { + str, err := strconv.Unquote(p.expect(scanner.String)) + if err != nil { + p.error(err) + } + return str +} + +// unquotedString = { unquotedStringChar } . +// unquotedStringChar = . +func (p *parser) parseUnquotedString() string { + if p.tok == scanner.EOF { + p.error("unexpected EOF") + } + var buf bytes.Buffer + buf.WriteString(p.scanner.TokenText()) + // This loop needs to examine each character before deciding whether to consume it. If we see a semicolon, + // we need to let it be consumed by p.next(). + for ch := p.scanner.Peek(); ch != ';' && ch != scanner.EOF && p.scanner.Whitespace&(1< 0 { + p.expect(',') + } + par, variadic := p.parseParam(pkg) + list = append(list, par) + if variadic { + if isVariadic { + p.error("... not on final argument") + } + isVariadic = true + } + } + p.expect(')') + + return types.NewTuple(list...), isVariadic +} + +// ResultList = Type | ParamList . +func (p *parser) parseResultList(pkg *types.Package) *types.Tuple { + switch p.tok { + case '<': + return types.NewTuple(types.NewParam(token.NoPos, pkg, "", p.parseType(pkg))) + + case '(': + params, _ := p.parseParamList(pkg) + return params + + default: + return nil + } +} + +// FunctionType = ParamList ResultList . +func (p *parser) parseFunctionType(pkg *types.Package) *types.Signature { + params, isVariadic := p.parseParamList(pkg) + results := p.parseResultList(pkg) + return types.NewSignature(nil, params, results, isVariadic) +} + +// Func = Name FunctionType . +func (p *parser) parseFunc(pkg *types.Package) *types.Func { + name := p.parseName() + if strings.ContainsRune(name, '$') { + // This is a Type$equal or Type$hash function, which we don't want to parse, + // except for the types. + p.discardDirectiveWhileParsingTypes(pkg) + return nil + } + return types.NewFunc(token.NoPos, pkg, name, p.parseFunctionType(pkg)) +} + +// InterfaceType = "interface" "{" { ("?" Type | Func) ";" } "}" . +func (p *parser) parseInterfaceType(pkg *types.Package) types.Type { + p.expectKeyword("interface") + + var methods []*types.Func + var typs []*types.Named + + p.expect('{') + for p.tok != '}' && p.tok != scanner.EOF { + if p.tok == '?' { + p.next() + typs = append(typs, p.parseType(pkg).(*types.Named)) + } else { + method := p.parseFunc(pkg) + methods = append(methods, method) + } + p.expect(';') + } + p.expect('}') + + return types.NewInterface(methods, typs) +} + +// PointerType = "*" ("any" | Type) . +func (p *parser) parsePointerType(pkg *types.Package) types.Type { + p.expect('*') + if p.tok == scanner.Ident { + p.expectKeyword("any") + return types.Typ[types.UnsafePointer] + } + return types.NewPointer(p.parseType(pkg)) +} + +// TypeDefinition = NamedType | MapType | ChanType | StructType | InterfaceType | PointerType | ArrayOrSliceType | FunctionType . +func (p *parser) parseTypeDefinition(pkg *types.Package, n int) types.Type { + var t types.Type + switch p.tok { + case scanner.String: + t = p.parseNamedType(n) + + case scanner.Ident: + switch p.lit { + case "map": + t = p.parseMapType(pkg) + + case "chan": + t = p.parseChanType(pkg) + + case "struct": + t = p.parseStructType(pkg) + + case "interface": + t = p.parseInterfaceType(pkg) + } + + case '*': + t = p.parsePointerType(pkg) + + case '[': + t = p.parseArrayOrSliceType(pkg) + + case '(': + t = p.parseFunctionType(pkg) + } + + p.typeMap[n] = t + return t +} + +const ( + // From gofrontend/go/export.h + // Note that these values are negative in the gofrontend and have been made positive + // in the gccgoimporter. + gccgoBuiltinINT8 = 1 + gccgoBuiltinINT16 = 2 + gccgoBuiltinINT32 = 3 + gccgoBuiltinINT64 = 4 + gccgoBuiltinUINT8 = 5 + gccgoBuiltinUINT16 = 6 + gccgoBuiltinUINT32 = 7 + gccgoBuiltinUINT64 = 8 + gccgoBuiltinFLOAT32 = 9 + gccgoBuiltinFLOAT64 = 10 + gccgoBuiltinINT = 11 + gccgoBuiltinUINT = 12 + gccgoBuiltinUINTPTR = 13 + gccgoBuiltinBOOL = 15 + gccgoBuiltinSTRING = 16 + gccgoBuiltinCOMPLEX64 = 17 + gccgoBuiltinCOMPLEX128 = 18 + gccgoBuiltinERROR = 19 + gccgoBuiltinBYTE = 20 + gccgoBuiltinRUNE = 21 +) + +func lookupBuiltinType(typ int) types.Type { + return [...]types.Type{ + gccgoBuiltinINT8: types.Typ[types.Int8], + gccgoBuiltinINT16: types.Typ[types.Int16], + gccgoBuiltinINT32: types.Typ[types.Int32], + gccgoBuiltinINT64: types.Typ[types.Int64], + gccgoBuiltinUINT8: types.Typ[types.Uint8], + gccgoBuiltinUINT16: types.Typ[types.Uint16], + gccgoBuiltinUINT32: types.Typ[types.Uint32], + gccgoBuiltinUINT64: types.Typ[types.Uint64], + gccgoBuiltinFLOAT32: types.Typ[types.Float32], + gccgoBuiltinFLOAT64: types.Typ[types.Float64], + gccgoBuiltinINT: types.Typ[types.Int], + gccgoBuiltinUINT: types.Typ[types.Uint], + gccgoBuiltinUINTPTR: types.Typ[types.Uintptr], + gccgoBuiltinBOOL: types.Typ[types.Bool], + gccgoBuiltinSTRING: types.Typ[types.String], + gccgoBuiltinCOMPLEX64: types.Typ[types.Complex64], + gccgoBuiltinCOMPLEX128: types.Typ[types.Complex128], + gccgoBuiltinERROR: types.Universe.Lookup("error").Type(), + gccgoBuiltinBYTE: types.Universe.Lookup("byte").Type(), + gccgoBuiltinRUNE: types.Universe.Lookup("rune").Type(), + }[typ] +} + +// Type = "<" "type" ( "-" int | int [ TypeDefinition ] ) ">" . +func (p *parser) parseType(pkg *types.Package) (t types.Type) { + p.expect('<') + p.expectKeyword("type") + + switch p.tok { + case scanner.Int: + n := p.parseInt() + + if p.tok == '>' { + t = p.typeMap[int(n)] + } else { + t = p.parseTypeDefinition(pkg, int(n)) + } + + case '-': + p.next() + n := p.parseInt() + t = lookupBuiltinType(int(n)) + + default: + p.errorf("expected type number, got %s (%q)", scanner.TokenString(p.tok), p.lit) + return nil + } + + p.expect('>') + return +} + +// PackageInit = unquotedString unquotedString int . +func (p *parser) parsePackageInit() PackageInit { + name := p.parseUnquotedString() + initfunc := p.parseUnquotedString() + priority := int(p.parseInt()) + return PackageInit{Name: name, InitFunc: initfunc, Priority: priority} +} + +// Throw away tokens until we see a ';'. If we see a '<', attempt to parse as a type. +func (p *parser) discardDirectiveWhileParsingTypes(pkg *types.Package) { + for { + switch p.tok { + case ';': + return + case '<': + p.parseType(p.pkg) + case scanner.EOF: + p.error("unexpected EOF") + default: + p.next() + } + } +} + +// Create the package if we have parsed both the package path and package name. +func (p *parser) maybeCreatePackage() { + if p.pkgname != "" && p.pkgpath != "" { + p.pkg = p.getPkg(p.pkgpath, p.pkgname) + } +} + +// InitDataDirective = "v1" ";" | +// "priority" int ";" | +// "init" { PackageInit } ";" | +// "checksum" unquotedString ";" . +func (p *parser) parseInitDataDirective() { + if p.tok != scanner.Ident { + // unexpected token kind; panic + p.expect(scanner.Ident) + } + + switch p.lit { + case "v1": + p.next() + p.expect(';') + + case "priority": + p.next() + p.initdata.Priority = int(p.parseInt()) + p.expect(';') + + case "init": + p.next() + for p.tok != ';' && p.tok != scanner.EOF { + p.initdata.Inits = append(p.initdata.Inits, p.parsePackageInit()) + } + p.expect(';') + + case "checksum": + // Don't let the scanner try to parse the checksum as a number. + defer func(mode uint) { + p.scanner.Mode = mode + }(p.scanner.Mode) + p.scanner.Mode &^= scanner.ScanInts | scanner.ScanFloats + p.next() + p.parseUnquotedString() + p.expect(';') + + default: + p.errorf("unexpected identifier: %q", p.lit) + } +} + +// Directive = InitDataDirective | +// "package" unquotedString ";" | +// "pkgpath" unquotedString ";" | +// "import" unquotedString unquotedString string ";" | +// "func" Func ";" | +// "type" Type ";" | +// "var" Var ";" | +// "const" Const ";" . +func (p *parser) parseDirective() { + if p.tok != scanner.Ident { + // unexpected token kind; panic + p.expect(scanner.Ident) + } + + switch p.lit { + case "v1", "priority", "init", "checksum": + p.parseInitDataDirective() + + case "package": + p.next() + p.pkgname = p.parseUnquotedString() + p.maybeCreatePackage() + p.expect(';') + + case "pkgpath": + p.next() + p.pkgpath = p.parseUnquotedString() + p.maybeCreatePackage() + p.expect(';') + + case "import": + p.next() + pkgname := p.parseUnquotedString() + pkgpath := p.parseUnquotedString() + p.getPkg(pkgpath, pkgname) + p.parseString() + p.expect(';') + + case "func": + p.next() + fun := p.parseFunc(p.pkg) + if fun != nil { + p.pkg.Scope().Insert(fun) + } + p.expect(';') + + case "type": + p.next() + p.parseType(p.pkg) + p.expect(';') + + case "var": + p.next() + v := p.parseVar(p.pkg) + p.pkg.Scope().Insert(v) + p.expect(';') + + case "const": + p.next() + c := p.parseConst(p.pkg) + p.pkg.Scope().Insert(c) + p.expect(';') + + default: + p.errorf("unexpected identifier: %q", p.lit) + } +} + +// Package = { Directive } . +func (p *parser) parsePackage() *types.Package { + for p.tok != scanner.EOF { + p.parseDirective() + } + for _, typ := range p.typeMap { + if it, ok := typ.(*types.Interface); ok { + it.Complete() + } + } + p.pkg.MarkComplete() + return p.pkg +} + +// InitData = { InitDataDirective } . +func (p *parser) parseInitData() { + for p.tok != scanner.EOF { + p.parseInitDataDirective() + } +} diff --git a/libgo/go/go/internal/gccgoimporter/parser_test.go b/libgo/go/go/internal/gccgoimporter/parser_test.go new file mode 100644 index 00000000000..b96486f20ad --- /dev/null +++ b/libgo/go/go/internal/gccgoimporter/parser_test.go @@ -0,0 +1,72 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package gccgoimporter + +import ( + "bytes" + "go/types" + "strings" + "testing" + "text/scanner" +) + +var typeParserTests = []struct { + id, typ, want, underlying, methods string +}{ + {id: "foo", typ: "", want: "int8"}, + {id: "foo", typ: ">", want: "*error"}, + {id: "foo", typ: "", want: "unsafe.Pointer"}, + {id: "foo", typ: ">>", want: "foo.Bar", underlying: "*foo.Bar"}, + {id: "foo", typ: " func (? ) M (); >", want: "bar.Foo", underlying: "int8", methods: "func (bar.Foo).M()"}, + {id: "foo", typ: ">", want: "bar.foo", underlying: "int8"}, + {id: "foo", typ: ">", want: "[]int8"}, + {id: "foo", typ: ">", want: "[42]int8"}, + {id: "foo", typ: "] >", want: "map[int8]int16"}, + {id: "foo", typ: ">", want: "chan int8"}, + {id: "foo", typ: ">", want: "<-chan int8"}, + {id: "foo", typ: ">", want: "chan<- int8"}, + {id: "foo", typ: "; I16 \"i16\"; }>", want: "struct{I8 int8; I16 int16 \"i16\"}"}, + {id: "foo", typ: ", b ) ; Bar (? , ? ...) (? , ? ); Baz (); }>", want: "interface{Bar(int16, ...int8) (int16, int8); Baz(); Foo(a int8, b int16) int8}"}, + {id: "foo", typ: ") >", want: "func(int8) int16"}, +} + +func TestTypeParser(t *testing.T) { + for _, test := range typeParserTests { + var p parser + p.init("test.gox", strings.NewReader(test.typ), make(map[string]*types.Package)) + p.pkgname = test.id + p.pkgpath = test.id + p.maybeCreatePackage() + typ := p.parseType(p.pkg) + + if p.tok != scanner.EOF { + t.Errorf("expected full parse, stopped at %q", p.lit) + } + + got := typ.String() + if got != test.want { + t.Errorf("got type %q, expected %q", got, test.want) + } + + if test.underlying != "" { + underlying := typ.Underlying().String() + if underlying != test.underlying { + t.Errorf("got underlying type %q, expected %q", underlying, test.underlying) + } + } + + if test.methods != "" { + nt := typ.(*types.Named) + var buf bytes.Buffer + for i := 0; i != nt.NumMethods(); i++ { + buf.WriteString(nt.Method(i).String()) + } + methods := buf.String() + if methods != test.methods { + t.Errorf("got methods %q, expected %q", methods, test.methods) + } + } + } +} diff --git a/libgo/go/go/internal/gccgoimporter/testdata/complexnums.go b/libgo/go/go/internal/gccgoimporter/testdata/complexnums.go new file mode 100644 index 00000000000..a51b6b01c0b --- /dev/null +++ b/libgo/go/go/internal/gccgoimporter/testdata/complexnums.go @@ -0,0 +1,6 @@ +package complexnums + +const NN = -1 - 1i +const NP = -1 + 1i +const PN = 1 - 1i +const PP = 1 + 1i diff --git a/libgo/go/go/internal/gccgoimporter/testdata/imports.go b/libgo/go/go/internal/gccgoimporter/testdata/imports.go new file mode 100644 index 00000000000..7907316a607 --- /dev/null +++ b/libgo/go/go/internal/gccgoimporter/testdata/imports.go @@ -0,0 +1,5 @@ +package imports + +import "fmt" + +var Hello = fmt.Sprintf("Hello, world") diff --git a/libgo/go/go/internal/gccgoimporter/testdata/pointer.go b/libgo/go/go/internal/gccgoimporter/testdata/pointer.go new file mode 100644 index 00000000000..4ebc67137d6 --- /dev/null +++ b/libgo/go/go/internal/gccgoimporter/testdata/pointer.go @@ -0,0 +1,3 @@ +package pointer + +type Int8Ptr *int8 diff --git a/libgo/go/go/internal/gcimporter/exportdata.go b/libgo/go/go/internal/gcimporter/exportdata.go new file mode 100644 index 00000000000..657742bb6d7 --- /dev/null +++ b/libgo/go/go/internal/gcimporter/exportdata.go @@ -0,0 +1,108 @@ +// 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 implements FindExportData. + +package gcimporter + +import ( + "bufio" + "errors" + "fmt" + "io" + "strconv" + "strings" +) + +func readGopackHeader(r *bufio.Reader) (name string, size int, err error) { + // See $GOROOT/include/ar.h. + hdr := make([]byte, 16+12+6+6+8+10+2) + _, err = io.ReadFull(r, hdr) + if err != nil { + return + } + // leave for debugging + if false { + fmt.Printf("header: %s", hdr) + } + s := strings.TrimSpace(string(hdr[16+12+6+6+8:][:10])) + size, err = strconv.Atoi(s) + if err != nil || hdr[len(hdr)-2] != '`' || hdr[len(hdr)-1] != '\n' { + err = errors.New("invalid archive header") + return + } + name = strings.TrimSpace(string(hdr[:16])) + return +} + +// FindExportData positions the reader r at the beginning of the +// export data section of an underlying GC-created object/archive +// file by reading from it. The reader must be positioned at the +// start of the file before calling this function. +// +func FindExportData(r *bufio.Reader) (err error) { + // Read first line to make sure this is an object file. + line, err := r.ReadSlice('\n') + if err != nil { + return + } + if string(line) == "!\n" { + // Archive file. Scan to __.PKGDEF. + var name string + var size int + if name, size, err = readGopackHeader(r); err != nil { + return + } + + // Optional leading __.GOSYMDEF or __.SYMDEF. + // Read and discard. + if name == "__.SYMDEF" || name == "__.GOSYMDEF" { + const block = 4096 + tmp := make([]byte, block) + for size > 0 { + n := size + if n > block { + n = block + } + if _, err = io.ReadFull(r, tmp[:n]); err != nil { + return + } + size -= n + } + + if name, size, err = readGopackHeader(r); err != nil { + return + } + } + + // First real entry should be __.PKGDEF. + if name != "__.PKGDEF" { + err = errors.New("go archive is missing __.PKGDEF") + return + } + + // Read first line of __.PKGDEF data, so that line + // is once again the first line of the input. + if line, err = r.ReadSlice('\n'); err != nil { + return + } + } + + // Now at __.PKGDEF in archive or still at beginning of file. + // Either way, line should begin with "go object ". + if !strings.HasPrefix(string(line), "go object ") { + err = errors.New("not a go object file") + return + } + + // Skip over object header to export data. + // Begins after first line with $$. + for line[0] != '$' { + if line, err = r.ReadSlice('\n'); err != nil { + return + } + } + + return +} diff --git a/libgo/go/go/internal/gcimporter/gcimporter.go b/libgo/go/go/internal/gcimporter/gcimporter.go new file mode 100644 index 00000000000..1d485cf9cbf --- /dev/null +++ b/libgo/go/go/internal/gcimporter/gcimporter.go @@ -0,0 +1,991 @@ +// 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 gcimporter implements Import for gc-generated object files. +package gcimporter // import "go/internal/gcimporter" + +import ( + "bufio" + "errors" + "fmt" + "go/build" + "go/token" + "io" + "os" + "path/filepath" + "sort" + "strconv" + "strings" + "text/scanner" + + exact "go/constant" + "go/types" +) + +// debugging/development support +const debug = false + +var pkgExts = [...]string{".a", ".o"} + +// FindPkg returns the filename and unique package id for an import +// path based on package information provided by build.Import (using +// the build.Default build.Context). +// If no file was found, an empty filename is returned. +// +func FindPkg(path, srcDir string) (filename, id string) { + if len(path) == 0 { + return + } + + id = path + var noext string + switch { + default: + // "x" -> "$GOPATH/pkg/$GOOS_$GOARCH/x.ext", "x" + // Don't require the source files to be present. + bp, _ := build.Import(path, srcDir, build.FindOnly|build.AllowBinary) + if bp.PkgObj == "" { + return + } + noext = strings.TrimSuffix(bp.PkgObj, ".a") + + case build.IsLocalImport(path): + // "./x" -> "/this/directory/x.ext", "/this/directory/x" + noext = filepath.Join(srcDir, path) + id = noext + + case filepath.IsAbs(path): + // for completeness only - go/build.Import + // does not support absolute imports + // "/x" -> "/x.ext", "/x" + noext = path + } + + // try extensions + for _, ext := range pkgExts { + filename = noext + ext + if f, err := os.Stat(filename); err == nil && !f.IsDir() { + return + } + } + + filename = "" // not found + return +} + +// ImportData imports a package by reading the gc-generated export data, +// adds the corresponding package object to the packages map indexed by id, +// and returns the object. +// +// The packages map must contains all packages already imported. The data +// reader position must be the beginning of the export data section. The +// filename is only used in error messages. +// +// If packages[id] contains the completely imported package, that package +// can be used directly, and there is no need to call this function (but +// there is also no harm but for extra time used). +// +func ImportData(packages map[string]*types.Package, filename, id string, data io.Reader) (pkg *types.Package, err error) { + // support for parser error handling + defer func() { + switch r := recover().(type) { + case nil: + // nothing to do + case importError: + err = r + default: + panic(r) // internal error + } + }() + + var p parser + p.init(filename, id, data, packages) + pkg = p.parseExport() + + return +} + +// Import imports a gc-generated package given its import path, adds the +// corresponding package object to the packages map, and returns the object. +// Local import paths are interpreted relative to the current working directory. +// The packages map must contain all packages already imported. +// +func Import(packages map[string]*types.Package, path string) (pkg *types.Package, err error) { + // package "unsafe" is handled by the type checker + if path == "unsafe" { + panic(`gcimporter.Import called for package "unsafe"`) + } + + srcDir := "." + if build.IsLocalImport(path) { + srcDir, err = os.Getwd() + if err != nil { + return + } + } + + filename, id := FindPkg(path, srcDir) + if filename == "" { + err = fmt.Errorf("can't find import: %s", id) + return + } + + // no need to re-import if the package was imported completely before + if pkg = packages[id]; pkg != nil && pkg.Complete() { + return + } + + // open file + f, err := os.Open(filename) + if err != nil { + return + } + defer func() { + f.Close() + if err != nil { + // add file name to error + err = fmt.Errorf("reading export data: %s: %v", filename, err) + } + }() + + buf := bufio.NewReader(f) + if err = FindExportData(buf); err != nil { + return + } + + pkg, err = ImportData(packages, filename, id, buf) + + return +} + +// ---------------------------------------------------------------------------- +// Parser + +// TODO(gri) Imported objects don't have position information. +// Ideally use the debug table line info; alternatively +// create some fake position (or the position of the +// import). That way error messages referring to imported +// objects can print meaningful information. + +// parser parses the exports inside a gc compiler-produced +// object/archive file and populates its scope with the results. +type parser struct { + scanner scanner.Scanner + tok rune // current token + lit string // literal string; only valid for Ident, Int, String tokens + id string // package id of imported package + sharedPkgs map[string]*types.Package // package id -> package object (across importer) + localPkgs map[string]*types.Package // package id -> package object (just this package) +} + +func (p *parser) init(filename, id string, src io.Reader, packages map[string]*types.Package) { + p.scanner.Init(src) + p.scanner.Error = func(_ *scanner.Scanner, msg string) { p.error(msg) } + p.scanner.Mode = scanner.ScanIdents | scanner.ScanInts | scanner.ScanChars | scanner.ScanStrings | scanner.ScanComments | scanner.SkipComments + p.scanner.Whitespace = 1<<'\t' | 1<<' ' + p.scanner.Filename = filename // for good error messages + p.next() + p.id = id + p.sharedPkgs = packages + if debug { + // check consistency of packages map + for _, pkg := range packages { + if pkg.Name() == "" { + fmt.Printf("no package name for %s\n", pkg.Path()) + } + } + } +} + +func (p *parser) next() { + p.tok = p.scanner.Scan() + switch p.tok { + case scanner.Ident, scanner.Int, scanner.Char, scanner.String, '·': + p.lit = p.scanner.TokenText() + default: + p.lit = "" + } + if debug { + fmt.Printf("%s: %q -> %q\n", scanner.TokenString(p.tok), p.scanner.TokenText(), p.lit) + } +} + +func declTypeName(pkg *types.Package, name string) *types.TypeName { + scope := pkg.Scope() + if obj := scope.Lookup(name); obj != nil { + return obj.(*types.TypeName) + } + obj := types.NewTypeName(token.NoPos, pkg, name, nil) + // a named type may be referred to before the underlying type + // is known - set it up + types.NewNamed(obj, nil, nil) + scope.Insert(obj) + return obj +} + +// ---------------------------------------------------------------------------- +// Error handling + +// Internal errors are boxed as importErrors. +type importError struct { + pos scanner.Position + err error +} + +func (e importError) Error() string { + return fmt.Sprintf("import error %s (byte offset = %d): %s", e.pos, e.pos.Offset, e.err) +} + +func (p *parser) error(err interface{}) { + if s, ok := err.(string); ok { + err = errors.New(s) + } + // panic with a runtime.Error if err is not an error + panic(importError{p.scanner.Pos(), err.(error)}) +} + +func (p *parser) errorf(format string, args ...interface{}) { + p.error(fmt.Sprintf(format, args...)) +} + +func (p *parser) expect(tok rune) string { + lit := p.lit + if p.tok != tok { + p.errorf("expected %s, got %s (%s)", scanner.TokenString(tok), scanner.TokenString(p.tok), lit) + } + p.next() + return lit +} + +func (p *parser) expectSpecial(tok string) { + sep := 'x' // not white space + i := 0 + for i < len(tok) && p.tok == rune(tok[i]) && sep > ' ' { + sep = p.scanner.Peek() // if sep <= ' ', there is white space before the next token + p.next() + i++ + } + if i < len(tok) { + p.errorf("expected %q, got %q", tok, tok[0:i]) + } +} + +func (p *parser) expectKeyword(keyword string) { + lit := p.expect(scanner.Ident) + if lit != keyword { + p.errorf("expected keyword %s, got %q", keyword, lit) + } +} + +// ---------------------------------------------------------------------------- +// Qualified and unqualified names + +// PackageId = string_lit . +// +func (p *parser) parsePackageId() string { + id, err := strconv.Unquote(p.expect(scanner.String)) + if err != nil { + p.error(err) + } + // id == "" stands for the imported package id + // (only known at time of package installation) + if id == "" { + id = p.id + } + return id +} + +// PackageName = ident . +// +func (p *parser) parsePackageName() string { + return p.expect(scanner.Ident) +} + +// dotIdentifier = ( ident | '·' ) { ident | int | '·' } . +func (p *parser) parseDotIdent() string { + ident := "" + if p.tok != scanner.Int { + sep := 'x' // not white space + for (p.tok == scanner.Ident || p.tok == scanner.Int || p.tok == '·') && sep > ' ' { + ident += p.lit + sep = p.scanner.Peek() // if sep <= ' ', there is white space before the next token + p.next() + } + } + if ident == "" { + p.expect(scanner.Ident) // use expect() for error handling + } + return ident +} + +// QualifiedName = "@" PackageId "." ( "?" | dotIdentifier ) . +// +func (p *parser) parseQualifiedName() (id, name string) { + p.expect('@') + id = p.parsePackageId() + p.expect('.') + // Per rev f280b8a485fd (10/2/2013), qualified names may be used for anonymous fields. + if p.tok == '?' { + p.next() + } else { + name = p.parseDotIdent() + } + return +} + +// getPkg returns the package for a given id. If the package is +// not found but we have a package name, create the package and +// add it to the p.localPkgs and p.sharedPkgs maps. +// +// id identifies a package, usually by a canonical package path like +// "encoding/json" but possibly by a non-canonical import path like +// "./json". +// +func (p *parser) getPkg(id, name string) *types.Package { + // package unsafe is not in the packages maps - handle explicitly + if id == "unsafe" { + return types.Unsafe + } + + pkg := p.localPkgs[id] + if pkg == nil && name != "" { + // first import of id from this package + pkg = p.sharedPkgs[id] + if pkg == nil { + // first import of id by this importer + pkg = types.NewPackage(id, name) + p.sharedPkgs[id] = pkg + } + + if p.localPkgs == nil { + p.localPkgs = make(map[string]*types.Package) + } + p.localPkgs[id] = pkg + } + return pkg +} + +// parseExportedName is like parseQualifiedName, but +// the package id is resolved to an imported *types.Package. +// +func (p *parser) parseExportedName() (pkg *types.Package, name string) { + id, name := p.parseQualifiedName() + pkg = p.getPkg(id, "") + if pkg == nil { + p.errorf("%s package not found", id) + } + return +} + +// ---------------------------------------------------------------------------- +// Types + +// BasicType = identifier . +// +func (p *parser) parseBasicType() types.Type { + id := p.expect(scanner.Ident) + obj := types.Universe.Lookup(id) + if obj, ok := obj.(*types.TypeName); ok { + return obj.Type() + } + p.errorf("not a basic type: %s", id) + return nil +} + +// ArrayType = "[" int_lit "]" Type . +// +func (p *parser) parseArrayType() types.Type { + // "[" already consumed and lookahead known not to be "]" + lit := p.expect(scanner.Int) + p.expect(']') + elem := p.parseType() + n, err := strconv.ParseInt(lit, 10, 64) + if err != nil { + p.error(err) + } + return types.NewArray(elem, n) +} + +// MapType = "map" "[" Type "]" Type . +// +func (p *parser) parseMapType() types.Type { + p.expectKeyword("map") + p.expect('[') + key := p.parseType() + p.expect(']') + elem := p.parseType() + return types.NewMap(key, elem) +} + +// Name = identifier | "?" | QualifiedName . +// +// If materializePkg is set, the returned package is guaranteed to be set. +// For fully qualified names, the returned package may be a fake package +// (without name, scope, and not in the p.sharedPkgs map), created for the +// sole purpose of providing a package path. Fake packages are created +// when the package id is not found in the p.sharedPkgs map; in that case +// we cannot create a real package because we don't have a package name. +// For non-qualified names, the returned package is the imported package. +// +func (p *parser) parseName(materializePkg bool) (pkg *types.Package, name string) { + switch p.tok { + case scanner.Ident: + pkg = p.sharedPkgs[p.id] + name = p.lit + p.next() + case '?': + // anonymous + pkg = p.sharedPkgs[p.id] + p.next() + case '@': + // exported name prefixed with package path + var id string + id, name = p.parseQualifiedName() + if materializePkg { + // we don't have a package name - if the package + // doesn't exist yet, create a fake package instead + pkg = p.getPkg(id, "") + if pkg == nil { + pkg = types.NewPackage(id, "") + } + } + default: + p.error("name expected") + } + return +} + +func deref(typ types.Type) types.Type { + if p, _ := typ.(*types.Pointer); p != nil { + return p.Elem() + } + return typ +} + +// Field = Name Type [ string_lit ] . +// +func (p *parser) parseField() (*types.Var, string) { + pkg, name := p.parseName(true) + typ := p.parseType() + anonymous := false + if name == "" { + // anonymous field - typ must be T or *T and T must be a type name + switch typ := deref(typ).(type) { + case *types.Basic: // basic types are named types + pkg = nil + name = typ.Name() + case *types.Named: + name = typ.Obj().Name() + default: + p.errorf("anonymous field expected") + } + anonymous = true + } + tag := "" + if p.tok == scanner.String { + s := p.expect(scanner.String) + var err error + tag, err = strconv.Unquote(s) + if err != nil { + p.errorf("invalid struct tag %s: %s", s, err) + } + } + return types.NewField(token.NoPos, pkg, name, typ, anonymous), tag +} + +// StructType = "struct" "{" [ FieldList ] "}" . +// FieldList = Field { ";" Field } . +// +func (p *parser) parseStructType() types.Type { + var fields []*types.Var + var tags []string + + p.expectKeyword("struct") + p.expect('{') + for i := 0; p.tok != '}' && p.tok != scanner.EOF; i++ { + if i > 0 { + p.expect(';') + } + fld, tag := p.parseField() + if tag != "" && tags == nil { + tags = make([]string, i) + } + if tags != nil { + tags = append(tags, tag) + } + fields = append(fields, fld) + } + p.expect('}') + + return types.NewStruct(fields, tags) +} + +// Parameter = ( identifier | "?" ) [ "..." ] Type [ string_lit ] . +// +func (p *parser) parseParameter() (par *types.Var, isVariadic bool) { + _, name := p.parseName(false) + // remove gc-specific parameter numbering + if i := strings.Index(name, "·"); i >= 0 { + name = name[:i] + } + if p.tok == '.' { + p.expectSpecial("...") + isVariadic = true + } + typ := p.parseType() + if isVariadic { + typ = types.NewSlice(typ) + } + // ignore argument tag (e.g. "noescape") + if p.tok == scanner.String { + p.next() + } + // TODO(gri) should we provide a package? + par = types.NewVar(token.NoPos, nil, name, typ) + return +} + +// Parameters = "(" [ ParameterList ] ")" . +// ParameterList = { Parameter "," } Parameter . +// +func (p *parser) parseParameters() (list []*types.Var, isVariadic bool) { + p.expect('(') + for p.tok != ')' && p.tok != scanner.EOF { + if len(list) > 0 { + p.expect(',') + } + par, variadic := p.parseParameter() + list = append(list, par) + if variadic { + if isVariadic { + p.error("... not on final argument") + } + isVariadic = true + } + } + p.expect(')') + + return +} + +// Signature = Parameters [ Result ] . +// Result = Type | Parameters . +// +func (p *parser) parseSignature(recv *types.Var) *types.Signature { + params, isVariadic := p.parseParameters() + + // optional result type + var results []*types.Var + if p.tok == '(' { + var variadic bool + results, variadic = p.parseParameters() + if variadic { + p.error("... not permitted on result type") + } + } + + return types.NewSignature(recv, types.NewTuple(params...), types.NewTuple(results...), isVariadic) +} + +// InterfaceType = "interface" "{" [ MethodList ] "}" . +// MethodList = Method { ";" Method } . +// Method = Name Signature . +// +// The methods of embedded interfaces are always "inlined" +// by the compiler and thus embedded interfaces are never +// visible in the export data. +// +func (p *parser) parseInterfaceType() types.Type { + var methods []*types.Func + + p.expectKeyword("interface") + p.expect('{') + for i := 0; p.tok != '}' && p.tok != scanner.EOF; i++ { + if i > 0 { + p.expect(';') + } + pkg, name := p.parseName(true) + sig := p.parseSignature(nil) + methods = append(methods, types.NewFunc(token.NoPos, pkg, name, sig)) + } + p.expect('}') + + // Complete requires the type's embedded interfaces to be fully defined, + // but we do not define any + return types.NewInterface(methods, nil).Complete() +} + +// ChanType = ( "chan" [ "<-" ] | "<-" "chan" ) Type . +// +func (p *parser) parseChanType() types.Type { + dir := types.SendRecv + if p.tok == scanner.Ident { + p.expectKeyword("chan") + if p.tok == '<' { + p.expectSpecial("<-") + dir = types.SendOnly + } + } else { + p.expectSpecial("<-") + p.expectKeyword("chan") + dir = types.RecvOnly + } + elem := p.parseType() + return types.NewChan(dir, elem) +} + +// Type = +// BasicType | TypeName | ArrayType | SliceType | StructType | +// PointerType | FuncType | InterfaceType | MapType | ChanType | +// "(" Type ")" . +// +// BasicType = ident . +// TypeName = ExportedName . +// SliceType = "[" "]" Type . +// PointerType = "*" Type . +// FuncType = "func" Signature . +// +func (p *parser) parseType() types.Type { + switch p.tok { + case scanner.Ident: + switch p.lit { + default: + return p.parseBasicType() + case "struct": + return p.parseStructType() + case "func": + // FuncType + p.next() + return p.parseSignature(nil) + case "interface": + return p.parseInterfaceType() + case "map": + return p.parseMapType() + case "chan": + return p.parseChanType() + } + case '@': + // TypeName + pkg, name := p.parseExportedName() + return declTypeName(pkg, name).Type() + case '[': + p.next() // look ahead + if p.tok == ']' { + // SliceType + p.next() + return types.NewSlice(p.parseType()) + } + return p.parseArrayType() + case '*': + // PointerType + p.next() + return types.NewPointer(p.parseType()) + case '<': + return p.parseChanType() + case '(': + // "(" Type ")" + p.next() + typ := p.parseType() + p.expect(')') + return typ + } + p.errorf("expected type, got %s (%q)", scanner.TokenString(p.tok), p.lit) + return nil +} + +// ---------------------------------------------------------------------------- +// Declarations + +// ImportDecl = "import" PackageName PackageId . +// +func (p *parser) parseImportDecl() { + p.expectKeyword("import") + name := p.parsePackageName() + p.getPkg(p.parsePackageId(), name) +} + +// int_lit = [ "+" | "-" ] { "0" ... "9" } . +// +func (p *parser) parseInt() string { + s := "" + switch p.tok { + case '-': + s = "-" + p.next() + case '+': + p.next() + } + return s + p.expect(scanner.Int) +} + +// number = int_lit [ "p" int_lit ] . +// +func (p *parser) parseNumber() (typ *types.Basic, val exact.Value) { + // mantissa + mant := exact.MakeFromLiteral(p.parseInt(), token.INT, 0) + if mant == nil { + panic("invalid mantissa") + } + + if p.lit == "p" { + // exponent (base 2) + p.next() + exp, err := strconv.ParseInt(p.parseInt(), 10, 0) + if err != nil { + p.error(err) + } + if exp < 0 { + denom := exact.MakeInt64(1) + denom = exact.Shift(denom, token.SHL, uint(-exp)) + typ = types.Typ[types.UntypedFloat] + val = exact.BinaryOp(mant, token.QUO, denom) + return + } + if exp > 0 { + mant = exact.Shift(mant, token.SHL, uint(exp)) + } + typ = types.Typ[types.UntypedFloat] + val = mant + return + } + + typ = types.Typ[types.UntypedInt] + val = mant + return +} + +// ConstDecl = "const" ExportedName [ Type ] "=" Literal . +// Literal = bool_lit | int_lit | float_lit | complex_lit | rune_lit | string_lit . +// bool_lit = "true" | "false" . +// complex_lit = "(" float_lit "+" float_lit "i" ")" . +// rune_lit = "(" int_lit "+" int_lit ")" . +// string_lit = `"` { unicode_char } `"` . +// +func (p *parser) parseConstDecl() { + p.expectKeyword("const") + pkg, name := p.parseExportedName() + + var typ0 types.Type + if p.tok != '=' { + typ0 = p.parseType() + } + + p.expect('=') + var typ types.Type + var val exact.Value + switch p.tok { + case scanner.Ident: + // bool_lit + if p.lit != "true" && p.lit != "false" { + p.error("expected true or false") + } + typ = types.Typ[types.UntypedBool] + val = exact.MakeBool(p.lit == "true") + p.next() + + case '-', scanner.Int: + // int_lit + typ, val = p.parseNumber() + + case '(': + // complex_lit or rune_lit + p.next() + if p.tok == scanner.Char { + p.next() + p.expect('+') + typ = types.Typ[types.UntypedRune] + _, val = p.parseNumber() + p.expect(')') + break + } + _, re := p.parseNumber() + p.expect('+') + _, im := p.parseNumber() + p.expectKeyword("i") + p.expect(')') + typ = types.Typ[types.UntypedComplex] + val = exact.BinaryOp(re, token.ADD, exact.MakeImag(im)) + + case scanner.Char: + // rune_lit + typ = types.Typ[types.UntypedRune] + val = exact.MakeFromLiteral(p.lit, token.CHAR, 0) + p.next() + + case scanner.String: + // string_lit + typ = types.Typ[types.UntypedString] + val = exact.MakeFromLiteral(p.lit, token.STRING, 0) + p.next() + + default: + p.errorf("expected literal got %s", scanner.TokenString(p.tok)) + } + + if typ0 == nil { + typ0 = typ + } + + pkg.Scope().Insert(types.NewConst(token.NoPos, pkg, name, typ0, val)) +} + +// TypeDecl = "type" ExportedName Type . +// +func (p *parser) parseTypeDecl() { + p.expectKeyword("type") + pkg, name := p.parseExportedName() + obj := declTypeName(pkg, name) + + // The type object may have been imported before and thus already + // have a type associated with it. We still need to parse the type + // structure, but throw it away if the object already has a type. + // This ensures that all imports refer to the same type object for + // a given type declaration. + typ := p.parseType() + + if name := obj.Type().(*types.Named); name.Underlying() == nil { + name.SetUnderlying(typ) + } +} + +// VarDecl = "var" ExportedName Type . +// +func (p *parser) parseVarDecl() { + p.expectKeyword("var") + pkg, name := p.parseExportedName() + typ := p.parseType() + pkg.Scope().Insert(types.NewVar(token.NoPos, pkg, name, typ)) +} + +// Func = Signature [ Body ] . +// Body = "{" ... "}" . +// +func (p *parser) parseFunc(recv *types.Var) *types.Signature { + sig := p.parseSignature(recv) + if p.tok == '{' { + p.next() + for i := 1; i > 0; p.next() { + switch p.tok { + case '{': + i++ + case '}': + i-- + } + } + } + return sig +} + +// MethodDecl = "func" Receiver Name Func . +// Receiver = "(" ( identifier | "?" ) [ "*" ] ExportedName ")" . +// +func (p *parser) parseMethodDecl() { + // "func" already consumed + p.expect('(') + recv, _ := p.parseParameter() // receiver + p.expect(')') + + // determine receiver base type object + base := deref(recv.Type()).(*types.Named) + + // parse method name, signature, and possibly inlined body + _, name := p.parseName(true) + sig := p.parseFunc(recv) + + // methods always belong to the same package as the base type object + pkg := base.Obj().Pkg() + + // add method to type unless type was imported before + // and method exists already + // TODO(gri) This leads to a quadratic algorithm - ok for now because method counts are small. + base.AddMethod(types.NewFunc(token.NoPos, pkg, name, sig)) +} + +// FuncDecl = "func" ExportedName Func . +// +func (p *parser) parseFuncDecl() { + // "func" already consumed + pkg, name := p.parseExportedName() + typ := p.parseFunc(nil) + pkg.Scope().Insert(types.NewFunc(token.NoPos, pkg, name, typ)) +} + +// Decl = [ ImportDecl | ConstDecl | TypeDecl | VarDecl | FuncDecl | MethodDecl ] "\n" . +// +func (p *parser) parseDecl() { + if p.tok == scanner.Ident { + switch p.lit { + case "import": + p.parseImportDecl() + case "const": + p.parseConstDecl() + case "type": + p.parseTypeDecl() + case "var": + p.parseVarDecl() + case "func": + p.next() // look ahead + if p.tok == '(' { + p.parseMethodDecl() + } else { + p.parseFuncDecl() + } + } + } + p.expect('\n') +} + +// ---------------------------------------------------------------------------- +// Export + +// Export = "PackageClause { Decl } "$$" . +// PackageClause = "package" PackageName [ "safe" ] "\n" . +// +func (p *parser) parseExport() *types.Package { + p.expectKeyword("package") + name := p.parsePackageName() + if p.tok == scanner.Ident && p.lit == "safe" { + // package was compiled with -u option - ignore + p.next() + } + p.expect('\n') + + pkg := p.getPkg(p.id, name) + + for p.tok != '$' && p.tok != scanner.EOF { + p.parseDecl() + } + + if ch := p.scanner.Peek(); p.tok != '$' || ch != '$' { + // don't call next()/expect() since reading past the + // export data may cause scanner errors (e.g. NUL chars) + p.errorf("expected '$$', got %s %c", scanner.TokenString(p.tok), ch) + } + + if n := p.scanner.ErrorCount; n != 0 { + p.errorf("expected no scanner errors, got %d", n) + } + + // Record all referenced packages as imports. + var imports []*types.Package + for id, pkg2 := range p.localPkgs { + if id == p.id { + continue // avoid self-edge + } + imports = append(imports, pkg2) + } + sort.Sort(byPath(imports)) + pkg.SetImports(imports) + + // package was imported completely and without errors + pkg.MarkComplete() + + return pkg +} + +type byPath []*types.Package + +func (a byPath) Len() int { return len(a) } +func (a byPath) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a byPath) Less(i, j int) bool { return a[i].Path() < a[j].Path() } diff --git a/libgo/go/go/internal/gcimporter/gcimporter_test.go b/libgo/go/go/internal/gcimporter/gcimporter_test.go new file mode 100644 index 00000000000..07993a801f7 --- /dev/null +++ b/libgo/go/go/internal/gcimporter/gcimporter_test.go @@ -0,0 +1,225 @@ +// 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 gcimporter + +import ( + "fmt" + "internal/testenv" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "runtime" + "strings" + "testing" + "time" + + "go/types" +) + +// skipSpecialPlatforms causes the test to be skipped for platforms where +// builders (build.golang.org) don't have access to compiled packages for +// import. +func skipSpecialPlatforms(t *testing.T) { + switch platform := runtime.GOOS + "-" + runtime.GOARCH; platform { + case "nacl-amd64p32", + "nacl-386", + "nacl-arm", + "darwin-arm", + "darwin-arm64": + t.Skipf("no compiled packages available for import on %s", platform) + } +} + +func compile(t *testing.T, dirname, filename string) string { + testenv.MustHaveGoBuild(t) + cmd := exec.Command("go", "tool", "compile", filename) + cmd.Dir = dirname + out, err := cmd.CombinedOutput() + if err != nil { + t.Logf("%s", out) + t.Fatalf("go tool compile %s failed: %s", filename, err) + } + // filename should end with ".go" + return filepath.Join(dirname, filename[:len(filename)-2]+"o") +} + +// Use the same global imports map for all tests. The effect is +// as if all tested packages were imported into a single package. +var imports = make(map[string]*types.Package) + +func testPath(t *testing.T, path string) *types.Package { + t0 := time.Now() + pkg, err := Import(imports, path) + if err != nil { + t.Errorf("testPath(%s): %s", path, err) + return nil + } + t.Logf("testPath(%s): %v", path, time.Since(t0)) + return pkg +} + +const maxTime = 30 * time.Second + +func testDir(t *testing.T, dir string, endTime time.Time) (nimports int) { + dirname := filepath.Join(runtime.GOROOT(), "pkg", runtime.GOOS+"_"+runtime.GOARCH, dir) + list, err := ioutil.ReadDir(dirname) + if err != nil { + t.Fatalf("testDir(%s): %s", dirname, err) + } + for _, f := range list { + if time.Now().After(endTime) { + t.Log("testing time used up") + return + } + switch { + case !f.IsDir(): + // try extensions + for _, ext := range pkgExts { + if strings.HasSuffix(f.Name(), ext) { + name := f.Name()[0 : len(f.Name())-len(ext)] // remove extension + if testPath(t, filepath.Join(dir, name)) != nil { + nimports++ + } + } + } + case f.IsDir(): + nimports += testDir(t, filepath.Join(dir, f.Name()), endTime) + } + } + return +} + +func TestImport(t *testing.T) { + // This package only handles gc export data. + if runtime.Compiler != "gc" { + t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler) + return + } + + if outFn := compile(t, "testdata", "exports.go"); outFn != "" { + defer os.Remove(outFn) + } + + nimports := 0 + if pkg := testPath(t, "./testdata/exports"); pkg != nil { + nimports++ + // The package's Imports should include all the types + // referenced by the exportdata, which may be more than + // the import statements in the package's source, but + // fewer than the transitive closure of dependencies. + want := `[package ast ("go/ast") package token ("go/token") package runtime ("runtime")]` + got := fmt.Sprint(pkg.Imports()) + if got != want { + t.Errorf(`Package("exports").Imports() = %s, want %s`, got, want) + } + } + nimports += testDir(t, "", time.Now().Add(maxTime)) // installed packages + t.Logf("tested %d imports", nimports) +} + +var importedObjectTests = []struct { + name string + want string +}{ + {"math.Pi", "const Pi untyped float"}, + {"io.Reader", "type Reader interface{Read(p []byte) (n int, err error)}"}, + {"io.ReadWriter", "type ReadWriter interface{Read(p []byte) (n int, err error); Write(p []byte) (n int, err error)}"}, + {"math.Sin", "func Sin(x float64) float64"}, + // TODO(gri) add more tests +} + +func TestImportedTypes(t *testing.T) { + skipSpecialPlatforms(t) + + // This package only handles gc export data. + if runtime.Compiler != "gc" { + t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler) + return + } + + for _, test := range importedObjectTests { + s := strings.Split(test.name, ".") + if len(s) != 2 { + t.Fatal("inconsistent test data") + } + importPath := s[0] + objName := s[1] + + pkg, err := Import(imports, importPath) + if err != nil { + t.Error(err) + continue + } + + obj := pkg.Scope().Lookup(objName) + if obj == nil { + t.Errorf("%s: object not found", test.name) + continue + } + + got := types.ObjectString(obj, types.RelativeTo(pkg)) + if got != test.want { + t.Errorf("%s: got %q; want %q", test.name, got, test.want) + } + } +} + +func TestIssue5815(t *testing.T) { + skipSpecialPlatforms(t) + + // This package only handles gc export data. + if runtime.Compiler != "gc" { + t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler) + return + } + + pkg, err := Import(make(map[string]*types.Package), "strings") + if err != nil { + t.Fatal(err) + } + + scope := pkg.Scope() + for _, name := range scope.Names() { + obj := scope.Lookup(name) + if obj.Pkg() == nil { + t.Errorf("no pkg for %s", obj) + } + if tname, _ := obj.(*types.TypeName); tname != nil { + named := tname.Type().(*types.Named) + for i := 0; i < named.NumMethods(); i++ { + m := named.Method(i) + if m.Pkg() == nil { + t.Errorf("no pkg for %s", m) + } + } + } + } +} + +// Smoke test to ensure that imported methods get the correct package. +func TestCorrectMethodPackage(t *testing.T) { + skipSpecialPlatforms(t) + + // This package only handles gc export data. + if runtime.Compiler != "gc" { + t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler) + return + } + + imports := make(map[string]*types.Package) + _, err := Import(imports, "net/http") + if err != nil { + t.Fatal(err) + } + + mutex := imports["sync"].Scope().Lookup("Mutex").(*types.TypeName).Type() + mset := types.NewMethodSet(types.NewPointer(mutex)) // methods of *sync.Mutex + sel := mset.Lookup(nil, "Lock") + lock := sel.Obj().(*types.Func) + if got, want := lock.Pkg().Path(), "sync"; got != want { + t.Errorf("got package path %q; want %q", got, want) + } +} diff --git a/libgo/go/go/internal/gcimporter/testdata/exports.go b/libgo/go/go/internal/gcimporter/testdata/exports.go new file mode 100644 index 00000000000..8ee28b0942b --- /dev/null +++ b/libgo/go/go/internal/gcimporter/testdata/exports.go @@ -0,0 +1,89 @@ +// 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 is used to generate an object file which +// serves as test file for gcimporter_test.go. + +package exports + +import ( + "go/ast" +) + +// Issue 3682: Correctly read dotted identifiers from export data. +const init1 = 0 + +func init() {} + +const ( + C0 int = 0 + C1 = 3.14159265 + C2 = 2.718281828i + C3 = -123.456e-789 + C4 = +123.456E+789 + C5 = 1234i + C6 = "foo\n" + C7 = `bar\n` +) + +type ( + T1 int + T2 [10]int + T3 []int + T4 *int + T5 chan int + T6a chan<- int + T6b chan (<-chan int) + T6c chan<- (chan int) + T7 <-chan *ast.File + T8 struct{} + T9 struct { + a int + b, c float32 + d []string `go:"tag"` + } + T10 struct { + T8 + T9 + _ *T10 + } + T11 map[int]string + T12 interface{} + T13 interface { + m1() + m2(int) float32 + } + T14 interface { + T12 + T13 + m3(x ...struct{}) []T9 + } + T15 func() + T16 func(int) + T17 func(x int) + T18 func() float32 + T19 func() (x float32) + T20 func(...interface{}) + T21 struct{ next *T21 } + T22 struct{ link *T23 } + T23 struct{ link *T22 } + T24 *T24 + T25 *T26 + T26 *T27 + T27 *T25 + T28 func(T28) T28 +) + +var ( + V0 int + V1 = -991.0 +) + +func F1() {} +func F2(x int) {} +func F3() int { return 0 } +func F4() float32 { return 0 } +func F5(a, b, c int, u, v, w struct{ x, y T1 }, more ...interface{}) (p, q, r chan<- T10) + +func (p *T1) M1() diff --git a/libgo/go/go/parser/error_test.go b/libgo/go/go/parser/error_test.go index 48fb53e5b0d..1a08d5a6b11 100644 --- a/libgo/go/go/parser/error_test.go +++ b/libgo/go/go/parser/error_test.go @@ -34,11 +34,9 @@ import ( const testdata = "testdata" -var fsetErrs = token.NewFileSet() - // getFile assumes that each filename occurs at most once -func getFile(filename string) (file *token.File) { - fsetErrs.Iterate(func(f *token.File) bool { +func getFile(fset *token.FileSet, filename string) (file *token.File) { + fset.Iterate(func(f *token.File) bool { if f.Name() == filename { if file != nil { panic(filename + " used multiple times") @@ -50,8 +48,8 @@ func getFile(filename string) (file *token.File) { return file } -func getPos(filename string, offset int) token.Pos { - if f := getFile(filename); f != nil { +func getPos(fset *token.FileSet, filename string, offset int) token.Pos { + if f := getFile(fset, filename); f != nil { return f.Pos(offset) } return token.NoPos @@ -68,14 +66,14 @@ var errRx = regexp.MustCompile(`^/\* *ERROR *(HERE)? *"([^"]*)" *\*/$`) // 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 { +func expectedErrors(t *testing.T, fset *token.FileSet, 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) + s.Init(getFile(fset, filename), src, nil, scanner.ScanComments) var prev token.Pos // position of last non-comment, non-semicolon token var here token.Pos // position immediately after the token at position prev @@ -109,11 +107,11 @@ func expectedErrors(t *testing.T, filename string, src []byte) map[token.Pos]str // 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) { +func compareErrors(t *testing.T, fset *token.FileSet, 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) + pos := getPos(fset, 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) @@ -140,7 +138,7 @@ func compareErrors(t *testing.T, expected map[token.Pos]string, found scanner.Er if len(expected) > 0 { t.Errorf("%d errors not reported:", len(expected)) for pos, msg := range expected { - t.Errorf("%s: %s\n", fsetErrs.Position(pos), msg) + t.Errorf("%s: %s\n", fset.Position(pos), msg) } } } @@ -152,7 +150,8 @@ func checkErrors(t *testing.T, filename string, input interface{}) { return } - _, err = ParseFile(fsetErrs, filename, src, DeclarationErrors|AllErrors) + fset := token.NewFileSet() + _, err = ParseFile(fset, filename, src, DeclarationErrors|AllErrors) found, ok := err.(scanner.ErrorList) if err != nil && !ok { t.Error(err) @@ -162,10 +161,10 @@ func checkErrors(t *testing.T, filename string, input interface{}) { // 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) + expected := expectedErrors(t, fset, filename, src) // verify errors returned by the parser - compareErrors(t, expected, found) + compareErrors(t, fset, expected, found) } func TestErrors(t *testing.T) { diff --git a/libgo/go/go/parser/interface.go b/libgo/go/go/parser/interface.go index 49103058b59..c6fd93240af 100644 --- a/libgo/go/go/parser/interface.go +++ b/libgo/go/go/parser/interface.go @@ -91,7 +91,10 @@ func ParseFile(fset *token.FileSet, filename string, src interface{}, mode Mode) var p parser defer func() { if e := recover(); e != nil { - _ = e.(bailout) // re-panics if it's not a bailout + // resume same panic if it's not a bailout + if _, ok := e.(bailout); !ok { + panic(e) + } } // set result values @@ -164,14 +167,31 @@ func ParseDir(fset *token.FileSet, path string, filter func(os.FileInfo) bool, m return } -// ParseExpr is a convenience function for obtaining the AST of an expression x. -// The position information recorded in the AST is undefined. The filename used -// in error messages is the empty string. +// ParseExprFrom is a convenience function for parsing an expression. +// The arguments have the same meaning as for Parse, but the source must +// be a valid Go (type or value) expression. // -func ParseExpr(x string) (ast.Expr, error) { +func ParseExprFrom(fset *token.FileSet, filename string, src interface{}, mode Mode) (ast.Expr, error) { + // get source + text, err := readSource(filename, src) + if err != nil { + return nil, err + } + var p parser - p.init(token.NewFileSet(), "", []byte(x), 0) + defer func() { + if e := recover(); e != nil { + // resume same panic if it's not a bailout + if _, ok := e.(bailout); !ok { + panic(e) + } + } + p.errors.Sort() + err = p.errors.Err() + }() + // parse expr + p.init(fset, filename, text, mode) // Set up pkg-level scopes to avoid nil-pointer errors. // This is not needed for a correct expression x as the // parser will be ok with a nil topScope, but be cautious @@ -196,3 +216,11 @@ func ParseExpr(x string) (ast.Expr, error) { return e, nil } + +// ParseExpr is a convenience function for obtaining the AST of an expression x. +// The position information recorded in the AST is undefined. The filename used +// in error messages is the empty string. +// +func ParseExpr(x string) (ast.Expr, error) { + return ParseExprFrom(token.NewFileSet(), "", []byte(x), 0) +} diff --git a/libgo/go/go/parser/parser.go b/libgo/go/go/parser/parser.go index 4a005d8ffa3..e82c0bd1223 100644 --- a/libgo/go/go/parser/parser.go +++ b/libgo/go/go/parser/parser.go @@ -7,6 +7,13 @@ // output is an abstract syntax tree (AST) representing the Go source. The // parser is invoked through one of the Parse* functions. // +// The parser accepts a larger language than is syntactically permitted by +// the Go spec, for simplicity, and for improved robustness in the presence +// of syntax errors. For instance, in method declarations, the receiver is +// treated like an ordinary parameter list and thus may contain multiple +// entries where the spec permits exactly one. Consequently, the corresponding +// field in the AST (ast.FuncDecl.Recv) field is not restricted to one entry. +// package parser import ( @@ -412,14 +419,17 @@ func (p *parser) expectSemi() { } } -func (p *parser) atComma(context string) bool { +func (p *parser) atComma(context string, follow token.Token) 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 - + if p.tok != follow { + msg := "missing ','" + if p.tok == token.SEMICOLON && p.lit == "\n" { + msg += " before newline" + } + p.error(p.pos, msg+" in "+context) + return true // "insert" comma and continue } return false } @@ -825,7 +835,7 @@ func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params [ // parameter or result variable is the function body. p.declare(field, nil, scope, ast.Var, idents...) p.resolve(typ) - if !p.atComma("parameter list") { + if !p.atComma("parameter list", token.RPAREN) { return } p.next() @@ -838,7 +848,7 @@ func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params [ // parameter or result variable is the function body. p.declare(field, nil, scope, ast.Var, idents...) p.resolve(typ) - if !p.atComma("parameter list") { + if !p.atComma("parameter list", token.RPAREN) { break } p.next() @@ -1248,7 +1258,7 @@ func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr { ellipsis = p.pos p.next() } - if !p.atComma("argument list") { + if !p.atComma("argument list", token.RPAREN) { break } p.next() @@ -1259,7 +1269,7 @@ func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr { return &ast.CallExpr{Fun: fun, Lparen: lparen, Args: list, Ellipsis: ellipsis, Rparen: rparen} } -func (p *parser) parseElement(keyOk bool) ast.Expr { +func (p *parser) parseValue(keyOk bool) ast.Expr { if p.trace { defer un(trace(p, "Element")) } @@ -1287,16 +1297,30 @@ func (p *parser) parseElement(keyOk bool) ast.Expr { x := p.checkExpr(p.parseExpr(keyOk)) if keyOk { if p.tok == token.COLON { - colon := p.pos - p.next() // Try to resolve the key but don't collect it // as unresolved identifier if it fails so that // we don't get (possibly false) errors about // undeclared names. p.tryResolve(x, false) - return &ast.KeyValueExpr{Key: x, Colon: colon, Value: p.parseElement(false)} + } else { + // not a key + p.resolve(x) } - p.resolve(x) // not a key + } + + return x +} + +func (p *parser) parseElement() ast.Expr { + if p.trace { + defer un(trace(p, "Element")) + } + + x := p.parseValue(true) + if p.tok == token.COLON { + colon := p.pos + p.next() + x = &ast.KeyValueExpr{Key: x, Colon: colon, Value: p.parseValue(false)} } return x @@ -1308,8 +1332,8 @@ func (p *parser) parseElementList() (list []ast.Expr) { } for p.tok != token.RBRACE && p.tok != token.EOF { - list = append(list, p.parseElement(true)) - if !p.atComma("composite literal") { + list = append(list, p.parseElement()) + if !p.atComma("composite literal", token.RBRACE) { break } p.next() @@ -1365,7 +1389,7 @@ func (p *parser) checkExpr(x ast.Expr) ast.Expr { return x } -// isTypeName returns true iff x is a (qualified) TypeName. +// isTypeName reports whether x is a (qualified) TypeName. func isTypeName(x ast.Expr) bool { switch t := x.(type) { case *ast.BadExpr: @@ -1379,7 +1403,7 @@ func isTypeName(x ast.Expr) bool { return true } -// isLiteralType returns true iff x is a legal composite literal type. +// isLiteralType reports whether x is a legal composite literal type. func isLiteralType(x ast.Expr) bool { switch t := x.(type) { case *ast.BadExpr: @@ -1455,7 +1479,8 @@ L: pos := p.pos p.errorExpected(pos, "selector or type assertion") p.next() // make progress - x = &ast.BadExpr{From: pos, To: p.pos} + sel := &ast.Ident{NamePos: pos, Name: "_"} + x = &ast.SelectorExpr{X: x, Sel: sel} } case token.LBRACK: if lhs { @@ -2123,7 +2148,7 @@ func (p *parser) parseStmt() (s ast.Stmt) { case // tokens that may start an expression token.IDENT, token.INT, token.FLOAT, token.IMAG, token.CHAR, token.STRING, token.FUNC, token.LPAREN, // operands - token.LBRACK, token.STRUCT, // composite types + token.LBRACK, token.STRUCT, token.MAP, token.CHAN, token.INTERFACE, // composite types token.ADD, token.SUB, token.MUL, token.AND, token.XOR, token.ARROW, token.NOT: // unary operators s, _ = p.parseSimpleStmt(labelOk) // because of the required look-ahead, labeled statements are @@ -2152,11 +2177,14 @@ func (p *parser) parseStmt() (s ast.Stmt) { case token.FOR: s = p.parseForStmt() case token.SEMICOLON: - s = &ast.EmptyStmt{Semicolon: p.pos} + // Is it ever possible to have an implicit semicolon + // producing an empty statement in a valid program? + // (handle correctly anyway) + s = &ast.EmptyStmt{Semicolon: p.pos, Implicit: p.lit == "\n"} p.next() case token.RBRACE: // a semicolon may be omitted before a closing "}" - s = &ast.EmptyStmt{Semicolon: p.pos} + s = &ast.EmptyStmt{Semicolon: p.pos, Implicit: true} default: // no statement found pos := p.pos @@ -2228,6 +2256,7 @@ func (p *parser) parseValueSpec(doc *ast.CommentGroup, keyword token.Token, iota defer un(trace(p, keyword.String()+"Spec")) } + pos := p.pos idents := p.parseIdentList() typ := p.tryType() var values []ast.Expr @@ -2238,6 +2267,17 @@ func (p *parser) parseValueSpec(doc *ast.CommentGroup, keyword token.Token, iota } p.expectSemi() // call before accessing p.linecomment + switch keyword { + case token.VAR: + if typ == nil && values == nil { + p.error(pos, "missing variable type or initialization") + } + case token.CONST: + if values == nil && (iota == 0 || typ != nil) { + p.error(pos, "missing constant value") + } + } + // Go spec: The scope of a constant or variable identifier declared inside // a function begins at the end of the ConstSpec or VarSpec and ends at // the end of the innermost containing block. diff --git a/libgo/go/go/parser/parser_test.go b/libgo/go/go/parser/parser_test.go index 85065fd1829..c7bb36d789d 100644 --- a/libgo/go/go/parser/parser_test.go +++ b/libgo/go/go/parser/parser_test.go @@ -14,8 +14,6 @@ import ( "testing" ) -var fset = token.NewFileSet() - var validFiles = []string{ "parser.go", "parser_test.go", @@ -25,7 +23,7 @@ var validFiles = []string{ func TestParse(t *testing.T) { for _, filename := range validFiles { - _, err := ParseFile(fset, filename, nil, DeclarationErrors) + _, err := ParseFile(token.NewFileSet(), filename, nil, DeclarationErrors) if err != nil { t.Fatalf("ParseFile(%s): %v", filename, err) } @@ -46,7 +44,7 @@ func dirFilter(f os.FileInfo) bool { return nameFilter(f.Name()) } func TestParseDir(t *testing.T) { path := "." - pkgs, err := ParseDir(fset, path, dirFilter, 0) + pkgs, err := ParseDir(token.NewFileSet(), path, dirFilter, 0) if err != nil { t.Fatalf("ParseDir(%s): %v", path, err) } @@ -131,7 +129,7 @@ func TestParseExpr(t *testing.T) { } func TestColonEqualsScope(t *testing.T) { - f, err := ParseFile(fset, "", `package p; func f() { x, y, z := x, y, z }`, 0) + f, err := ParseFile(token.NewFileSet(), "", `package p; func f() { x, y, z := x, y, z }`, 0) if err != nil { t.Fatal(err) } @@ -153,7 +151,7 @@ func TestColonEqualsScope(t *testing.T) { } func TestVarScope(t *testing.T) { - f, err := ParseFile(fset, "", `package p; func f() { var x, y, z = x, y, z }`, 0) + f, err := ParseFile(token.NewFileSet(), "", `package p; func f() { var x, y, z = x, y, z }`, 0) if err != nil { t.Fatal(err) } @@ -183,7 +181,7 @@ var x int func f() { L: } ` - f, err := ParseFile(fset, "", src, 0) + f, err := ParseFile(token.NewFileSet(), "", src, 0) if err != nil { t.Fatal(err) } @@ -221,7 +219,7 @@ func f() { L: } } func TestUnresolved(t *testing.T) { - f, err := ParseFile(fset, "", ` + f, err := ParseFile(token.NewFileSet(), "", ` package p // func f1a(int) @@ -316,7 +314,7 @@ var imports = map[string]bool{ func TestImports(t *testing.T) { for path, isValid := range imports { src := fmt.Sprintf("package p; import %s", path) - _, err := ParseFile(fset, "", src, 0) + _, err := ParseFile(token.NewFileSet(), "", src, 0) switch { case err != nil && isValid: t.Errorf("ParseFile(%s): got %v; expected no error", src, err) @@ -327,7 +325,7 @@ func TestImports(t *testing.T) { } func TestCommentGroups(t *testing.T) { - f, err := ParseFile(fset, "", ` + f, err := ParseFile(token.NewFileSet(), "", ` package p /* 1a */ /* 1b */ /* 1c */ // 1d /* 2a */ @@ -421,7 +419,7 @@ func checkFieldComments(t *testing.T, file *ast.File, fieldname, lead, line stri } func TestLeadAndLineComments(t *testing.T) { - f, err := ParseFile(fset, "", ` + f, err := ParseFile(token.NewFileSet(), "", ` package p type T struct { /* F1 lead comment */ @@ -447,3 +445,89 @@ type T struct { t.Error("not expected to find T.f3") } } + +// TestIssue9979 verifies that empty statements are contained within their enclosing blocks. +func TestIssue9979(t *testing.T) { + for _, src := range []string{ + "package p; func f() {;}", + "package p; func f() {L:}", + "package p; func f() {L:;}", + "package p; func f() {L:\n}", + "package p; func f() {L:\n;}", + "package p; func f() { ; }", + "package p; func f() { L: }", + "package p; func f() { L: ; }", + "package p; func f() { L: \n}", + "package p; func f() { L: \n; }", + } { + fset := token.NewFileSet() + f, err := ParseFile(fset, "", src, 0) + if err != nil { + t.Fatal(err) + } + + var pos, end token.Pos + ast.Inspect(f, func(x ast.Node) bool { + switch s := x.(type) { + case *ast.BlockStmt: + pos, end = s.Pos()+1, s.End()-1 // exclude "{", "}" + case *ast.LabeledStmt: + pos, end = s.Pos()+2, s.End() // exclude "L:" + case *ast.EmptyStmt: + // check containment + if s.Pos() < pos || s.End() > end { + t.Errorf("%s: %T[%d, %d] not inside [%d, %d]", src, s, s.Pos(), s.End(), pos, end) + } + // check semicolon + offs := fset.Position(s.Pos()).Offset + if ch := src[offs]; ch != ';' != s.Implicit { + want := "want ';'" + if s.Implicit { + want = "but ';' is implicit" + } + t.Errorf("%s: found %q at offset %d; %s", src, ch, offs, want) + } + } + return true + }) + } +} + +// TestIncompleteSelection ensures that an incomplete selector +// expression is parsed as a (blank) *ast.SelectorExpr, not a +// *ast.BadExpr. +func TestIncompleteSelection(t *testing.T) { + for _, src := range []string{ + "package p; var _ = fmt.", // at EOF + "package p; var _ = fmt.\ntype X int", // not at EOF + } { + fset := token.NewFileSet() + f, err := ParseFile(fset, "", src, 0) + if err == nil { + t.Errorf("ParseFile(%s) succeeded unexpectedly", src) + continue + } + + const wantErr = "expected selector or type assertion" + if !strings.Contains(err.Error(), wantErr) { + t.Errorf("ParseFile returned wrong error %q, want %q", err, wantErr) + } + + var sel *ast.SelectorExpr + ast.Inspect(f, func(n ast.Node) bool { + if n, ok := n.(*ast.SelectorExpr); ok { + sel = n + } + return true + }) + if sel == nil { + t.Error("found no *ast.SelectorExpr") + continue + } + const wantSel = "&{fmt _}" + if fmt.Sprint(sel) != wantSel { + t.Errorf("found selector %s, want %s", sel, wantSel) + continue + } + } +} diff --git a/libgo/go/go/parser/short_test.go b/libgo/go/go/parser/short_test.go index 05e44de28a7..ef2ffadbd98 100644 --- a/libgo/go/go/parser/short_test.go +++ b/libgo/go/go/parser/short_test.go @@ -40,6 +40,12 @@ var valids = []string{ `package p; func (*(T),) m() {}`, `package p; func _(x []int) { for range x {} }`, `package p; func _() { if [T{}.n]int{} {} }`, + `package p; func _() { map[int]int{}[0]++; map[int]int{}[0] += 1 }`, + `package p; func _(x interface{f()}) { interface{f()}(x).f() }`, + `package p; func _(x chan int) { chan int(x) <- 0 }`, + `package p; const (x = 0; y; z)`, // issue 9639 + `package p; var _ = map[P]int{P{}:0, {}:1}`, + `package p; var _ = map[*P]int{&P{}:0, {}:1}`, } func TestValid(t *testing.T) { @@ -93,8 +99,13 @@ var invalids = []string{ `package p; func f() { for i /* ERROR "boolean or range expression" */ , x := []string {} }`, `package p; func f() { go f /* ERROR HERE "function must be invoked" */ }`, `package p; func f() { defer func() {} /* ERROR HERE "function must be invoked" */ }`, - `package p; func f() { go func() { func() { f(x func /* ERROR "expected '\)'" */ (){}) } } }`, - `package p; func f() (a b string /* ERROR "expected '\)'" */ , ok bool) // issue 8656`, + `package p; func f() { go func() { func() { f(x func /* ERROR "missing ','" */ (){}) } } }`, + `package p; func f(x func(), u v func /* ERROR "missing ','" */ ()){}`, + `package p; func f() (a b string /* ERROR "missing ','" */ , ok bool)`, // issue 8656 + `package p; var x /* ERROR "missing variable type or initialization" */ , y, z;`, // issue 9639 + `package p; const x /* ERROR "missing constant value" */ ;`, // issue 9639 + `package p; const x /* ERROR "missing constant value" */ int;`, // issue 9639 + `package p; const (x = 0; y; z /* ERROR "missing constant value" */ int);`, // issue 9639 } func TestInvalid(t *testing.T) { diff --git a/libgo/go/go/parser/testdata/issue3106.src b/libgo/go/go/parser/testdata/issue3106.src index 82796c8ceb6..2db10be2354 100644 --- a/libgo/go/go/parser/testdata/issue3106.src +++ b/libgo/go/go/parser/testdata/issue3106.src @@ -19,7 +19,7 @@ func f() { time.Sleep(1e8) m.Lock() defer - if /* ERROR "expected operand, found 'if'" */ percent == 100 { + if /* ERROR "expected ';', found 'if'" */ percent == 100 { m.Unlock() break } diff --git a/libgo/go/go/printer/nodes.go b/libgo/go/go/printer/nodes.go index d5a69349beb..fe047053afb 100644 --- a/libgo/go/go/printer/nodes.go +++ b/libgo/go/go/printer/nodes.go @@ -12,6 +12,9 @@ import ( "bytes" "go/ast" "go/token" + "strconv" + "strings" + "unicode" "unicode/utf8" ) @@ -1334,6 +1337,49 @@ func (p *printer) valueSpec(s *ast.ValueSpec, keepType bool) { } } +func sanitizeImportPath(lit *ast.BasicLit) *ast.BasicLit { + // Note: An unmodified AST generated by go/parser will already + // contain a backward- or double-quoted path string that does + // not contain any invalid characters, and most of the work + // here is not needed. However, a modified or generated AST + // may possibly contain non-canonical paths. Do the work in + // all cases since it's not too hard and not speed-critical. + + // if we don't have a proper string, be conservative and return whatever we have + if lit.Kind != token.STRING { + return lit + } + s, err := strconv.Unquote(lit.Value) + if err != nil { + return lit + } + + // if the string is an invalid path, return whatever we have + // + // spec: "Implementation restriction: A compiler may restrict + // ImportPaths to non-empty strings using only characters belonging + // to Unicode's L, M, N, P, and S general categories (the Graphic + // characters without spaces) and may also exclude the characters + // !"#$%&'()*,:;<=>?[\]^`{|} and the Unicode replacement character + // U+FFFD." + if s == "" { + return lit + } + const illegalChars = `!"#$%&'()*,:;<=>?[\]^{|}` + "`\uFFFD" + for _, r := range s { + if !unicode.IsGraphic(r) || unicode.IsSpace(r) || strings.ContainsRune(illegalChars, r) { + return lit + } + } + + // otherwise, return the double-quoted path + s = strconv.Quote(s) + if s == lit.Value { + return lit // nothing wrong with lit + } + return &ast.BasicLit{ValuePos: lit.ValuePos, Kind: token.STRING, Value: s} +} + // The parameter n is the number of specs in the group. If doIndent is set, // multi-line identifier lists in the spec are indented when the first // linebreak is encountered. @@ -1346,7 +1392,7 @@ func (p *printer) spec(spec ast.Spec, n int, doIndent bool) { p.expr(s.Name) p.print(blank) } - p.expr(s.Path) + p.expr(sanitizeImportPath(s.Path)) p.setComment(s.Comment) p.print(s.EndPos) diff --git a/libgo/go/go/printer/printer.go b/libgo/go/go/printer/printer.go index 280c697a0dd..f9343d3af0d 100644 --- a/libgo/go/go/printer/printer.go +++ b/libgo/go/go/printer/printer.go @@ -144,7 +144,7 @@ func (p *printer) nextComment() { p.commentOffset = infinity } -// commentBefore returns true iff the current comment group occurs +// commentBefore reports whether the current comment group occurs // before the next position in the source code and printing it does // not introduce implicit semicolons. // @@ -496,29 +496,33 @@ func stripCommonPrefix(lines []string) { // Compute maximum common white prefix of all but the first, // last, and blank lines, and replace blank lines with empty // lines (the first line starts with /* and has no prefix). - // In case of two-line comments, consider the last line for - // the prefix computation since otherwise the prefix would - // be empty. + // In cases where only the first and last lines are not blank, + // such as two-line comments, or comments where all inner lines + // are blank, consider the last line for the prefix computation + // since otherwise the prefix would be empty. // // Note that the first and last line are never empty (they // contain the opening /* and closing */ respectively) and // thus they can be ignored by the blank line check. - var prefix string + prefix := "" + prefixSet := false if len(lines) > 2 { - first := true for i, line := range lines[1 : len(lines)-1] { - switch { - case isBlank(line): + if isBlank(line) { lines[1+i] = "" // range starts with lines[1] - case first: - prefix = commonPrefix(line, line) - first = false - default: + } else { + if !prefixSet { + prefix = line + prefixSet = true + } prefix = commonPrefix(prefix, line) } + } - } else { // len(lines) == 2, lines cannot be blank (contain /* and */) - line := lines[1] + } + // If we don't have a prefix yet, consider the last line. + if !prefixSet { + line := lines[len(lines)-1] prefix = commonPrefix(line, line) } diff --git a/libgo/go/go/printer/testdata/comments.golden b/libgo/go/go/printer/testdata/comments.golden index b1af7958a96..849fa624489 100644 --- a/libgo/go/go/printer/testdata/comments.golden +++ b/libgo/go/go/printer/testdata/comments.golden @@ -413,6 +413,68 @@ func _() { aligned line */ } +// Issue 9751. +func _() { + /*a string + + b string*/ + + /*A string + + + + Z string*/ + + /*a string + + b string + + c string*/ + + { + /*a string + b string*/ + + /*a string + + b string*/ + + /*a string + + b string + + c string*/ + } + + { + /*a string + b string*/ + + /*a string + + b string*/ + + /*a string + + b string + + c string*/ + } + + /* + */ + + /* + + */ + + /* + + * line + + */ +} + /* * line * of diff --git a/libgo/go/go/printer/testdata/comments.input b/libgo/go/go/printer/testdata/comments.input index 983e2b2c97e..30cd23c6dd4 100644 --- a/libgo/go/go/printer/testdata/comments.input +++ b/libgo/go/go/printer/testdata/comments.input @@ -418,6 +418,68 @@ func _() { aligned line */ } +// Issue 9751. +func _() { + /*a string + + b string*/ + + /*A string + + + + Z string*/ + + /*a string + + b string + + c string*/ + + { + /*a string +b string*/ + + /*a string + +b string*/ + + /*a string + +b string + +c string*/ + } + + { + /*a string + b string*/ + + /*a string + + b string*/ + + /*a string + + b string + + c string*/ + } + + /* + */ + + /* + + */ + + /* + + * line + + */ +} + /* * line * of diff --git a/libgo/go/go/printer/testdata/declarations.golden b/libgo/go/go/printer/testdata/declarations.golden index 9acd41b7d28..82f5e0f9147 100644 --- a/libgo/go/go/printer/testdata/declarations.golden +++ b/libgo/go/go/printer/testdata/declarations.golden @@ -110,6 +110,15 @@ import ( "package_dddd" // comment ) +// print import paths as double-quoted strings +// (we would like more test cases but the go/parser +// already excludes most incorrect paths, and we don't +// bother setting up test-ASTs manually) +import ( + "fmt" + "math" +) + // at least one empty line between declarations of different kind import _ "io" diff --git a/libgo/go/go/printer/testdata/declarations.input b/libgo/go/go/printer/testdata/declarations.input index 45beec25fc7..a0a3783b846 100644 --- a/libgo/go/go/printer/testdata/declarations.input +++ b/libgo/go/go/printer/testdata/declarations.input @@ -111,6 +111,15 @@ import ( "package_dddd" // comment ) +// print import paths as double-quoted strings +// (we would like more test cases but the go/parser +// already excludes most incorrect paths, and we don't +// bother setting up test-ASTs manually) +import ( + `fmt` + "math" +) + // at least one empty line between declarations of different kind import _ "io" var _ int diff --git a/libgo/go/go/printer/testdata/parser.go b/libgo/go/go/printer/testdata/parser.go index dba8bbd4351..44dfa19ff35 100644 --- a/libgo/go/go/printer/testdata/parser.go +++ b/libgo/go/go/printer/testdata/parser.go @@ -1165,7 +1165,7 @@ func (p *parser) checkExpr(x ast.Expr) ast.Expr { return x } -// isTypeName returns true iff x is a (qualified) TypeName. +// isTypeName reports whether x is a (qualified) TypeName. func isTypeName(x ast.Expr) bool { switch t := x.(type) { case *ast.BadExpr: @@ -1179,7 +1179,7 @@ func isTypeName(x ast.Expr) bool { return true } -// isLiteralType returns true iff x is a legal composite literal type. +// isLiteralType reports whether x is a legal composite literal type. func isLiteralType(x ast.Expr) bool { switch t := x.(type) { case *ast.BadExpr: diff --git a/libgo/go/go/scanner/errors.go b/libgo/go/go/scanner/errors.go index 22de69c3c1c..bf7bfa30e4b 100644 --- a/libgo/go/go/scanner/errors.go +++ b/libgo/go/go/scanner/errors.go @@ -54,18 +54,16 @@ func (p ErrorList) Less(i, j int) bool { // Note that it is not sufficient to simply compare file offsets because // the offsets do not reflect modified line information (through //line // comments). - if e.Filename < f.Filename { - return true + if e.Filename != f.Filename { + return e.Filename < f.Filename } - if e.Filename == f.Filename { - if e.Line < f.Line { - return true - } - if e.Line == f.Line { - return e.Column < f.Column - } + if e.Line != f.Line { + return e.Line < f.Line + } + if e.Column != f.Column { + return e.Column < f.Column } - return false + return p[i].Msg < p[j].Msg } // Sort sorts an ErrorList. *Error entries are sorted by position, diff --git a/libgo/go/go/scanner/scanner.go b/libgo/go/go/scanner/scanner.go index cec82ea10ef..e9476c4dee4 100644 --- a/libgo/go/go/scanner/scanner.go +++ b/libgo/go/go/scanner/scanner.go @@ -706,13 +706,14 @@ scanAgain: s.insertSemi = false // newline consumed return pos, token.SEMICOLON, "\n" } - lit = s.scanComment() + comment := s.scanComment() if s.mode&ScanComments == 0 { // skip comment s.insertSemi = false // newline consumed goto scanAgain } tok = token.COMMENT + lit = comment } else { tok = s.switch2(token.QUO, token.QUO_ASSIGN) } diff --git a/libgo/go/go/scanner/scanner_test.go b/libgo/go/go/scanner/scanner_test.go index fc450d8a6eb..0d21905166c 100644 --- a/libgo/go/go/scanner/scanner_test.go +++ b/libgo/go/go/scanner/scanner_test.go @@ -734,6 +734,41 @@ func TestScanErrors(t *testing.T) { } } +// Verify that no comments show up as literal values when skipping comments. +func TestIssue10213(t *testing.T) { + var src = ` + var ( + A = 1 // foo + ) + + var ( + B = 2 + // foo + ) + + var C = 3 // foo + + var D = 4 + // foo + + func anycode() { + // foo + } + ` + var s Scanner + s.Init(fset.AddFile("", fset.Base(), len(src)), []byte(src), nil, 0) + for { + pos, tok, lit := s.Scan() + class := tokenclass(tok) + if lit != "" && class != keyword && class != literal && tok != token.SEMICOLON { + t.Errorf("%s: tok = %s, lit = %q", fset.Position(pos), tok, lit) + } + if tok <= token.EOF { + break + } + } +} + func BenchmarkScan(b *testing.B) { b.StopTimer() fset := token.NewFileSet() diff --git a/libgo/go/go/token/position.go b/libgo/go/go/token/position.go index 82d90eeb728..33751779a3d 100644 --- a/libgo/go/go/token/position.go +++ b/libgo/go/go/token/position.go @@ -21,10 +21,10 @@ type Position struct { Filename string // filename, if any Offset int // offset, starting at 0 Line int // line number, starting at 1 - Column int // column number, starting at 1 (character count) + Column int // column number, starting at 1 (byte count) } -// IsValid returns true if the position is valid. +// IsValid reports whether the position is valid. func (pos *Position) IsValid() bool { return pos.Line > 0 } // String returns a string in one of several forms: @@ -56,8 +56,8 @@ func (pos Position) String() string { // where base and size are specified when adding the file to the file set via // AddFile. // -// To create the Pos value for a specific source offset, first add -// the respective file to the current file set (via FileSet.AddFile) +// To create the Pos value for a specific source offset (measured in bytes), +// first add the respective file to the current file set using FileSet.AddFile // and then call File.Pos(offset) for that file. Given a Pos value p // for a specific file set fset, the corresponding Position value is // obtained by calling fset.Position(p). @@ -77,7 +77,7 @@ type Pos int // const NoPos Pos = 0 -// IsValid returns true if the position is valid. +// IsValid reports whether the position is valid. func (p Pos) IsValid() bool { return p != NoPos } @@ -157,7 +157,7 @@ func (f *File) MergeLine(line int) { f.lines = f.lines[:len(f.lines)-1] } -// SetLines sets the line offsets for a file and returns true if successful. +// SetLines sets the line offsets for a file and reports whether it succeeded. // The line offsets are the offsets of the first character of each line; // for instance for the content "ab\nc\n" the line offsets are {0, 3}. // An empty file has an empty line offset table. diff --git a/libgo/go/go/types/api.go b/libgo/go/go/types/api.go new file mode 100644 index 00000000000..b3bf6f01476 --- /dev/null +++ b/libgo/go/go/types/api.go @@ -0,0 +1,336 @@ +// 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 types declares the data types and implements +// the algorithms for type-checking of Go packages. Use +// Config.Check to invoke the type checker for a package. +// Alternatively, create a new type checked with NewChecker +// and invoke it incrementally by calling Checker.Files. +// +// Type-checking consists of several interdependent phases: +// +// Name resolution maps each identifier (ast.Ident) in the program to the +// language object (Object) it denotes. +// Use Info.{Defs,Uses,Implicits} for the results of name resolution. +// +// Constant folding computes the exact constant value (constant.Value) +// for every expression (ast.Expr) that is a compile-time constant. +// Use Info.Types[expr].Value for the results of constant folding. +// +// Type inference computes the type (Type) of every expression (ast.Expr) +// and checks for compliance with the language specification. +// Use Info.Types[expr].Type for the results of type inference. +// +package types // import "go/types" + +import ( + "bytes" + "fmt" + "go/ast" + "go/constant" + "go/token" +) + +// An Error describes a type-checking error; it implements the error interface. +// A "soft" error is an error that still permits a valid interpretation of a +// package (such as "unused variable"); "hard" errors may lead to unpredictable +// behavior if ignored. +type Error struct { + Fset *token.FileSet // file set for interpretation of Pos + Pos token.Pos // error position + Msg string // error message + Soft bool // if set, error is "soft" +} + +// Error returns an error string formatted as follows: +// filename:line:column: message +func (err Error) Error() string { + return fmt.Sprintf("%s: %s", err.Fset.Position(err.Pos), err.Msg) +} + +// An importer resolves import paths to Packages. +// See go/importer for existing implementations. +type Importer interface { + // Import returns the imported package for the given import + // path, or an error if the package couldn't be imported. + // Import is responsible for returning the same package for + // matching import paths. + Import(path string) (*Package, error) +} + +// A Config specifies the configuration for type checking. +// The zero value for Config is a ready-to-use default configuration. +type Config struct { + // If IgnoreFuncBodies is set, function bodies are not + // type-checked. + IgnoreFuncBodies bool + + // If FakeImportC is set, `import "C"` (for packages requiring Cgo) + // declares an empty "C" package and errors are omitted for qualified + // identifiers referring to package C (which won't find an object). + // This feature is intended for the standard library cmd/api tool. + // + // Caution: Effects may be unpredictable due to follow-up errors. + // Do not use casually! + FakeImportC bool + + // If Error != nil, it is called with each error found + // during type checking; err has dynamic type Error. + // Secondary errors (for instance, to enumerate all types + // involved in an invalid recursive type declaration) have + // error strings that start with a '\t' character. + // If Error == nil, type-checking stops with the first + // error found. + Error func(err error) + + // Importer is called for each import declaration except when + // importing package "unsafe". An error is reported if an + // importer is needed but none was installed. + Importer Importer + + // If Sizes != nil, it provides the sizing functions for package unsafe. + // Otherwise &StdSizes{WordSize: 8, MaxAlign: 8} is used instead. + Sizes Sizes + + // If DisableUnusedImportCheck is set, packages are not checked + // for unused imports. + DisableUnusedImportCheck bool +} + +// Info holds result type information for a type-checked package. +// Only the information for which a map is provided is collected. +// If the package has type errors, the collected information may +// be incomplete. +type Info struct { + // Types maps expressions to their types, and for constant + // expressions, their values. Invalid expressions are omitted. + // + // For (possibly parenthesized) identifiers denoting built-in + // functions, the recorded signatures are call-site specific: + // if the call result is not a constant, the recorded type is + // an argument-specific signature. Otherwise, the recorded type + // is invalid. + // + // Identifiers on the lhs of declarations (i.e., the identifiers + // which are being declared) are collected in the Defs map. + // Identifiers denoting packages are collected in the Uses maps. + Types map[ast.Expr]TypeAndValue + + // Defs maps identifiers to the objects they define (including + // package names, dots "." of dot-imports, and blank "_" identifiers). + // For identifiers that do not denote objects (e.g., the package name + // in package clauses, or symbolic variables t in t := x.(type) of + // type switch headers), the corresponding objects are nil. + // + // For an anonymous field, Defs returns the field *Var it defines. + // + // Invariant: Defs[id] == nil || Defs[id].Pos() == id.Pos() + Defs map[*ast.Ident]Object + + // Uses maps identifiers to the objects they denote. + // + // For an anonymous field, Uses returns the *TypeName it denotes. + // + // Invariant: Uses[id].Pos() != id.Pos() + Uses map[*ast.Ident]Object + + // Implicits maps nodes to their implicitly declared objects, if any. + // The following node and object types may appear: + // + // node declared object + // + // *ast.ImportSpec *PkgName for dot-imports and imports without renames + // *ast.CaseClause type-specific *Var for each type switch case clause (incl. default) + // *ast.Field anonymous struct field or parameter *Var + // + Implicits map[ast.Node]Object + + // Selections maps selector expressions (excluding qualified identifiers) + // to their corresponding selections. + Selections map[*ast.SelectorExpr]*Selection + + // Scopes maps ast.Nodes to the scopes they define. Package scopes are not + // associated with a specific node but with all files belonging to a package. + // Thus, the package scope can be found in the type-checked Package object. + // Scopes nest, with the Universe scope being the outermost scope, enclosing + // the package scope, which contains (one or more) files scopes, which enclose + // function scopes which in turn enclose statement and function literal scopes. + // Note that even though package-level functions are declared in the package + // scope, the function scopes are embedded in the file scope of the file + // containing the function declaration. + // + // The following node types may appear in Scopes: + // + // *ast.File + // *ast.FuncType + // *ast.BlockStmt + // *ast.IfStmt + // *ast.SwitchStmt + // *ast.TypeSwitchStmt + // *ast.CaseClause + // *ast.CommClause + // *ast.ForStmt + // *ast.RangeStmt + // + Scopes map[ast.Node]*Scope + + // InitOrder is the list of package-level initializers in the order in which + // they must be executed. Initializers referring to variables related by an + // initialization dependency appear in topological order, the others appear + // in source order. Variables without an initialization expression do not + // appear in this list. + InitOrder []*Initializer +} + +// TypeOf returns the type of expression e, or nil if not found. +// Precondition: the Types, Uses and Defs maps are populated. +// +func (info *Info) TypeOf(e ast.Expr) Type { + if t, ok := info.Types[e]; ok { + return t.Type + } + if id, _ := e.(*ast.Ident); id != nil { + if obj := info.ObjectOf(id); obj != nil { + return obj.Type() + } + } + return nil +} + +// ObjectOf returns the object denoted by the specified id, +// or nil if not found. +// +// If id is an anonymous struct field, ObjectOf returns the field (*Var) +// it uses, not the type (*TypeName) it defines. +// +// Precondition: the Uses and Defs maps are populated. +// +func (info *Info) ObjectOf(id *ast.Ident) Object { + if obj, _ := info.Defs[id]; obj != nil { + return obj + } + return info.Uses[id] +} + +// TypeAndValue reports the type and value (for constants) +// of the corresponding expression. +type TypeAndValue struct { + mode operandMode + Type Type + Value constant.Value +} + +// TODO(gri) Consider eliminating the IsVoid predicate. Instead, report +// "void" values as regular values but with the empty tuple type. + +// IsVoid reports whether the corresponding expression +// is a function call without results. +func (tv TypeAndValue) IsVoid() bool { + return tv.mode == novalue +} + +// IsType reports whether the corresponding expression specifies a type. +func (tv TypeAndValue) IsType() bool { + return tv.mode == typexpr +} + +// IsBuiltin reports whether the corresponding expression denotes +// a (possibly parenthesized) built-in function. +func (tv TypeAndValue) IsBuiltin() bool { + return tv.mode == builtin +} + +// IsValue reports whether the corresponding expression is a value. +// Builtins are not considered values. Constant values have a non- +// nil Value. +func (tv TypeAndValue) IsValue() bool { + switch tv.mode { + case constant_, variable, mapindex, value, commaok: + return true + } + return false +} + +// IsNil reports whether the corresponding expression denotes the +// predeclared value nil. +func (tv TypeAndValue) IsNil() bool { + return tv.mode == value && tv.Type == Typ[UntypedNil] +} + +// Addressable reports whether the corresponding expression +// is addressable (https://golang.org/ref/spec#Address_operators). +func (tv TypeAndValue) Addressable() bool { + return tv.mode == variable +} + +// Assignable reports whether the corresponding expression +// is assignable to (provided a value of the right type). +func (tv TypeAndValue) Assignable() bool { + return tv.mode == variable || tv.mode == mapindex +} + +// HasOk reports whether the corresponding expression may be +// used on the lhs of a comma-ok assignment. +func (tv TypeAndValue) HasOk() bool { + return tv.mode == commaok || tv.mode == mapindex +} + +// An Initializer describes a package-level variable, or a list of variables in case +// of a multi-valued initialization expression, and the corresponding initialization +// expression. +type Initializer struct { + Lhs []*Var // var Lhs = Rhs + Rhs ast.Expr +} + +func (init *Initializer) String() string { + var buf bytes.Buffer + for i, lhs := range init.Lhs { + if i > 0 { + buf.WriteString(", ") + } + buf.WriteString(lhs.Name()) + } + buf.WriteString(" = ") + WriteExpr(&buf, init.Rhs) + return buf.String() +} + +// Check type-checks a package and returns the resulting package object, +// the first error if any, and if info != nil, additional type information. +// The package is marked as complete if no errors occurred, otherwise it is +// incomplete. See Config.Error for controlling behavior in the presence of +// errors. +// +// The package is specified by a list of *ast.Files and corresponding +// file set, and the package path the package is identified with. +// The clean path must not be empty or dot ("."). +func (conf *Config) Check(path string, fset *token.FileSet, files []*ast.File, info *Info) (*Package, error) { + pkg := NewPackage(path, "") + return pkg, NewChecker(conf, fset, pkg, info).Files(files) +} + +// AssertableTo reports whether a value of type V can be asserted to have type T. +func AssertableTo(V *Interface, T Type) bool { + m, _ := assertableTo(V, T) + return m == nil +} + +// AssignableTo reports whether a value of type V is assignable to a variable of type T. +func AssignableTo(V, T Type) bool { + x := operand{mode: value, typ: V} + return x.assignableTo(nil, T) // config not needed for non-constant x +} + +// ConvertibleTo reports whether a value of type V is convertible to a value of type T. +func ConvertibleTo(V, T Type) bool { + x := operand{mode: value, typ: V} + return x.convertibleTo(nil, T) // config not needed for non-constant x +} + +// Implements reports whether type V implements interface T. +func Implements(V Type, T *Interface) bool { + f, _ := MissingMethod(V, T, true) + return f == nil +} diff --git a/libgo/go/go/types/api_test.go b/libgo/go/go/types/api_test.go new file mode 100644 index 00000000000..eeda0d847c3 --- /dev/null +++ b/libgo/go/go/types/api_test.go @@ -0,0 +1,1044 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package types_test + +import ( + "bytes" + "fmt" + "go/ast" + "go/importer" + "go/parser" + "go/token" + "internal/testenv" + "reflect" + "regexp" + "strings" + "testing" + + . "go/types" +) + +func pkgFor(path, source string, info *Info) (*Package, error) { + fset := token.NewFileSet() + f, err := parser.ParseFile(fset, path, source, 0) + if err != nil { + return nil, err + } + + conf := Config{Importer: importer.Default()} + return conf.Check(f.Name.Name, fset, []*ast.File{f}, info) +} + +func mustTypecheck(t *testing.T, path, source string, info *Info) string { + pkg, err := pkgFor(path, source, info) + if err != nil { + name := path + if pkg != nil { + name = "package " + pkg.Name() + } + t.Fatalf("%s: didn't type-check (%s)", name, err) + } + return pkg.Name() +} + +func TestValuesInfo(t *testing.T) { + var tests = []struct { + src string + expr string // constant expression + typ string // constant type + val string // constant value + }{ + {`package a0; const _ = false`, `false`, `untyped bool`, `false`}, + {`package a1; const _ = 0`, `0`, `untyped int`, `0`}, + {`package a2; const _ = 'A'`, `'A'`, `untyped rune`, `65`}, + {`package a3; const _ = 0.`, `0.`, `untyped float`, `0`}, + {`package a4; const _ = 0i`, `0i`, `untyped complex`, `0`}, + {`package a5; const _ = "foo"`, `"foo"`, `untyped string`, `"foo"`}, + + {`package b0; var _ = false`, `false`, `bool`, `false`}, + {`package b1; var _ = 0`, `0`, `int`, `0`}, + {`package b2; var _ = 'A'`, `'A'`, `rune`, `65`}, + {`package b3; var _ = 0.`, `0.`, `float64`, `0`}, + {`package b4; var _ = 0i`, `0i`, `complex128`, `0`}, + {`package b5; var _ = "foo"`, `"foo"`, `string`, `"foo"`}, + + {`package c0a; var _ = bool(false)`, `false`, `bool`, `false`}, + {`package c0b; var _ = bool(false)`, `bool(false)`, `bool`, `false`}, + {`package c0c; type T bool; var _ = T(false)`, `T(false)`, `c0c.T`, `false`}, + + {`package c1a; var _ = int(0)`, `0`, `int`, `0`}, + {`package c1b; var _ = int(0)`, `int(0)`, `int`, `0`}, + {`package c1c; type T int; var _ = T(0)`, `T(0)`, `c1c.T`, `0`}, + + {`package c2a; var _ = rune('A')`, `'A'`, `rune`, `65`}, + {`package c2b; var _ = rune('A')`, `rune('A')`, `rune`, `65`}, + {`package c2c; type T rune; var _ = T('A')`, `T('A')`, `c2c.T`, `65`}, + + {`package c3a; var _ = float32(0.)`, `0.`, `float32`, `0`}, + {`package c3b; var _ = float32(0.)`, `float32(0.)`, `float32`, `0`}, + {`package c3c; type T float32; var _ = T(0.)`, `T(0.)`, `c3c.T`, `0`}, + + {`package c4a; var _ = complex64(0i)`, `0i`, `complex64`, `0`}, + {`package c4b; var _ = complex64(0i)`, `complex64(0i)`, `complex64`, `0`}, + {`package c4c; type T complex64; var _ = T(0i)`, `T(0i)`, `c4c.T`, `0`}, + + {`package c5a; var _ = string("foo")`, `"foo"`, `string`, `"foo"`}, + {`package c5b; var _ = string("foo")`, `string("foo")`, `string`, `"foo"`}, + {`package c5c; type T string; var _ = T("foo")`, `T("foo")`, `c5c.T`, `"foo"`}, + + {`package d0; var _ = []byte("foo")`, `"foo"`, `string`, `"foo"`}, + {`package d1; var _ = []byte(string("foo"))`, `"foo"`, `string`, `"foo"`}, + {`package d2; var _ = []byte(string("foo"))`, `string("foo")`, `string`, `"foo"`}, + {`package d3; type T []byte; var _ = T("foo")`, `"foo"`, `string`, `"foo"`}, + + {`package e0; const _ = float32( 1e-200)`, `float32(1e-200)`, `float32`, `0`}, + {`package e1; const _ = float32(-1e-200)`, `float32(-1e-200)`, `float32`, `0`}, + {`package e2; const _ = float64( 1e-2000)`, `float64(1e-2000)`, `float64`, `0`}, + {`package e3; const _ = float64(-1e-2000)`, `float64(-1e-2000)`, `float64`, `0`}, + {`package e4; const _ = complex64( 1e-200)`, `complex64(1e-200)`, `complex64`, `0`}, + {`package e5; const _ = complex64(-1e-200)`, `complex64(-1e-200)`, `complex64`, `0`}, + {`package e6; const _ = complex128( 1e-2000)`, `complex128(1e-2000)`, `complex128`, `0`}, + {`package e7; const _ = complex128(-1e-2000)`, `complex128(-1e-2000)`, `complex128`, `0`}, + + {`package f0 ; var _ float32 = 1e-200`, `1e-200`, `float32`, `0`}, + {`package f1 ; var _ float32 = -1e-200`, `-1e-200`, `float32`, `0`}, + {`package f2a; var _ float64 = 1e-2000`, `1e-2000`, `float64`, `0`}, + {`package f3a; var _ float64 = -1e-2000`, `-1e-2000`, `float64`, `0`}, + {`package f2b; var _ = 1e-2000`, `1e-2000`, `float64`, `0`}, + {`package f3b; var _ = -1e-2000`, `-1e-2000`, `float64`, `0`}, + {`package f4 ; var _ complex64 = 1e-200 `, `1e-200`, `complex64`, `0`}, + {`package f5 ; var _ complex64 = -1e-200 `, `-1e-200`, `complex64`, `0`}, + {`package f6a; var _ complex128 = 1e-2000i`, `1e-2000i`, `complex128`, `0`}, + {`package f7a; var _ complex128 = -1e-2000i`, `-1e-2000i`, `complex128`, `0`}, + {`package f6b; var _ = 1e-2000i`, `1e-2000i`, `complex128`, `0`}, + {`package f7b; var _ = -1e-2000i`, `-1e-2000i`, `complex128`, `0`}, + } + + for _, test := range tests { + info := Info{ + Types: make(map[ast.Expr]TypeAndValue), + } + name := mustTypecheck(t, "ValuesInfo", test.src, &info) + + // look for constant expression + var expr ast.Expr + for e := range info.Types { + if ExprString(e) == test.expr { + expr = e + break + } + } + if expr == nil { + t.Errorf("package %s: no expression found for %s", name, test.expr) + continue + } + tv := info.Types[expr] + + // check that type is correct + if got := tv.Type.String(); got != test.typ { + t.Errorf("package %s: got type %s; want %s", name, got, test.typ) + continue + } + + // check that value is correct + if got := tv.Value.String(); got != test.val { + t.Errorf("package %s: got value %s; want %s", name, got, test.val) + } + } +} + +func TestTypesInfo(t *testing.T) { + var tests = []struct { + src string + expr string // expression + typ string // value type + }{ + // single-valued expressions of untyped constants + {`package b0; var x interface{} = false`, `false`, `bool`}, + {`package b1; var x interface{} = 0`, `0`, `int`}, + {`package b2; var x interface{} = 0.`, `0.`, `float64`}, + {`package b3; var x interface{} = 0i`, `0i`, `complex128`}, + {`package b4; var x interface{} = "foo"`, `"foo"`, `string`}, + + // comma-ok expressions + {`package p0; var x interface{}; var _, _ = x.(int)`, + `x.(int)`, + `(int, bool)`, + }, + {`package p1; var x interface{}; func _() { _, _ = x.(int) }`, + `x.(int)`, + `(int, bool)`, + }, + // TODO(gri): uncomment if we accept issue 8189. + // {`package p2; type mybool bool; var m map[string]complex128; var b mybool; func _() { _, b = m["foo"] }`, + // `m["foo"]`, + // `(complex128, p2.mybool)`, + // }, + // TODO(gri): remove if we accept issue 8189. + {`package p2; var m map[string]complex128; var b bool; func _() { _, b = m["foo"] }`, + `m["foo"]`, + `(complex128, bool)`, + }, + {`package p3; var c chan string; var _, _ = <-c`, + `<-c`, + `(string, bool)`, + }, + + // issue 6796 + {`package issue6796_a; var x interface{}; var _, _ = (x.(int))`, + `x.(int)`, + `(int, bool)`, + }, + {`package issue6796_b; var c chan string; var _, _ = (<-c)`, + `(<-c)`, + `(string, bool)`, + }, + {`package issue6796_c; var c chan string; var _, _ = (<-c)`, + `<-c`, + `(string, bool)`, + }, + {`package issue6796_d; var c chan string; var _, _ = ((<-c))`, + `(<-c)`, + `(string, bool)`, + }, + {`package issue6796_e; func f(c chan string) { _, _ = ((<-c)) }`, + `(<-c)`, + `(string, bool)`, + }, + + // issue 7060 + {`package issue7060_a; var ( m map[int]string; x, ok = m[0] )`, + `m[0]`, + `(string, bool)`, + }, + {`package issue7060_b; var ( m map[int]string; x, ok interface{} = m[0] )`, + `m[0]`, + `(string, bool)`, + }, + {`package issue7060_c; func f(x interface{}, ok bool, m map[int]string) { x, ok = m[0] }`, + `m[0]`, + `(string, bool)`, + }, + {`package issue7060_d; var ( ch chan string; x, ok = <-ch )`, + `<-ch`, + `(string, bool)`, + }, + {`package issue7060_e; var ( ch chan string; x, ok interface{} = <-ch )`, + `<-ch`, + `(string, bool)`, + }, + {`package issue7060_f; func f(x interface{}, ok bool, ch chan string) { x, ok = <-ch }`, + `<-ch`, + `(string, bool)`, + }, + } + + for _, test := range tests { + info := Info{Types: make(map[ast.Expr]TypeAndValue)} + name := mustTypecheck(t, "TypesInfo", test.src, &info) + + // look for expression type + var typ Type + for e, tv := range info.Types { + if ExprString(e) == test.expr { + typ = tv.Type + break + } + } + if typ == nil { + t.Errorf("package %s: no type found for %s", name, test.expr) + continue + } + + // check that type is correct + if got := typ.String(); got != test.typ { + t.Errorf("package %s: got %s; want %s", name, got, test.typ) + } + } +} + +func predString(tv TypeAndValue) string { + var buf bytes.Buffer + pred := func(b bool, s string) { + if b { + if buf.Len() > 0 { + buf.WriteString(", ") + } + buf.WriteString(s) + } + } + + pred(tv.IsVoid(), "void") + pred(tv.IsType(), "type") + pred(tv.IsBuiltin(), "builtin") + pred(tv.IsValue() && tv.Value != nil, "const") + pred(tv.IsValue() && tv.Value == nil, "value") + pred(tv.IsNil(), "nil") + pred(tv.Addressable(), "addressable") + pred(tv.Assignable(), "assignable") + pred(tv.HasOk(), "hasOk") + + if buf.Len() == 0 { + return "invalid" + } + return buf.String() +} + +func TestPredicatesInfo(t *testing.T) { + testenv.MustHaveGoBuild(t) + + var tests = []struct { + src string + expr string + pred string + }{ + // void + {`package n0; func f() { f() }`, `f()`, `void`}, + + // types + {`package t0; type _ int`, `int`, `type`}, + {`package t1; type _ []int`, `[]int`, `type`}, + {`package t2; type _ func()`, `func()`, `type`}, + + // built-ins + {`package b0; var _ = len("")`, `len`, `builtin`}, + {`package b1; var _ = (len)("")`, `(len)`, `builtin`}, + + // constants + {`package c0; var _ = 42`, `42`, `const`}, + {`package c1; var _ = "foo" + "bar"`, `"foo" + "bar"`, `const`}, + {`package c2; const (i = 1i; _ = i)`, `i`, `const`}, + + // values + {`package v0; var (a, b int; _ = a + b)`, `a + b`, `value`}, + {`package v1; var _ = &[]int{1}`, `([]int literal)`, `value`}, + {`package v2; var _ = func(){}`, `(func() literal)`, `value`}, + {`package v4; func f() { _ = f }`, `f`, `value`}, + {`package v3; var _ *int = nil`, `nil`, `value, nil`}, + {`package v3; var _ *int = (nil)`, `(nil)`, `value, nil`}, + + // addressable (and thus assignable) operands + {`package a0; var (x int; _ = x)`, `x`, `value, addressable, assignable`}, + {`package a1; var (p *int; _ = *p)`, `*p`, `value, addressable, assignable`}, + {`package a2; var (s []int; _ = s[0])`, `s[0]`, `value, addressable, assignable`}, + {`package a3; var (s struct{f int}; _ = s.f)`, `s.f`, `value, addressable, assignable`}, + {`package a4; var (a [10]int; _ = a[0])`, `a[0]`, `value, addressable, assignable`}, + {`package a5; func _(x int) { _ = x }`, `x`, `value, addressable, assignable`}, + {`package a6; func _()(x int) { _ = x; return }`, `x`, `value, addressable, assignable`}, + {`package a7; type T int; func (x T) _() { _ = x }`, `x`, `value, addressable, assignable`}, + // composite literals are not addressable + + // assignable but not addressable values + {`package s0; var (m map[int]int; _ = m[0])`, `m[0]`, `value, assignable, hasOk`}, + {`package s1; var (m map[int]int; _, _ = m[0])`, `m[0]`, `value, assignable, hasOk`}, + + // hasOk expressions + {`package k0; var (ch chan int; _ = <-ch)`, `<-ch`, `value, hasOk`}, + {`package k1; var (ch chan int; _, _ = <-ch)`, `<-ch`, `value, hasOk`}, + + // missing entries + // - package names are collected in the Uses map + // - identifiers being declared are collected in the Defs map + {`package m0; import "os"; func _() { _ = os.Stdout }`, `os`, ``}, + {`package m1; import p "os"; func _() { _ = p.Stdout }`, `p`, ``}, + {`package m2; const c = 0`, `c`, ``}, + {`package m3; type T int`, `T`, ``}, + {`package m4; var v int`, `v`, ``}, + {`package m5; func f() {}`, `f`, ``}, + {`package m6; func _(x int) {}`, `x`, ``}, + {`package m6; func _()(x int) { return }`, `x`, ``}, + {`package m6; type T int; func (x T) _() {}`, `x`, ``}, + } + + for _, test := range tests { + info := Info{Types: make(map[ast.Expr]TypeAndValue)} + name := mustTypecheck(t, "PredicatesInfo", test.src, &info) + + // look for expression predicates + got := "" + for e, tv := range info.Types { + //println(name, ExprString(e)) + if ExprString(e) == test.expr { + got = predString(tv) + break + } + } + + if got != test.pred { + t.Errorf("package %s: got %s; want %s", name, got, test.pred) + } + } +} + +func TestScopesInfo(t *testing.T) { + testenv.MustHaveGoBuild(t) + + var tests = []struct { + src string + scopes []string // list of scope descriptors of the form kind:varlist + }{ + {`package p0`, []string{ + "file:", + }}, + {`package p1; import ( "fmt"; m "math"; _ "os" ); var ( _ = fmt.Println; _ = m.Pi )`, []string{ + "file:fmt m", + }}, + {`package p2; func _() {}`, []string{ + "file:", "func:", + }}, + {`package p3; func _(x, y int) {}`, []string{ + "file:", "func:x y", + }}, + {`package p4; func _(x, y int) { x, z := 1, 2; _ = z }`, []string{ + "file:", "func:x y z", // redeclaration of x + }}, + {`package p5; func _(x, y int) (u, _ int) { return }`, []string{ + "file:", "func:u x y", + }}, + {`package p6; func _() { { var x int; _ = x } }`, []string{ + "file:", "func:", "block:x", + }}, + {`package p7; func _() { if true {} }`, []string{ + "file:", "func:", "if:", "block:", + }}, + {`package p8; func _() { if x := 0; x < 0 { y := x; _ = y } }`, []string{ + "file:", "func:", "if:x", "block:y", + }}, + {`package p9; func _() { switch x := 0; x {} }`, []string{ + "file:", "func:", "switch:x", + }}, + {`package p10; func _() { switch x := 0; x { case 1: y := x; _ = y; default: }}`, []string{ + "file:", "func:", "switch:x", "case:y", "case:", + }}, + {`package p11; func _(t interface{}) { switch t.(type) {} }`, []string{ + "file:", "func:t", "type switch:", + }}, + {`package p12; func _(t interface{}) { switch t := t; t.(type) {} }`, []string{ + "file:", "func:t", "type switch:t", + }}, + {`package p13; func _(t interface{}) { switch x := t.(type) { case int: _ = x } }`, []string{ + "file:", "func:t", "type switch:", "case:x", // x implicitly declared + }}, + {`package p14; func _() { select{} }`, []string{ + "file:", "func:", + }}, + {`package p15; func _(c chan int) { select{ case <-c: } }`, []string{ + "file:", "func:c", "comm:", + }}, + {`package p16; func _(c chan int) { select{ case i := <-c: x := i; _ = x} }`, []string{ + "file:", "func:c", "comm:i x", + }}, + {`package p17; func _() { for{} }`, []string{ + "file:", "func:", "for:", "block:", + }}, + {`package p18; func _(n int) { for i := 0; i < n; i++ { _ = i } }`, []string{ + "file:", "func:n", "for:i", "block:", + }}, + {`package p19; func _(a []int) { for i := range a { _ = i} }`, []string{ + "file:", "func:a", "range:i", "block:", + }}, + {`package p20; var s int; func _(a []int) { for i, x := range a { s += x; _ = i } }`, []string{ + "file:", "func:a", "range:i x", "block:", + }}, + } + + for _, test := range tests { + info := Info{Scopes: make(map[ast.Node]*Scope)} + name := mustTypecheck(t, "ScopesInfo", test.src, &info) + + // number of scopes must match + if len(info.Scopes) != len(test.scopes) { + t.Errorf("package %s: got %d scopes; want %d", name, len(info.Scopes), len(test.scopes)) + } + + // scope descriptions must match + for node, scope := range info.Scopes { + kind := "" + switch node.(type) { + case *ast.File: + kind = "file" + case *ast.FuncType: + kind = "func" + case *ast.BlockStmt: + kind = "block" + case *ast.IfStmt: + kind = "if" + case *ast.SwitchStmt: + kind = "switch" + case *ast.TypeSwitchStmt: + kind = "type switch" + case *ast.CaseClause: + kind = "case" + case *ast.CommClause: + kind = "comm" + case *ast.ForStmt: + kind = "for" + case *ast.RangeStmt: + kind = "range" + } + + // look for matching scope description + desc := kind + ":" + strings.Join(scope.Names(), " ") + found := false + for _, d := range test.scopes { + if desc == d { + found = true + break + } + } + if !found { + t.Errorf("package %s: no matching scope found for %s", name, desc) + } + } + } +} + +func TestInitOrderInfo(t *testing.T) { + var tests = []struct { + src string + inits []string + }{ + {`package p0; var (x = 1; y = x)`, []string{ + "x = 1", "y = x", + }}, + {`package p1; var (a = 1; b = 2; c = 3)`, []string{ + "a = 1", "b = 2", "c = 3", + }}, + {`package p2; var (a, b, c = 1, 2, 3)`, []string{ + "a = 1", "b = 2", "c = 3", + }}, + {`package p3; var _ = f(); func f() int { return 1 }`, []string{ + "_ = f()", // blank var + }}, + {`package p4; var (a = 0; x = y; y = z; z = 0)`, []string{ + "a = 0", "z = 0", "y = z", "x = y", + }}, + {`package p5; var (a, _ = m[0]; m map[int]string)`, []string{ + "a, _ = m[0]", // blank var + }}, + {`package p6; var a, b = f(); func f() (_, _ int) { return z, z }; var z = 0`, []string{ + "z = 0", "a, b = f()", + }}, + {`package p7; var (a = func() int { return b }(); b = 1)`, []string{ + "b = 1", "a = (func() int literal)()", + }}, + {`package p8; var (a, b = func() (_, _ int) { return c, c }(); c = 1)`, []string{ + "c = 1", "a, b = (func() (_, _ int) literal)()", + }}, + {`package p9; type T struct{}; func (T) m() int { _ = y; return 0 }; var x, y = T.m, 1`, []string{ + "y = 1", "x = T.m", + }}, + {`package p10; var (d = c + b; a = 0; b = 0; c = 0)`, []string{ + "a = 0", "b = 0", "c = 0", "d = c + b", + }}, + {`package p11; var (a = e + c; b = d + c; c = 0; d = 0; e = 0)`, []string{ + "c = 0", "d = 0", "b = d + c", "e = 0", "a = e + c", + }}, + // emit an initializer for n:1 initializations only once (not for each node + // on the lhs which may appear in different order in the dependency graph) + {`package p12; var (a = x; b = 0; x, y = m[0]; m map[int]int)`, []string{ + "b = 0", "x, y = m[0]", "a = x", + }}, + // test case from spec section on package initialization + {`package p12 + + var ( + a = c + b + b = f() + c = f() + d = 3 + ) + + func f() int { + d++ + return d + }`, []string{ + "d = 3", "b = f()", "c = f()", "a = c + b", + }}, + // test case for issue 7131 + {`package main + + var counter int + func next() int { counter++; return counter } + + var _ = makeOrder() + func makeOrder() []int { return []int{f, b, d, e, c, a} } + + var a = next() + var b, c = next(), next() + var d, e, f = next(), next(), next() + `, []string{ + "a = next()", "b = next()", "c = next()", "d = next()", "e = next()", "f = next()", "_ = makeOrder()", + }}, + } + + for _, test := range tests { + info := Info{} + name := mustTypecheck(t, "InitOrderInfo", test.src, &info) + + // number of initializers must match + if len(info.InitOrder) != len(test.inits) { + t.Errorf("package %s: got %d initializers; want %d", name, len(info.InitOrder), len(test.inits)) + continue + } + + // initializers must match + for i, want := range test.inits { + got := info.InitOrder[i].String() + if got != want { + t.Errorf("package %s, init %d: got %s; want %s", name, i, got, want) + continue + } + } + } +} + +func TestMultiFileInitOrder(t *testing.T) { + fset := token.NewFileSet() + mustParse := func(src string) *ast.File { + f, err := parser.ParseFile(fset, "main", src, 0) + if err != nil { + t.Fatal(err) + } + return f + } + + fileA := mustParse(`package main; var a = 1`) + fileB := mustParse(`package main; var b = 2`) + + // The initialization order must not depend on the parse + // order of the files, only on the presentation order to + // the type-checker. + for _, test := range []struct { + files []*ast.File + want string + }{ + {[]*ast.File{fileA, fileB}, "[a = 1 b = 2]"}, + {[]*ast.File{fileB, fileA}, "[b = 2 a = 1]"}, + } { + var info Info + if _, err := new(Config).Check("main", fset, test.files, &info); err != nil { + t.Fatal(err) + } + if got := fmt.Sprint(info.InitOrder); got != test.want { + t.Fatalf("got %s; want %s", got, test.want) + } + } +} + +func TestFiles(t *testing.T) { + var sources = []string{ + "package p; type T struct{}; func (T) m1() {}", + "package p; func (T) m2() {}; var x interface{ m1(); m2() } = T{}", + "package p; func (T) m3() {}; var y interface{ m1(); m2(); m3() } = T{}", + "package p", + } + + var conf Config + fset := token.NewFileSet() + pkg := NewPackage("p", "p") + var info Info + check := NewChecker(&conf, fset, pkg, &info) + + for i, src := range sources { + filename := fmt.Sprintf("sources%d", i) + f, err := parser.ParseFile(fset, filename, src, 0) + if err != nil { + t.Fatal(err) + } + if err := check.Files([]*ast.File{f}); err != nil { + t.Error(err) + } + } + + // check InitOrder is [x y] + var vars []string + for _, init := range info.InitOrder { + for _, v := range init.Lhs { + vars = append(vars, v.Name()) + } + } + if got, want := fmt.Sprint(vars), "[x y]"; got != want { + t.Errorf("InitOrder == %s, want %s", got, want) + } +} + +type testImporter map[string]*Package + +func (m testImporter) Import(path string) (*Package, error) { + if pkg := m[path]; pkg != nil { + return pkg, nil + } + return nil, fmt.Errorf("package %q not found", path) +} + +func TestSelection(t *testing.T) { + selections := make(map[*ast.SelectorExpr]*Selection) + + fset := token.NewFileSet() + imports := make(testImporter) + conf := Config{Importer: imports} + makePkg := func(path, src string) { + f, err := parser.ParseFile(fset, path+".go", src, 0) + if err != nil { + t.Fatal(err) + } + pkg, err := conf.Check(path, fset, []*ast.File{f}, &Info{Selections: selections}) + if err != nil { + t.Fatal(err) + } + imports[path] = pkg + } + + const libSrc = ` +package lib +type T float64 +const C T = 3 +var V T +func F() {} +func (T) M() {} +` + const mainSrc = ` +package main +import "lib" + +type A struct { + *B + C +} + +type B struct { + b int +} + +func (B) f(int) + +type C struct { + c int +} + +func (C) g() +func (*C) h() + +func main() { + // qualified identifiers + var _ lib.T + _ = lib.C + _ = lib.F + _ = lib.V + _ = lib.T.M + + // fields + _ = A{}.B + _ = new(A).B + + _ = A{}.C + _ = new(A).C + + _ = A{}.b + _ = new(A).b + + _ = A{}.c + _ = new(A).c + + // methods + _ = A{}.f + _ = new(A).f + _ = A{}.g + _ = new(A).g + _ = new(A).h + + _ = B{}.f + _ = new(B).f + + _ = C{}.g + _ = new(C).g + _ = new(C).h + + // method expressions + _ = A.f + _ = (*A).f + _ = B.f + _ = (*B).f +}` + + wantOut := map[string][2]string{ + "lib.T.M": {"method expr (lib.T) M(lib.T)", ".[0]"}, + + "A{}.B": {"field (main.A) B *main.B", ".[0]"}, + "new(A).B": {"field (*main.A) B *main.B", "->[0]"}, + "A{}.C": {"field (main.A) C main.C", ".[1]"}, + "new(A).C": {"field (*main.A) C main.C", "->[1]"}, + "A{}.b": {"field (main.A) b int", "->[0 0]"}, + "new(A).b": {"field (*main.A) b int", "->[0 0]"}, + "A{}.c": {"field (main.A) c int", ".[1 0]"}, + "new(A).c": {"field (*main.A) c int", "->[1 0]"}, + + "A{}.f": {"method (main.A) f(int)", "->[0 0]"}, + "new(A).f": {"method (*main.A) f(int)", "->[0 0]"}, + "A{}.g": {"method (main.A) g()", ".[1 0]"}, + "new(A).g": {"method (*main.A) g()", "->[1 0]"}, + "new(A).h": {"method (*main.A) h()", "->[1 1]"}, // TODO(gri) should this report .[1 1] ? + "B{}.f": {"method (main.B) f(int)", ".[0]"}, + "new(B).f": {"method (*main.B) f(int)", "->[0]"}, + "C{}.g": {"method (main.C) g()", ".[0]"}, + "new(C).g": {"method (*main.C) g()", "->[0]"}, + "new(C).h": {"method (*main.C) h()", "->[1]"}, // TODO(gri) should this report .[1] ? + + "A.f": {"method expr (main.A) f(main.A, int)", "->[0 0]"}, + "(*A).f": {"method expr (*main.A) f(*main.A, int)", "->[0 0]"}, + "B.f": {"method expr (main.B) f(main.B, int)", ".[0]"}, + "(*B).f": {"method expr (*main.B) f(*main.B, int)", "->[0]"}, + } + + makePkg("lib", libSrc) + makePkg("main", mainSrc) + + for e, sel := range selections { + sel.String() // assertion: must not panic + + start := fset.Position(e.Pos()).Offset + end := fset.Position(e.End()).Offset + syntax := mainSrc[start:end] // (all SelectorExprs are in main, not lib) + + direct := "." + if sel.Indirect() { + direct = "->" + } + got := [2]string{ + sel.String(), + fmt.Sprintf("%s%v", direct, sel.Index()), + } + want := wantOut[syntax] + if want != got { + t.Errorf("%s: got %q; want %q", syntax, got, want) + } + delete(wantOut, syntax) + + // We must explicitly assert properties of the + // Signature's receiver since it doesn't participate + // in Identical() or String(). + sig, _ := sel.Type().(*Signature) + if sel.Kind() == MethodVal { + got := sig.Recv().Type() + want := sel.Recv() + if !Identical(got, want) { + t.Errorf("%s: Recv() = %s, want %s", syntax, got, want) + } + } else if sig != nil && sig.Recv() != nil { + t.Errorf("%s: signature has receiver %s", sig, sig.Recv().Type()) + } + } + // Assert that all wantOut entries were used exactly once. + for syntax := range wantOut { + t.Errorf("no ast.Selection found with syntax %q", syntax) + } +} + +func TestIssue8518(t *testing.T) { + fset := token.NewFileSet() + imports := make(testImporter) + conf := Config{ + Error: func(err error) { t.Log(err) }, // don't exit after first error + Importer: imports, + } + makePkg := func(path, src string) { + f, err := parser.ParseFile(fset, path, src, 0) + if err != nil { + t.Fatal(err) + } + pkg, _ := conf.Check(path, fset, []*ast.File{f}, nil) // errors logged via conf.Error + imports[path] = pkg + } + + const libSrc = ` +package a +import "missing" +const C1 = foo +const C2 = missing.C +` + + const mainSrc = ` +package main +import "a" +var _ = a.C1 +var _ = a.C2 +` + + makePkg("a", libSrc) + makePkg("main", mainSrc) // don't crash when type-checking this package +} + +func TestLookupFieldOrMethod(t *testing.T) { + // Test cases assume a lookup of the form a.f or x.f, where a stands for an + // addressable value, and x for a non-addressable value (even though a variable + // for ease of test case writing). + var tests = []struct { + src string + found bool + index []int + indirect bool + }{ + // field lookups + {"var x T; type T struct{}", false, nil, false}, + {"var x T; type T struct{ f int }", true, []int{0}, false}, + {"var x T; type T struct{ a, b, f, c int }", true, []int{2}, false}, + + // method lookups + {"var a T; type T struct{}; func (T) f() {}", true, []int{0}, false}, + {"var a *T; type T struct{}; func (T) f() {}", true, []int{0}, true}, + {"var a T; type T struct{}; func (*T) f() {}", true, []int{0}, false}, + {"var a *T; type T struct{}; func (*T) f() {}", true, []int{0}, true}, // TODO(gri) should this report indirect = false? + + // collisions + {"type ( E1 struct{ f int }; E2 struct{ f int }; x struct{ E1; *E2 })", false, []int{1, 0}, false}, + {"type ( E1 struct{ f int }; E2 struct{}; x struct{ E1; *E2 }); func (E2) f() {}", false, []int{1, 0}, false}, + + // outside methodset + // (*T).f method exists, but value of type T is not addressable + {"var x T; type T struct{}; func (*T) f() {}", false, nil, true}, + } + + for _, test := range tests { + pkg, err := pkgFor("test", "package p;"+test.src, nil) + if err != nil { + t.Errorf("%s: incorrect test case: %s", test.src, err) + continue + } + + obj := pkg.Scope().Lookup("a") + if obj == nil { + if obj = pkg.Scope().Lookup("x"); obj == nil { + t.Errorf("%s: incorrect test case - no object a or x", test.src) + continue + } + } + + f, index, indirect := LookupFieldOrMethod(obj.Type(), obj.Name() == "a", pkg, "f") + if (f != nil) != test.found { + if f == nil { + t.Errorf("%s: got no object; want one", test.src) + } else { + t.Errorf("%s: got object = %v; want none", test.src, f) + } + } + if !sameSlice(index, test.index) { + t.Errorf("%s: got index = %v; want %v", test.src, index, test.index) + } + if indirect != test.indirect { + t.Errorf("%s: got indirect = %v; want %v", test.src, indirect, test.indirect) + } + } +} + +func sameSlice(a, b []int) bool { + if len(a) != len(b) { + return false + } + for i, x := range a { + if x != b[i] { + return false + } + } + return true +} + +// TestScopeLookupParent ensures that (*Scope).LookupParent returns +// the correct result at various positions with the source. +func TestScopeLookupParent(t *testing.T) { + fset := token.NewFileSet() + imports := make(testImporter) + conf := Config{Importer: imports} + mustParse := func(src string) *ast.File { + f, err := parser.ParseFile(fset, "dummy.go", src, parser.ParseComments) + if err != nil { + t.Fatal(err) + } + return f + } + var info Info + makePkg := func(path string, files ...*ast.File) { + imports[path], _ = conf.Check(path, fset, files, &info) + } + + makePkg("lib", mustParse("package lib; var X int")) + // Each /*name=kind:line*/ comment makes the test look up the + // name at that point and checks that it resolves to a decl of + // the specified kind and line number. "undef" means undefined. + mainSrc := ` +package main +import "lib" +var Y = lib.X +func f() { + print(Y) /*Y=var:4*/ + z /*z=undef*/ := /*z=undef*/ 1 /*z=var:7*/ + print(z) + /*f=func:5*/ /*lib=pkgname:3*/ + type /*T=undef*/ T /*T=typename:10*/ *T +} +` + info.Uses = make(map[*ast.Ident]Object) + f := mustParse(mainSrc) + makePkg("main", f) + mainScope := imports["main"].Scope() + rx := regexp.MustCompile(`^/\*(\w*)=([\w:]*)\*/$`) + for _, group := range f.Comments { + for _, comment := range group.List { + // Parse the assertion in the comment. + m := rx.FindStringSubmatch(comment.Text) + if m == nil { + t.Errorf("%s: bad comment: %s", + fset.Position(comment.Pos()), comment.Text) + continue + } + name, want := m[1], m[2] + + // Look up the name in the innermost enclosing scope. + inner := mainScope.Innermost(comment.Pos()) + if inner == nil { + t.Errorf("%s: at %s: can't find innermost scope", + fset.Position(comment.Pos()), comment.Text) + continue + } + got := "undef" + if _, obj := inner.LookupParent(name, comment.Pos()); obj != nil { + kind := strings.ToLower(strings.TrimPrefix(reflect.TypeOf(obj).String(), "*types.")) + got = fmt.Sprintf("%s:%d", kind, fset.Position(obj.Pos()).Line) + } + if got != want { + t.Errorf("%s: at %s: %s resolved to %s, want %s", + fset.Position(comment.Pos()), comment.Text, name, got, want) + } + } + } + + // Check that for each referring identifier, + // a lookup of its name on the innermost + // enclosing scope returns the correct object. + + for id, wantObj := range info.Uses { + inner := mainScope.Innermost(id.Pos()) + if inner == nil { + t.Errorf("%s: can't find innermost scope enclosing %q", + fset.Position(id.Pos()), id.Name) + continue + } + + // Exclude selectors and qualified identifiers---lexical + // refs only. (Ideally, we'd see if the AST parent is a + // SelectorExpr, but that requires PathEnclosingInterval + // from golang.org/x/tools/go/ast/astutil.) + if id.Name == "X" { + continue + } + + _, gotObj := inner.LookupParent(id.Name, id.Pos()) + if gotObj != wantObj { + t.Errorf("%s: got %v, want %v", + fset.Position(id.Pos()), gotObj, wantObj) + continue + } + } +} diff --git a/libgo/go/go/types/assignments.go b/libgo/go/go/types/assignments.go new file mode 100644 index 00000000000..e88de56a0da --- /dev/null +++ b/libgo/go/go/types/assignments.go @@ -0,0 +1,328 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file implements initialization and assignment checks. + +package types + +import ( + "go/ast" + "go/token" +) + +// assignment reports whether x can be assigned to a variable of type T, +// if necessary by attempting to convert untyped values to the appropriate +// type. If x.mode == invalid upon return, then assignment has already +// issued an error message and the caller doesn't have to report another. +// Use T == nil to indicate assignment to an untyped blank identifier. +// +// TODO(gri) Should find a better way to handle in-band errors. +// +func (check *Checker) assignment(x *operand, T Type) bool { + switch x.mode { + case invalid: + return true // error reported before + case constant_, variable, mapindex, value, commaok: + // ok + default: + unreachable() + } + + // x must be a single value + // (tuple types are never named - no need for underlying type) + if t, _ := x.typ.(*Tuple); t != nil { + assert(t.Len() > 1) + check.errorf(x.pos(), "%d-valued expression %s used as single value", t.Len(), x) + x.mode = invalid + return false + } + + if isUntyped(x.typ) { + target := T + // spec: "If an untyped constant is assigned to a variable of interface + // type or the blank identifier, the constant is first converted to type + // bool, rune, int, float64, complex128 or string respectively, depending + // on whether the value is a boolean, rune, integer, floating-point, complex, + // or string constant." + if T == nil || IsInterface(T) { + if T == nil && x.typ == Typ[UntypedNil] { + check.errorf(x.pos(), "use of untyped nil") + x.mode = invalid + return false + } + target = defaultType(x.typ) + } + check.convertUntyped(x, target) + if x.mode == invalid { + return false + } + } + + // spec: "If a left-hand side is the blank identifier, any typed or + // non-constant value except for the predeclared identifier nil may + // be assigned to it." + return T == nil || x.assignableTo(check.conf, T) +} + +func (check *Checker) initConst(lhs *Const, x *operand) { + if x.mode == invalid || x.typ == Typ[Invalid] || lhs.typ == Typ[Invalid] { + if lhs.typ == nil { + lhs.typ = Typ[Invalid] + } + return + } + + // rhs must be a constant + if x.mode != constant_ { + check.errorf(x.pos(), "%s is not constant", x) + if lhs.typ == nil { + lhs.typ = Typ[Invalid] + } + return + } + assert(isConstType(x.typ)) + + // If the lhs doesn't have a type yet, use the type of x. + if lhs.typ == nil { + lhs.typ = x.typ + } + + if !check.assignment(x, lhs.typ) { + if x.mode != invalid { + check.errorf(x.pos(), "cannot define constant %s (type %s) as %s", lhs.Name(), lhs.typ, x) + } + return + } + + lhs.val = x.val +} + +// If result is set, lhs is a function result parameter and x is a return result. +func (check *Checker) initVar(lhs *Var, x *operand, result bool) Type { + if x.mode == invalid || x.typ == Typ[Invalid] || lhs.typ == Typ[Invalid] { + if lhs.typ == nil { + lhs.typ = Typ[Invalid] + } + return nil + } + + // If the lhs doesn't have a type yet, use the type of x. + if lhs.typ == nil { + typ := x.typ + if isUntyped(typ) { + // convert untyped types to default types + if typ == Typ[UntypedNil] { + check.errorf(x.pos(), "use of untyped nil") + lhs.typ = Typ[Invalid] + return nil + } + typ = defaultType(typ) + } + lhs.typ = typ + } + + if !check.assignment(x, lhs.typ) { + if x.mode != invalid { + if result { + // don't refer to lhs.name because it may be an anonymous result parameter + check.errorf(x.pos(), "cannot return %s as value of type %s", x, lhs.typ) + } else { + check.errorf(x.pos(), "cannot initialize %s with %s", lhs, x) + } + } + return nil + } + + return x.typ +} + +func (check *Checker) assignVar(lhs ast.Expr, x *operand) Type { + if x.mode == invalid || x.typ == Typ[Invalid] { + return nil + } + + // Determine if the lhs is a (possibly parenthesized) identifier. + ident, _ := unparen(lhs).(*ast.Ident) + + // Don't evaluate lhs if it is the blank identifier. + if ident != nil && ident.Name == "_" { + check.recordDef(ident, nil) + if !check.assignment(x, nil) { + assert(x.mode == invalid) + x.typ = nil + } + return x.typ + } + + // If the lhs is an identifier denoting a variable v, this assignment + // is not a 'use' of v. Remember current value of v.used and restore + // after evaluating the lhs via check.expr. + var v *Var + var v_used bool + if ident != nil { + if _, obj := check.scope.LookupParent(ident.Name, token.NoPos); obj != nil { + v, _ = obj.(*Var) + if v != nil { + v_used = v.used + } + } + } + + var z operand + check.expr(&z, lhs) + if v != nil { + v.used = v_used // restore v.used + } + + if z.mode == invalid || z.typ == Typ[Invalid] { + return nil + } + + // spec: "Each left-hand side operand must be addressable, a map index + // expression, or the blank identifier. Operands may be parenthesized." + switch z.mode { + case invalid: + return nil + case variable, mapindex: + // ok + default: + check.errorf(z.pos(), "cannot assign to %s", &z) + return nil + } + + if !check.assignment(x, z.typ) { + if x.mode != invalid { + check.errorf(x.pos(), "cannot assign %s to %s", x, &z) + } + return nil + } + + return x.typ +} + +// If returnPos is valid, initVars is called to type-check the assignment of +// return expressions, and returnPos is the position of the return statement. +func (check *Checker) initVars(lhs []*Var, rhs []ast.Expr, returnPos token.Pos) { + l := len(lhs) + get, r, commaOk := unpack(func(x *operand, i int) { check.expr(x, rhs[i]) }, len(rhs), l == 2 && !returnPos.IsValid()) + if get == nil || l != r { + // invalidate lhs and use rhs + for _, obj := range lhs { + if obj.typ == nil { + obj.typ = Typ[Invalid] + } + } + if get == nil { + return // error reported by unpack + } + check.useGetter(get, r) + if returnPos.IsValid() { + check.errorf(returnPos, "wrong number of return values (want %d, got %d)", l, r) + return + } + check.errorf(rhs[0].Pos(), "assignment count mismatch (%d vs %d)", l, r) + return + } + + var x operand + if commaOk { + var a [2]Type + for i := range a { + get(&x, i) + a[i] = check.initVar(lhs[i], &x, returnPos.IsValid()) + } + check.recordCommaOkTypes(rhs[0], a) + return + } + + for i, lhs := range lhs { + get(&x, i) + check.initVar(lhs, &x, returnPos.IsValid()) + } +} + +func (check *Checker) assignVars(lhs, rhs []ast.Expr) { + l := len(lhs) + get, r, commaOk := unpack(func(x *operand, i int) { check.expr(x, rhs[i]) }, len(rhs), l == 2) + if get == nil { + return // error reported by unpack + } + if l != r { + check.useGetter(get, r) + check.errorf(rhs[0].Pos(), "assignment count mismatch (%d vs %d)", l, r) + return + } + + var x operand + if commaOk { + var a [2]Type + for i := range a { + get(&x, i) + a[i] = check.assignVar(lhs[i], &x) + } + check.recordCommaOkTypes(rhs[0], a) + return + } + + for i, lhs := range lhs { + get(&x, i) + check.assignVar(lhs, &x) + } +} + +func (check *Checker) shortVarDecl(pos token.Pos, lhs, rhs []ast.Expr) { + scope := check.scope + + // collect lhs variables + var newVars []*Var + var lhsVars = make([]*Var, len(lhs)) + for i, lhs := range lhs { + var obj *Var + if ident, _ := lhs.(*ast.Ident); ident != nil { + // Use the correct obj if the ident is redeclared. The + // variable's scope starts after the declaration; so we + // must use Scope.Lookup here and call Scope.Insert + // (via check.declare) later. + name := ident.Name + if alt := scope.Lookup(name); alt != nil { + // redeclared object must be a variable + if alt, _ := alt.(*Var); alt != nil { + obj = alt + } else { + check.errorf(lhs.Pos(), "cannot assign to %s", lhs) + } + check.recordUse(ident, alt) + } else { + // declare new variable, possibly a blank (_) variable + obj = NewVar(ident.Pos(), check.pkg, name, nil) + if name != "_" { + newVars = append(newVars, obj) + } + check.recordDef(ident, obj) + } + } else { + check.errorf(lhs.Pos(), "cannot declare %s", lhs) + } + if obj == nil { + obj = NewVar(lhs.Pos(), check.pkg, "_", nil) // dummy variable + } + lhsVars[i] = obj + } + + check.initVars(lhsVars, rhs, token.NoPos) + + // declare new variables + if len(newVars) > 0 { + // spec: "The scope of a constant or variable identifier declared inside + // a function begins at the end of the ConstSpec or VarSpec (ShortVarDecl + // for short variable declarations) and ends at the end of the innermost + // containing block." + scopePos := rhs[len(rhs)-1].End() + for _, obj := range newVars { + check.declare(scope, nil, obj, scopePos) // recordObject already called + } + } else { + check.softErrorf(pos, "no new variables on left side of :=") + } +} diff --git a/libgo/go/go/types/builtins.go b/libgo/go/go/types/builtins.go new file mode 100644 index 00000000000..47295914d00 --- /dev/null +++ b/libgo/go/go/types/builtins.go @@ -0,0 +1,627 @@ +// 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 typechecking of builtin function calls. + +package types + +import ( + "go/ast" + "go/constant" + "go/token" +) + +// builtin type-checks a call to the built-in specified by id and +// returns true if the call is valid, with *x holding the result; +// but x.expr is not set. If the call is invalid, the result is +// false, and *x is undefined. +// +func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ bool) { + // append is the only built-in that permits the use of ... for the last argument + bin := predeclaredFuncs[id] + if call.Ellipsis.IsValid() && id != _Append { + check.invalidOp(call.Ellipsis, "invalid use of ... with built-in %s", bin.name) + check.use(call.Args...) + return + } + + // For len(x) and cap(x) we need to know if x contains any function calls or + // receive operations. Save/restore current setting and set hasCallOrRecv to + // false for the evaluation of x so that we can check it afterwards. + // Note: We must do this _before_ calling unpack because unpack evaluates the + // first argument before we even call arg(x, 0)! + if id == _Len || id == _Cap { + defer func(b bool) { + check.hasCallOrRecv = b + }(check.hasCallOrRecv) + check.hasCallOrRecv = false + } + + // determine actual arguments + var arg getter + nargs := len(call.Args) + switch id { + default: + // make argument getter + arg, nargs, _ = unpack(func(x *operand, i int) { check.expr(x, call.Args[i]) }, nargs, false) + if arg == nil { + return + } + // evaluate first argument, if present + if nargs > 0 { + arg(x, 0) + if x.mode == invalid { + return + } + } + case _Make, _New, _Offsetof, _Trace: + // arguments require special handling + } + + // check argument count + { + msg := "" + if nargs < bin.nargs { + msg = "not enough" + } else if !bin.variadic && nargs > bin.nargs { + msg = "too many" + } + if msg != "" { + check.invalidOp(call.Rparen, "%s arguments for %s (expected %d, found %d)", msg, call, bin.nargs, nargs) + return + } + } + + switch id { + case _Append: + // append(s S, x ...T) S, where T is the element type of S + // spec: "The variadic function append appends zero or more values x to s of type + // S, which must be a slice type, and returns the resulting slice, also of type S. + // The values x are passed to a parameter of type ...T where T is the element type + // of S and the respective parameter passing rules apply." + S := x.typ + var T Type + if s, _ := S.Underlying().(*Slice); s != nil { + T = s.elem + } else { + check.invalidArg(x.pos(), "%s is not a slice", x) + return + } + + // remember arguments that have been evaluated already + alist := []operand{*x} + + // spec: "As a special case, append also accepts a first argument assignable + // to type []byte with a second argument of string type followed by ... . + // This form appends the bytes of the string. + if nargs == 2 && call.Ellipsis.IsValid() && x.assignableTo(check.conf, NewSlice(universeByte)) { + arg(x, 1) + if x.mode == invalid { + return + } + if isString(x.typ) { + if check.Types != nil { + sig := makeSig(S, S, x.typ) + sig.variadic = true + check.recordBuiltinType(call.Fun, sig) + } + x.mode = value + x.typ = S + break + } + alist = append(alist, *x) + // fallthrough + } + + // check general case by creating custom signature + sig := makeSig(S, S, NewSlice(T)) // []T required for variadic signature + sig.variadic = true + check.arguments(x, call, sig, func(x *operand, i int) { + // only evaluate arguments that have not been evaluated before + if i < len(alist) { + *x = alist[i] + return + } + arg(x, i) + }, nargs) + // ok to continue even if check.arguments reported errors + + x.mode = value + x.typ = S + if check.Types != nil { + check.recordBuiltinType(call.Fun, sig) + } + + case _Cap, _Len: + // cap(x) + // len(x) + mode := invalid + var typ Type + var val constant.Value + switch typ = implicitArrayDeref(x.typ.Underlying()); t := typ.(type) { + case *Basic: + if isString(t) && id == _Len { + if x.mode == constant_ { + mode = constant_ + val = constant.MakeInt64(int64(len(constant.StringVal(x.val)))) + } else { + mode = value + } + } + + case *Array: + mode = value + // spec: "The expressions len(s) and cap(s) are constants + // if the type of s is an array or pointer to an array and + // the expression s does not contain channel receives or + // function calls; in this case s is not evaluated." + if !check.hasCallOrRecv { + mode = constant_ + val = constant.MakeInt64(t.len) + } + + case *Slice, *Chan: + mode = value + + case *Map: + if id == _Len { + mode = value + } + } + + if mode == invalid { + check.invalidArg(x.pos(), "%s for %s", x, bin.name) + return + } + + x.mode = mode + x.typ = Typ[Int] + x.val = val + if check.Types != nil && mode != constant_ { + check.recordBuiltinType(call.Fun, makeSig(x.typ, typ)) + } + + case _Close: + // close(c) + c, _ := x.typ.Underlying().(*Chan) + if c == nil { + check.invalidArg(x.pos(), "%s is not a channel", x) + return + } + if c.dir == RecvOnly { + check.invalidArg(x.pos(), "%s must not be a receive-only channel", x) + return + } + + x.mode = novalue + if check.Types != nil { + check.recordBuiltinType(call.Fun, makeSig(nil, c)) + } + + case _Complex: + // complex(x, y realT) complexT + if !check.complexArg(x) { + return + } + + var y operand + arg(&y, 1) + if y.mode == invalid { + return + } + if !check.complexArg(&y) { + return + } + + check.convertUntyped(x, y.typ) + if x.mode == invalid { + return + } + check.convertUntyped(&y, x.typ) + if y.mode == invalid { + return + } + + if !Identical(x.typ, y.typ) { + check.invalidArg(x.pos(), "mismatched types %s and %s", x.typ, y.typ) + return + } + + if x.mode == constant_ && y.mode == constant_ { + x.val = constant.BinaryOp(x.val, token.ADD, constant.MakeImag(y.val)) + } else { + x.mode = value + } + + realT := x.typ + complexT := Typ[Invalid] + switch realT.Underlying().(*Basic).kind { + case Float32: + complexT = Typ[Complex64] + case Float64: + complexT = Typ[Complex128] + case UntypedInt, UntypedRune, UntypedFloat: + if x.mode == constant_ { + realT = defaultType(realT).(*Basic) + complexT = Typ[UntypedComplex] + } else { + // untyped but not constant; probably because one + // operand is a non-constant shift of untyped lhs + realT = Typ[Float64] + complexT = Typ[Complex128] + } + default: + check.invalidArg(x.pos(), "float32 or float64 arguments expected") + return + } + + x.typ = complexT + if check.Types != nil && x.mode != constant_ { + check.recordBuiltinType(call.Fun, makeSig(complexT, realT, realT)) + } + + if x.mode != constant_ { + // The arguments have now their final types, which at run- + // time will be materialized. Update the expression trees. + // If the current types are untyped, the materialized type + // is the respective default type. + // (If the result is constant, the arguments are never + // materialized and there is nothing to do.) + check.updateExprType(x.expr, realT, true) + check.updateExprType(y.expr, realT, true) + } + + case _Copy: + // copy(x, y []T) int + var dst Type + if t, _ := x.typ.Underlying().(*Slice); t != nil { + dst = t.elem + } + + var y operand + arg(&y, 1) + if y.mode == invalid { + return + } + var src Type + switch t := y.typ.Underlying().(type) { + case *Basic: + if isString(y.typ) { + src = universeByte + } + case *Slice: + src = t.elem + } + + if dst == nil || src == nil { + check.invalidArg(x.pos(), "copy expects slice arguments; found %s and %s", x, &y) + return + } + + if !Identical(dst, src) { + check.invalidArg(x.pos(), "arguments to copy %s and %s have different element types %s and %s", x, &y, dst, src) + return + } + + if check.Types != nil { + check.recordBuiltinType(call.Fun, makeSig(Typ[Int], x.typ, y.typ)) + } + x.mode = value + x.typ = Typ[Int] + + case _Delete: + // delete(m, k) + m, _ := x.typ.Underlying().(*Map) + if m == nil { + check.invalidArg(x.pos(), "%s is not a map", x) + return + } + arg(x, 1) // k + if x.mode == invalid { + return + } + + if !x.assignableTo(check.conf, m.key) { + check.invalidArg(x.pos(), "%s is not assignable to %s", x, m.key) + return + } + + x.mode = novalue + if check.Types != nil { + check.recordBuiltinType(call.Fun, makeSig(nil, m, m.key)) + } + + case _Imag, _Real: + // imag(complexT) realT + // real(complexT) realT + if !isComplex(x.typ) { + check.invalidArg(x.pos(), "%s must be a complex number", x) + return + } + if x.mode == constant_ { + if id == _Real { + x.val = constant.Real(x.val) + } else { + x.val = constant.Imag(x.val) + } + } else { + x.mode = value + } + var k BasicKind + switch x.typ.Underlying().(*Basic).kind { + case Complex64: + k = Float32 + case Complex128: + k = Float64 + case UntypedComplex: + k = UntypedFloat + default: + unreachable() + } + + if check.Types != nil && x.mode != constant_ { + check.recordBuiltinType(call.Fun, makeSig(Typ[k], x.typ)) + } + x.typ = Typ[k] + + case _Make: + // make(T, n) + // make(T, n, m) + // (no argument evaluated yet) + arg0 := call.Args[0] + T := check.typ(arg0) + if T == Typ[Invalid] { + return + } + + var min int // minimum number of arguments + switch T.Underlying().(type) { + case *Slice: + min = 2 + case *Map, *Chan: + min = 1 + default: + check.invalidArg(arg0.Pos(), "cannot make %s; type must be slice, map, or channel", arg0) + return + } + if nargs < min || min+1 < nargs { + check.errorf(call.Pos(), "%s expects %d or %d arguments; found %d", call, min, min+1, nargs) + return + } + var sizes []int64 // constant integer arguments, if any + for _, arg := range call.Args[1:] { + if s, ok := check.index(arg, -1); ok && s >= 0 { + sizes = append(sizes, s) + } + } + if len(sizes) == 2 && sizes[0] > sizes[1] { + check.invalidArg(call.Args[1].Pos(), "length and capacity swapped") + // safe to continue + } + x.mode = value + x.typ = T + if check.Types != nil { + params := [...]Type{T, Typ[Int], Typ[Int]} + check.recordBuiltinType(call.Fun, makeSig(x.typ, params[:1+len(sizes)]...)) + } + + case _New: + // new(T) + // (no argument evaluated yet) + T := check.typ(call.Args[0]) + if T == Typ[Invalid] { + return + } + + x.mode = value + x.typ = &Pointer{base: T} + if check.Types != nil { + check.recordBuiltinType(call.Fun, makeSig(x.typ, T)) + } + + case _Panic: + // panic(x) + T := new(Interface) + if !check.assignment(x, T) { + assert(x.mode == invalid) + return + } + + x.mode = novalue + if check.Types != nil { + check.recordBuiltinType(call.Fun, makeSig(nil, T)) + } + + case _Print, _Println: + // print(x, y, ...) + // println(x, y, ...) + var params []Type + if nargs > 0 { + params = make([]Type, nargs) + for i := 0; i < nargs; i++ { + if i > 0 { + arg(x, i) // first argument already evaluated + } + if !check.assignment(x, nil) { + assert(x.mode == invalid) + return + } + params[i] = x.typ + } + } + + x.mode = novalue + if check.Types != nil { + check.recordBuiltinType(call.Fun, makeSig(nil, params...)) + } + + case _Recover: + // recover() interface{} + x.mode = value + x.typ = new(Interface) + if check.Types != nil { + check.recordBuiltinType(call.Fun, makeSig(x.typ)) + } + + case _Alignof: + // unsafe.Alignof(x T) uintptr + if !check.assignment(x, nil) { + assert(x.mode == invalid) + return + } + + x.mode = constant_ + x.val = constant.MakeInt64(check.conf.alignof(x.typ)) + x.typ = Typ[Uintptr] + // result is constant - no need to record signature + + case _Offsetof: + // unsafe.Offsetof(x T) uintptr, where x must be a selector + // (no argument evaluated yet) + arg0 := call.Args[0] + selx, _ := unparen(arg0).(*ast.SelectorExpr) + if selx == nil { + check.invalidArg(arg0.Pos(), "%s is not a selector expression", arg0) + check.use(arg0) + return + } + + check.expr(x, selx.X) + if x.mode == invalid { + return + } + + base := derefStructPtr(x.typ) + sel := selx.Sel.Name + obj, index, indirect := LookupFieldOrMethod(base, false, check.pkg, sel) + switch obj.(type) { + case nil: + check.invalidArg(x.pos(), "%s has no single field %s", base, sel) + return + case *Func: + // TODO(gri) Using derefStructPtr may result in methods being found + // that don't actually exist. An error either way, but the error + // message is confusing. See: https://play.golang.org/p/al75v23kUy , + // but go/types reports: "invalid argument: x.m is a method value". + check.invalidArg(arg0.Pos(), "%s is a method value", arg0) + return + } + if indirect { + check.invalidArg(x.pos(), "field %s is embedded via a pointer in %s", sel, base) + return + } + + // TODO(gri) Should we pass x.typ instead of base (and indirect report if derefStructPtr indirected)? + check.recordSelection(selx, FieldVal, base, obj, index, false) + + offs := check.conf.offsetof(base, index) + x.mode = constant_ + x.val = constant.MakeInt64(offs) + x.typ = Typ[Uintptr] + // result is constant - no need to record signature + + case _Sizeof: + // unsafe.Sizeof(x T) uintptr + if !check.assignment(x, nil) { + assert(x.mode == invalid) + return + } + + x.mode = constant_ + x.val = constant.MakeInt64(check.conf.sizeof(x.typ)) + x.typ = Typ[Uintptr] + // result is constant - no need to record signature + + case _Assert: + // assert(pred) causes a typechecker error if pred is false. + // The result of assert is the value of pred if there is no error. + // Note: assert is only available in self-test mode. + if x.mode != constant_ || !isBoolean(x.typ) { + check.invalidArg(x.pos(), "%s is not a boolean constant", x) + return + } + if x.val.Kind() != constant.Bool { + check.errorf(x.pos(), "internal error: value of %s should be a boolean constant", x) + return + } + if !constant.BoolVal(x.val) { + check.errorf(call.Pos(), "%s failed", call) + // compile-time assertion failure - safe to continue + } + // result is constant - no need to record signature + + case _Trace: + // trace(x, y, z, ...) dumps the positions, expressions, and + // values of its arguments. The result of trace is the value + // of the first argument. + // Note: trace is only available in self-test mode. + // (no argument evaluated yet) + if nargs == 0 { + check.dump("%s: trace() without arguments", call.Pos()) + x.mode = novalue + break + } + var t operand + x1 := x + for _, arg := range call.Args { + check.rawExpr(x1, arg, nil) // permit trace for types, e.g.: new(trace(T)) + check.dump("%s: %s", x1.pos(), x1) + x1 = &t // use incoming x only for first argument + } + // trace is only available in test mode - no need to record signature + + default: + unreachable() + } + + return true +} + +// makeSig makes a signature for the given argument and result types. +// Default types are used for untyped arguments, and res may be nil. +func makeSig(res Type, args ...Type) *Signature { + list := make([]*Var, len(args)) + for i, param := range args { + list[i] = NewVar(token.NoPos, nil, "", defaultType(param)) + } + params := NewTuple(list...) + var result *Tuple + if res != nil { + assert(!isUntyped(res)) + result = NewTuple(NewVar(token.NoPos, nil, "", res)) + } + return &Signature{params: params, results: result} +} + +// implicitArrayDeref returns A if typ is of the form *A and A is an array; +// otherwise it returns typ. +// +func implicitArrayDeref(typ Type) Type { + if p, ok := typ.(*Pointer); ok { + if a, ok := p.base.Underlying().(*Array); ok { + return a + } + } + return typ +} + +// unparen returns e with any enclosing parentheses stripped. +func unparen(e ast.Expr) ast.Expr { + for { + p, ok := e.(*ast.ParenExpr) + if !ok { + return e + } + e = p.X + } +} + +func (check *Checker) complexArg(x *operand) bool { + t, _ := x.typ.Underlying().(*Basic) + if t != nil && (t.info&IsFloat != 0 || t.kind == UntypedInt || t.kind == UntypedRune) { + return true + } + check.invalidArg(x.pos(), "%s must be a float32, float64, or an untyped non-complex numeric constant", x) + return false +} diff --git a/libgo/go/go/types/builtins_test.go b/libgo/go/go/types/builtins_test.go new file mode 100644 index 00000000000..9835a482670 --- /dev/null +++ b/libgo/go/go/types/builtins_test.go @@ -0,0 +1,204 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package types_test + +import ( + "fmt" + "go/ast" + "go/importer" + "go/parser" + "testing" + + . "go/types" +) + +var builtinCalls = []struct { + name, src, sig string +}{ + {"append", `var s []int; _ = append(s)`, `func([]int, ...int) []int`}, + {"append", `var s []int; _ = append(s, 0)`, `func([]int, ...int) []int`}, + {"append", `var s []int; _ = (append)(s, 0)`, `func([]int, ...int) []int`}, + {"append", `var s []byte; _ = ((append))(s, 0)`, `func([]byte, ...byte) []byte`}, + {"append", `var s []byte; _ = append(s, "foo"...)`, `func([]byte, string...) []byte`}, + {"append", `type T []byte; var s T; var str string; _ = append(s, str...)`, `func(p.T, string...) p.T`}, + {"append", `type T []byte; type U string; var s T; var str U; _ = append(s, str...)`, `func(p.T, p.U...) p.T`}, + + {"cap", `var s [10]int; _ = cap(s)`, `invalid type`}, // constant + {"cap", `var s [10]int; _ = cap(&s)`, `invalid type`}, // constant + {"cap", `var s []int64; _ = cap(s)`, `func([]int64) int`}, + {"cap", `var c chan<-bool; _ = cap(c)`, `func(chan<- bool) int`}, + + {"len", `_ = len("foo")`, `invalid type`}, // constant + {"len", `var s string; _ = len(s)`, `func(string) int`}, + {"len", `var s [10]int; _ = len(s)`, `invalid type`}, // constant + {"len", `var s [10]int; _ = len(&s)`, `invalid type`}, // constant + {"len", `var s []int64; _ = len(s)`, `func([]int64) int`}, + {"len", `var c chan<-bool; _ = len(c)`, `func(chan<- bool) int`}, + {"len", `var m map[string]float32; _ = len(m)`, `func(map[string]float32) int`}, + + {"close", `var c chan int; close(c)`, `func(chan int)`}, + {"close", `var c chan<- chan string; close(c)`, `func(chan<- chan string)`}, + + {"complex", `_ = complex(1, 0)`, `invalid type`}, // constant + {"complex", `var re float32; _ = complex(re, 1.0)`, `func(float32, float32) complex64`}, + {"complex", `var im float64; _ = complex(1, im)`, `func(float64, float64) complex128`}, + {"complex", `type F32 float32; var re, im F32; _ = complex(re, im)`, `func(p.F32, p.F32) complex64`}, + {"complex", `type F64 float64; var re, im F64; _ = complex(re, im)`, `func(p.F64, p.F64) complex128`}, + + {"copy", `var src, dst []byte; copy(dst, src)`, `func([]byte, []byte) int`}, + {"copy", `type T [][]int; var src, dst T; _ = copy(dst, src)`, `func(p.T, p.T) int`}, + {"copy", `var src string; var dst []byte; copy(dst, src)`, `func([]byte, string) int`}, + {"copy", `type T string; type U []byte; var src T; var dst U; copy(dst, src)`, `func(p.U, p.T) int`}, + {"copy", `var dst []byte; copy(dst, "hello")`, `func([]byte, string) int`}, + + {"delete", `var m map[string]bool; delete(m, "foo")`, `func(map[string]bool, string)`}, + {"delete", `type (K string; V int); var m map[K]V; delete(m, "foo")`, `func(map[p.K]p.V, p.K)`}, + + {"imag", `_ = imag(1i)`, `invalid type`}, // constant + {"imag", `var c complex64; _ = imag(c)`, `func(complex64) float32`}, + {"imag", `var c complex128; _ = imag(c)`, `func(complex128) float64`}, + {"imag", `type C64 complex64; var c C64; _ = imag(c)`, `func(p.C64) float32`}, + {"imag", `type C128 complex128; var c C128; _ = imag(c)`, `func(p.C128) float64`}, + + {"real", `_ = real(1i)`, `invalid type`}, // constant + {"real", `var c complex64; _ = real(c)`, `func(complex64) float32`}, + {"real", `var c complex128; _ = real(c)`, `func(complex128) float64`}, + {"real", `type C64 complex64; var c C64; _ = real(c)`, `func(p.C64) float32`}, + {"real", `type C128 complex128; var c C128; _ = real(c)`, `func(p.C128) float64`}, + + {"make", `_ = make([]int, 10)`, `func([]int, int) []int`}, + {"make", `type T []byte; _ = make(T, 10, 20)`, `func(p.T, int, int) p.T`}, + + {"new", `_ = new(int)`, `func(int) *int`}, + {"new", `type T struct{}; _ = new(T)`, `func(p.T) *p.T`}, + + {"panic", `panic(0)`, `func(interface{})`}, + {"panic", `panic("foo")`, `func(interface{})`}, + + {"print", `print()`, `func()`}, + {"print", `print(0)`, `func(int)`}, + {"print", `print(1, 2.0, "foo", true)`, `func(int, float64, string, bool)`}, + + {"println", `println()`, `func()`}, + {"println", `println(0)`, `func(int)`}, + {"println", `println(1, 2.0, "foo", true)`, `func(int, float64, string, bool)`}, + + {"recover", `recover()`, `func() interface{}`}, + {"recover", `_ = recover()`, `func() interface{}`}, + + {"Alignof", `_ = unsafe.Alignof(0)`, `invalid type`}, // constant + {"Alignof", `var x struct{}; _ = unsafe.Alignof(x)`, `invalid type`}, // constant + + {"Offsetof", `var x struct{f bool}; _ = unsafe.Offsetof(x.f)`, `invalid type`}, // constant + {"Offsetof", `var x struct{_ int; f bool}; _ = unsafe.Offsetof((&x).f)`, `invalid type`}, // constant + + {"Sizeof", `_ = unsafe.Sizeof(0)`, `invalid type`}, // constant + {"Sizeof", `var x struct{}; _ = unsafe.Sizeof(x)`, `invalid type`}, // constant + + {"assert", `assert(true)`, `invalid type`}, // constant + {"assert", `type B bool; const pred B = 1 < 2; assert(pred)`, `invalid type`}, // constant + + // no tests for trace since it produces output as a side-effect +} + +func TestBuiltinSignatures(t *testing.T) { + DefPredeclaredTestFuncs() + + seen := map[string]bool{"trace": true} // no test for trace built-in; add it manually + for _, call := range builtinCalls { + testBuiltinSignature(t, call.name, call.src, call.sig) + seen[call.name] = true + } + + // make sure we didn't miss one + for _, name := range Universe.Names() { + if _, ok := Universe.Lookup(name).(*Builtin); ok && !seen[name] { + t.Errorf("missing test for %s", name) + } + } + for _, name := range Unsafe.Scope().Names() { + if _, ok := Unsafe.Scope().Lookup(name).(*Builtin); ok && !seen[name] { + t.Errorf("missing test for unsafe.%s", name) + } + } +} + +func testBuiltinSignature(t *testing.T, name, src0, want string) { + src := fmt.Sprintf(`package p; import "unsafe"; type _ unsafe.Pointer /* use unsafe */; func _() { %s }`, src0) + f, err := parser.ParseFile(fset, "", src, 0) + if err != nil { + t.Errorf("%s: %s", src0, err) + return + } + + conf := Config{Importer: importer.Default()} + uses := make(map[*ast.Ident]Object) + types := make(map[ast.Expr]TypeAndValue) + _, err = conf.Check(f.Name.Name, fset, []*ast.File{f}, &Info{Uses: uses, Types: types}) + if err != nil { + t.Errorf("%s: %s", src0, err) + return + } + + // find called function + n := 0 + var fun ast.Expr + for x := range types { + if call, _ := x.(*ast.CallExpr); call != nil { + fun = call.Fun + n++ + } + } + if n != 1 { + t.Errorf("%s: got %d CallExprs; want 1", src0, n) + return + } + + // check recorded types for fun and descendents (may be parenthesized) + for { + // the recorded type for the built-in must match the wanted signature + typ := types[fun].Type + if typ == nil { + t.Errorf("%s: no type recorded for %s", src0, ExprString(fun)) + return + } + if got := typ.String(); got != want { + t.Errorf("%s: got type %s; want %s", src0, got, want) + return + } + + // called function must be a (possibly parenthesized, qualified) + // identifier denoting the expected built-in + switch p := fun.(type) { + case *ast.Ident: + obj := uses[p] + if obj == nil { + t.Errorf("%s: no object found for %s", src0, p) + return + } + bin, _ := obj.(*Builtin) + if bin == nil { + t.Errorf("%s: %s does not denote a built-in", src0, p) + return + } + if bin.Name() != name { + t.Errorf("%s: got built-in %s; want %s", src0, bin.Name(), name) + return + } + return // we're done + + case *ast.ParenExpr: + fun = p.X // unpack + + case *ast.SelectorExpr: + // built-in from package unsafe - ignore details + return // we're done + + default: + t.Errorf("%s: invalid function call", src0) + return + } + } +} diff --git a/libgo/go/go/types/call.go b/libgo/go/go/types/call.go new file mode 100644 index 00000000000..62cefc047ef --- /dev/null +++ b/libgo/go/go/types/call.go @@ -0,0 +1,441 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file implements typechecking of call and selector expressions. + +package types + +import ( + "go/ast" + "go/token" +) + +func (check *Checker) call(x *operand, e *ast.CallExpr) exprKind { + check.exprOrType(x, e.Fun) + + switch x.mode { + case invalid: + check.use(e.Args...) + x.mode = invalid + x.expr = e + return statement + + case typexpr: + // conversion + T := x.typ + x.mode = invalid + switch n := len(e.Args); n { + case 0: + check.errorf(e.Rparen, "missing argument in conversion to %s", T) + case 1: + check.expr(x, e.Args[0]) + if x.mode != invalid { + check.conversion(x, T) + } + default: + check.errorf(e.Args[n-1].Pos(), "too many arguments in conversion to %s", T) + } + x.expr = e + return conversion + + case builtin: + id := x.id + if !check.builtin(x, e, id) { + x.mode = invalid + } + x.expr = e + // a non-constant result implies a function call + if x.mode != invalid && x.mode != constant_ { + check.hasCallOrRecv = true + } + return predeclaredFuncs[id].kind + + default: + // function/method call + sig, _ := x.typ.Underlying().(*Signature) + if sig == nil { + check.invalidOp(x.pos(), "cannot call non-function %s", x) + x.mode = invalid + x.expr = e + return statement + } + + arg, n, _ := unpack(func(x *operand, i int) { check.expr(x, e.Args[i]) }, len(e.Args), false) + if arg == nil { + x.mode = invalid + x.expr = e + return statement + } + + check.arguments(x, e, sig, arg, n) + + // determine result + switch sig.results.Len() { + case 0: + x.mode = novalue + case 1: + x.mode = value + x.typ = sig.results.vars[0].typ // unpack tuple + default: + x.mode = value + x.typ = sig.results + } + x.expr = e + check.hasCallOrRecv = true + + return statement + } +} + +// use type-checks each argument. +// Useful to make sure expressions are evaluated +// (and variables are "used") in the presence of other errors. +func (check *Checker) use(arg ...ast.Expr) { + var x operand + for _, e := range arg { + check.rawExpr(&x, e, nil) + } +} + +// useGetter is like use, but takes a getter instead of a list of expressions. +// It should be called instead of use if a getter is present to avoid repeated +// evaluation of the first argument (since the getter was likely obtained via +// unpack, which may have evaluated the first argument already). +func (check *Checker) useGetter(get getter, n int) { + var x operand + for i := 0; i < n; i++ { + get(&x, i) + } +} + +// A getter sets x as the i'th operand, where 0 <= i < n and n is the total +// number of operands (context-specific, and maintained elsewhere). A getter +// type-checks the i'th operand; the details of the actual check are getter- +// specific. +type getter func(x *operand, i int) + +// unpack takes a getter get and a number of operands n. If n == 1, unpack +// calls the incoming getter for the first operand. If that operand is +// invalid, unpack returns (nil, 0, false). Otherwise, if that operand is a +// function call, or a comma-ok expression and allowCommaOk is set, the result +// is a new getter and operand count providing access to the function results, +// or comma-ok values, respectively. The third result value reports if it +// is indeed the comma-ok case. In all other cases, the incoming getter and +// operand count are returned unchanged, and the third result value is false. +// +// In other words, if there's exactly one operand that - after type-checking +// by calling get - stands for multiple operands, the resulting getter provides +// access to those operands instead. +// +// If the returned getter is called at most once for a given operand index i +// (including i == 0), that operand is guaranteed to cause only one call of +// the incoming getter with that i. +// +func unpack(get getter, n int, allowCommaOk bool) (getter, int, bool) { + if n == 1 { + // possibly result of an n-valued function call or comma,ok value + var x0 operand + get(&x0, 0) + if x0.mode == invalid { + return nil, 0, false + } + + if t, ok := x0.typ.(*Tuple); ok { + // result of an n-valued function call + return func(x *operand, i int) { + x.mode = value + x.expr = x0.expr + x.typ = t.At(i).typ + }, t.Len(), false + } + + if x0.mode == mapindex || x0.mode == commaok { + // comma-ok value + if allowCommaOk { + a := [2]Type{x0.typ, Typ[UntypedBool]} + return func(x *operand, i int) { + x.mode = value + x.expr = x0.expr + x.typ = a[i] + }, 2, true + } + x0.mode = value + } + + // single value + return func(x *operand, i int) { + if i != 0 { + unreachable() + } + *x = x0 + }, 1, false + } + + // zero or multiple values + return get, n, false +} + +// arguments checks argument passing for the call with the given signature. +// The arg function provides the operand for the i'th argument. +func (check *Checker) arguments(x *operand, call *ast.CallExpr, sig *Signature, arg getter, n int) { + if call.Ellipsis.IsValid() { + // last argument is of the form x... + if len(call.Args) == 1 && n > 1 { + // f()... is not permitted if f() is multi-valued + check.errorf(call.Ellipsis, "cannot use ... with %d-valued expression %s", n, call.Args[0]) + check.useGetter(arg, n) + return + } + if !sig.variadic { + check.errorf(call.Ellipsis, "cannot use ... in call to non-variadic %s", call.Fun) + check.useGetter(arg, n) + return + } + } + + // evaluate arguments + for i := 0; i < n; i++ { + arg(x, i) + if x.mode != invalid { + var ellipsis token.Pos + if i == n-1 && call.Ellipsis.IsValid() { + ellipsis = call.Ellipsis + } + check.argument(sig, i, x, ellipsis) + } + } + + // check argument count + if sig.variadic { + // a variadic function accepts an "empty" + // last argument: count one extra + n++ + } + if n < sig.params.Len() { + check.errorf(call.Rparen, "too few arguments in call to %s", call.Fun) + // ok to continue + } +} + +// argument checks passing of argument x to the i'th parameter of the given signature. +// If ellipsis is valid, the argument is followed by ... at that position in the call. +func (check *Checker) argument(sig *Signature, i int, x *operand, ellipsis token.Pos) { + n := sig.params.Len() + + // determine parameter type + var typ Type + switch { + case i < n: + typ = sig.params.vars[i].typ + case sig.variadic: + typ = sig.params.vars[n-1].typ + if debug { + if _, ok := typ.(*Slice); !ok { + check.dump("%s: expected unnamed slice type, got %s", sig.params.vars[n-1].Pos(), typ) + } + } + default: + check.errorf(x.pos(), "too many arguments") + return + } + + if ellipsis.IsValid() { + // argument is of the form x... + if i != n-1 { + check.errorf(ellipsis, "can only use ... with matching parameter") + return + } + switch t := x.typ.Underlying().(type) { + case *Slice: + // ok + case *Tuple: + check.errorf(ellipsis, "cannot use ... with %d-valued expression %s", t.Len(), x) + return + default: + check.errorf(x.pos(), "cannot use %s as parameter of type %s", x, typ) + return + } + } else if sig.variadic && i >= n-1 { + // use the variadic parameter slice's element type + typ = typ.(*Slice).elem + } + + if !check.assignment(x, typ) && x.mode != invalid { + check.errorf(x.pos(), "cannot pass argument %s to parameter of type %s", x, typ) + } +} + +func (check *Checker) selector(x *operand, e *ast.SelectorExpr) { + // these must be declared before the "goto Error" statements + var ( + obj Object + index []int + indirect bool + ) + + sel := e.Sel.Name + // If the identifier refers to a package, handle everything here + // so we don't need a "package" mode for operands: package names + // can only appear in qualified identifiers which are mapped to + // selector expressions. + if ident, ok := e.X.(*ast.Ident); ok { + _, obj := check.scope.LookupParent(ident.Name, check.pos) + if pkg, _ := obj.(*PkgName); pkg != nil { + assert(pkg.pkg == check.pkg) + check.recordUse(ident, pkg) + pkg.used = true + exp := pkg.imported.scope.Lookup(sel) + if exp == nil { + if !pkg.imported.fake { + check.errorf(e.Pos(), "%s not declared by package %s", sel, ident) + } + goto Error + } + if !exp.Exported() { + check.errorf(e.Pos(), "%s not exported by package %s", sel, ident) + // ok to continue + } + check.recordUse(e.Sel, exp) + // Simplified version of the code for *ast.Idents: + // - imported objects are always fully initialized + switch exp := exp.(type) { + case *Const: + assert(exp.Val() != nil) + x.mode = constant_ + x.typ = exp.typ + x.val = exp.val + case *TypeName: + x.mode = typexpr + x.typ = exp.typ + case *Var: + x.mode = variable + x.typ = exp.typ + case *Func: + x.mode = value + x.typ = exp.typ + case *Builtin: + x.mode = builtin + x.typ = exp.typ + x.id = exp.id + default: + unreachable() + } + x.expr = e + return + } + } + + check.exprOrType(x, e.X) + if x.mode == invalid { + goto Error + } + + obj, index, indirect = LookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, sel) + if obj == nil { + switch { + case index != nil: + // TODO(gri) should provide actual type where the conflict happens + check.invalidOp(e.Pos(), "ambiguous selector %s", sel) + case indirect: + check.invalidOp(e.Pos(), "%s is not in method set of %s", sel, x.typ) + default: + check.invalidOp(e.Pos(), "%s has no field or method %s", x, sel) + } + goto Error + } + + if x.mode == typexpr { + // method expression + m, _ := obj.(*Func) + if m == nil { + check.invalidOp(e.Pos(), "%s has no method %s", x, sel) + goto Error + } + + check.recordSelection(e, MethodExpr, x.typ, m, index, indirect) + + // the receiver type becomes the type of the first function + // argument of the method expression's function type + var params []*Var + sig := m.typ.(*Signature) + if sig.params != nil { + params = sig.params.vars + } + x.mode = value + x.typ = &Signature{ + params: NewTuple(append([]*Var{NewVar(token.NoPos, check.pkg, "", x.typ)}, params...)...), + results: sig.results, + variadic: sig.variadic, + } + + check.addDeclDep(m) + + } else { + // regular selector + switch obj := obj.(type) { + case *Var: + check.recordSelection(e, FieldVal, x.typ, obj, index, indirect) + if x.mode == variable || indirect { + x.mode = variable + } else { + x.mode = value + } + x.typ = obj.typ + + case *Func: + // TODO(gri) If we needed to take into account the receiver's + // addressability, should we report the type &(x.typ) instead? + check.recordSelection(e, MethodVal, x.typ, obj, index, indirect) + + if debug { + // Verify that LookupFieldOrMethod and MethodSet.Lookup agree. + typ := x.typ + if x.mode == variable { + // If typ is not an (unnamed) pointer or an interface, + // use *typ instead, because the method set of *typ + // includes the methods of typ. + // Variables are addressable, so we can always take their + // address. + if _, ok := typ.(*Pointer); !ok && !IsInterface(typ) { + typ = &Pointer{base: typ} + } + } + // If we created a synthetic pointer type above, we will throw + // away the method set computed here after use. + // TODO(gri) Method set computation should probably always compute + // both, the value and the pointer receiver method set and represent + // them in a single structure. + // TODO(gri) Consider also using a method set cache for the lifetime + // of checker once we rely on MethodSet lookup instead of individual + // lookup. + mset := NewMethodSet(typ) + if m := mset.Lookup(check.pkg, sel); m == nil || m.obj != obj { + check.dump("%s: (%s).%v -> %s", e.Pos(), typ, obj.name, m) + check.dump("%s\n", mset) + panic("method sets and lookup don't agree") + } + } + + x.mode = value + + // remove receiver + sig := *obj.typ.(*Signature) + sig.recv = nil + x.typ = &sig + + check.addDeclDep(obj) + + default: + unreachable() + } + } + + // everything went well + x.expr = e + return + +Error: + x.mode = invalid + x.expr = e +} diff --git a/libgo/go/go/types/check.go b/libgo/go/go/types/check.go new file mode 100644 index 00000000000..bb0b07415e8 --- /dev/null +++ b/libgo/go/go/types/check.go @@ -0,0 +1,358 @@ +// 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 implements the Check function, which drives type-checking. + +package types + +import ( + "go/ast" + "go/constant" + "go/token" +) + +// debugging/development support +const ( + debug = false // leave on during development + trace = false // turn on for detailed type resolution traces +) + +// If Strict is set, the type-checker enforces additional +// rules not specified by the Go 1 spec, but which will +// catch guaranteed run-time errors if the respective +// code is executed. In other words, programs passing in +// Strict mode are Go 1 compliant, but not all Go 1 programs +// will pass in Strict mode. The additional rules are: +// +// - A type assertion x.(T) where T is an interface type +// is invalid if any (statically known) method that exists +// for both x and T have different signatures. +// +const strict = false + +// exprInfo stores information about an untyped expression. +type exprInfo struct { + isLhs bool // expression is lhs operand of a shift with delayed type-check + mode operandMode + typ *Basic + val constant.Value // constant value; or nil (if not a constant) +} + +// funcInfo stores the information required for type-checking a function. +type funcInfo struct { + name string // for debugging/tracing only + decl *declInfo // for cycle detection + sig *Signature + body *ast.BlockStmt +} + +// A context represents the context within which an object is type-checked. +type context struct { + decl *declInfo // package-level declaration whose init expression/function body is checked + scope *Scope // top-most scope for lookups + iota constant.Value // value of iota in a constant declaration; nil otherwise + sig *Signature // function signature if inside a function; nil otherwise + hasLabel bool // set if a function makes use of labels (only ~1% of functions); unused outside functions + hasCallOrRecv bool // set if an expression contains a function call or channel receive operation +} + +// A Checker maintains the state of the type checker. +// It must be created with NewChecker. +type Checker struct { + // package information + // (initialized by NewChecker, valid for the life-time of checker) + conf *Config + fset *token.FileSet + pkg *Package + *Info + objMap map[Object]*declInfo // maps package-level object to declaration info + + // information collected during type-checking of a set of package files + // (initialized by Files, valid only for the duration of check.Files; + // maps and lists are allocated on demand) + files []*ast.File // package files + unusedDotImports map[*Scope]map[*Package]token.Pos // positions of unused dot-imported packages for each file scope + + firstErr error // first error encountered + methods map[string][]*Func // maps type names to associated methods + untyped map[ast.Expr]exprInfo // map of expressions without final type + funcs []funcInfo // list of functions to type-check + delayed []func() // delayed checks requiring fully setup types + + // context within which the current object is type-checked + // (valid only for the duration of type-checking a specific object) + context + pos token.Pos // if valid, identifiers are looked up as if at position pos (used by Eval) + + // debugging + indent int // indentation for tracing +} + +// addUnusedImport adds the position of a dot-imported package +// pkg to the map of dot imports for the given file scope. +func (check *Checker) addUnusedDotImport(scope *Scope, pkg *Package, pos token.Pos) { + mm := check.unusedDotImports + if mm == nil { + mm = make(map[*Scope]map[*Package]token.Pos) + check.unusedDotImports = mm + } + m := mm[scope] + if m == nil { + m = make(map[*Package]token.Pos) + mm[scope] = m + } + m[pkg] = pos +} + +// addDeclDep adds the dependency edge (check.decl -> to) if check.decl exists +func (check *Checker) addDeclDep(to Object) { + from := check.decl + if from == nil { + return // not in a package-level init expression + } + if _, found := check.objMap[to]; !found { + return // to is not a package-level object + } + from.addDep(to) +} + +func (check *Checker) assocMethod(tname string, meth *Func) { + m := check.methods + if m == nil { + m = make(map[string][]*Func) + check.methods = m + } + m[tname] = append(m[tname], meth) +} + +func (check *Checker) rememberUntyped(e ast.Expr, lhs bool, mode operandMode, typ *Basic, val constant.Value) { + m := check.untyped + if m == nil { + m = make(map[ast.Expr]exprInfo) + check.untyped = m + } + m[e] = exprInfo{lhs, mode, typ, val} +} + +func (check *Checker) later(name string, decl *declInfo, sig *Signature, body *ast.BlockStmt) { + check.funcs = append(check.funcs, funcInfo{name, decl, sig, body}) +} + +func (check *Checker) delay(f func()) { + check.delayed = append(check.delayed, f) +} + +// NewChecker returns a new Checker instance for a given package. +// Package files may be added incrementally via checker.Files. +func NewChecker(conf *Config, fset *token.FileSet, pkg *Package, info *Info) *Checker { + // make sure we have a configuration + if conf == nil { + conf = new(Config) + } + + // make sure we have an info struct + if info == nil { + info = new(Info) + } + + return &Checker{ + conf: conf, + fset: fset, + pkg: pkg, + Info: info, + objMap: make(map[Object]*declInfo), + } +} + +// initFiles initializes the files-specific portion of checker. +// The provided files must all belong to the same package. +func (check *Checker) initFiles(files []*ast.File) { + // start with a clean slate (check.Files may be called multiple times) + check.files = nil + check.unusedDotImports = nil + + check.firstErr = nil + check.methods = nil + check.untyped = nil + check.funcs = nil + check.delayed = nil + + // determine package name and collect valid files + pkg := check.pkg + for _, file := range files { + switch name := file.Name.Name; pkg.name { + case "": + if name != "_" { + pkg.name = name + } else { + check.errorf(file.Name.Pos(), "invalid package name _") + } + fallthrough + + case name: + check.files = append(check.files, file) + + default: + check.errorf(file.Package, "package %s; expected %s", name, pkg.name) + // ignore this file + } + } +} + +// A bailout panic is used for early termination. +type bailout struct{} + +func (check *Checker) handleBailout(err *error) { + switch p := recover().(type) { + case nil, bailout: + // normal return or early exit + *err = check.firstErr + default: + // re-panic + panic(p) + } +} + +// Files checks the provided files as part of the checker's package. +func (check *Checker) Files(files []*ast.File) (err error) { + defer check.handleBailout(&err) + + check.initFiles(files) + + check.collectObjects() + + check.packageObjects(check.resolveOrder()) + + check.functionBodies() + + check.initOrder() + + if !check.conf.DisableUnusedImportCheck { + check.unusedImports() + } + + // perform delayed checks + for _, f := range check.delayed { + f() + } + + check.recordUntyped() + + check.pkg.complete = true + return +} + +func (check *Checker) recordUntyped() { + if !debug && check.Types == nil { + return // nothing to do + } + + for x, info := range check.untyped { + if debug && isTyped(info.typ) { + check.dump("%s: %s (type %s) is typed", x.Pos(), x, info.typ) + unreachable() + } + check.recordTypeAndValue(x, info.mode, info.typ, info.val) + } +} + +func (check *Checker) recordTypeAndValue(x ast.Expr, mode operandMode, typ Type, val constant.Value) { + assert(x != nil) + assert(typ != nil) + if mode == invalid { + return // omit + } + assert(typ != nil) + if mode == constant_ { + assert(val != nil) + assert(typ == Typ[Invalid] || isConstType(typ)) + } + if m := check.Types; m != nil { + m[x] = TypeAndValue{mode, typ, val} + } +} + +func (check *Checker) recordBuiltinType(f ast.Expr, sig *Signature) { + // f must be a (possibly parenthesized) identifier denoting a built-in + // (built-ins in package unsafe always produce a constant result and + // we don't record their signatures, so we don't see qualified idents + // here): record the signature for f and possible children. + for { + check.recordTypeAndValue(f, builtin, sig, nil) + switch p := f.(type) { + case *ast.Ident: + return // we're done + case *ast.ParenExpr: + f = p.X + default: + unreachable() + } + } +} + +func (check *Checker) recordCommaOkTypes(x ast.Expr, a [2]Type) { + assert(x != nil) + if a[0] == nil || a[1] == nil { + return + } + assert(isTyped(a[0]) && isTyped(a[1]) && isBoolean(a[1])) + if m := check.Types; m != nil { + for { + tv := m[x] + assert(tv.Type != nil) // should have been recorded already + pos := x.Pos() + tv.Type = NewTuple( + NewVar(pos, check.pkg, "", a[0]), + NewVar(pos, check.pkg, "", a[1]), + ) + m[x] = tv + // if x is a parenthesized expression (p.X), update p.X + p, _ := x.(*ast.ParenExpr) + if p == nil { + break + } + x = p.X + } + } +} + +func (check *Checker) recordDef(id *ast.Ident, obj Object) { + assert(id != nil) + if m := check.Defs; m != nil { + m[id] = obj + } +} + +func (check *Checker) recordUse(id *ast.Ident, obj Object) { + assert(id != nil) + assert(obj != nil) + if m := check.Uses; m != nil { + m[id] = obj + } +} + +func (check *Checker) recordImplicit(node ast.Node, obj Object) { + assert(node != nil) + assert(obj != nil) + if m := check.Implicits; m != nil { + m[node] = obj + } +} + +func (check *Checker) recordSelection(x *ast.SelectorExpr, kind SelectionKind, recv Type, obj Object, index []int, indirect bool) { + assert(obj != nil && (recv == nil || len(index) > 0)) + check.recordUse(x.Sel, obj) + // TODO(gri) Should we also call recordTypeAndValue? + if m := check.Selections; m != nil { + m[x] = &Selection{kind, recv, obj, index, indirect} + } +} + +func (check *Checker) recordScope(node ast.Node, scope *Scope) { + assert(node != nil) + assert(scope != nil) + if m := check.Scopes; m != nil { + m[node] = scope + } +} diff --git a/libgo/go/go/types/check_test.go b/libgo/go/go/types/check_test.go new file mode 100644 index 00000000000..5e34c65b636 --- /dev/null +++ b/libgo/go/go/types/check_test.go @@ -0,0 +1,298 @@ +// 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 implements a typechecker test harness. The packages specified +// in tests are typechecked. Error messages reported by the typechecker are +// compared against the error messages expected in the test files. +// +// 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. Consecutive comments may be +// used to indicate multiple errors for the same token 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 +// } + +// TODO(gri) Also collect strict mode errors of the form /* STRICT ... */ +// and test against strict mode. + +package types_test + +import ( + "flag" + "go/ast" + "go/importer" + "go/parser" + "go/scanner" + "go/token" + "internal/testenv" + "io/ioutil" + "regexp" + "strings" + "testing" + + . "go/types" +) + +var ( + listErrors = flag.Bool("list", false, "list errors") + testFiles = flag.String("files", "", "space-separated list of test files") +) + +// The test filenames do not end in .go so that they are invisible +// to gofmt since they contain comments that must not change their +// positions relative to surrounding tokens. + +// Each tests entry is list of files belonging to the same package. +var tests = [][]string{ + {"testdata/errors.src"}, + {"testdata/importdecl0a.src", "testdata/importdecl0b.src"}, + {"testdata/importdecl1a.src", "testdata/importdecl1b.src"}, + {"testdata/cycles.src"}, + {"testdata/cycles1.src"}, + {"testdata/cycles2.src"}, + {"testdata/cycles3.src"}, + {"testdata/cycles4.src"}, + {"testdata/init0.src"}, + {"testdata/init1.src"}, + {"testdata/init2.src"}, + {"testdata/decls0.src"}, + {"testdata/decls1.src"}, + {"testdata/decls2a.src", "testdata/decls2b.src"}, + {"testdata/decls3.src"}, + {"testdata/const0.src"}, + {"testdata/const1.src"}, + {"testdata/constdecl.src"}, + {"testdata/vardecl.src"}, + {"testdata/expr0.src"}, + {"testdata/expr1.src"}, + {"testdata/expr2.src"}, + {"testdata/expr3.src"}, + {"testdata/methodsets.src"}, + {"testdata/shifts.src"}, + {"testdata/builtins.src"}, + {"testdata/conversions.src"}, + {"testdata/stmt0.src"}, + {"testdata/stmt1.src"}, + {"testdata/gotos.src"}, + {"testdata/labels.src"}, + {"testdata/issues.src"}, + {"testdata/blank.src"}, +} + +var fset = token.NewFileSet() + +// Positioned errors are of the form filename:line:column: message . +var posMsgRx = regexp.MustCompile(`^(.*:[0-9]+:[0-9]+): *(.*)`) + +// splitError splits an error's error message into a position string +// and the actual error message. If there's no position information, +// pos is the empty string, and msg is the entire error message. +// +func splitError(err error) (pos, msg string) { + msg = err.Error() + if m := posMsgRx.FindStringSubmatch(msg); len(m) == 3 { + pos = m[1] + msg = m[2] + } + return +} + +func parseFiles(t *testing.T, filenames []string) ([]*ast.File, []error) { + var files []*ast.File + var errlist []error + for _, filename := range filenames { + file, err := parser.ParseFile(fset, filename, nil, parser.AllErrors) + if file == nil { + t.Fatalf("%s: %s", filename, err) + } + files = append(files, file) + if err != nil { + if list, _ := err.(scanner.ErrorList); len(list) > 0 { + for _, err := range list { + errlist = append(errlist, err) + } + } else { + errlist = append(errlist, err) + } + } + } + return files, errlist +} + +// ERROR comments must start with text `ERROR "rx"` or `ERROR rx` where +// rx is a regular expression that matches the expected error message. +// Space around "rx" or rx is ignored. Use the form `ERROR HERE "rx"` +// for error messages that are located immediately after rather than +// at a token's position. +// +var errRx = regexp.MustCompile(`^ *ERROR *(HERE)? *"?([^"]*)"?`) + +// errMap collects the regular expressions of ERROR comments found +// in files and returns them as a map of error positions to error messages. +// +func errMap(t *testing.T, testname string, files []*ast.File) map[string][]string { + // map of position strings to lists of error message patterns + errmap := make(map[string][]string) + + for _, file := range files { + filename := fset.Position(file.Package).Filename + src, err := ioutil.ReadFile(filename) + if err != nil { + t.Fatalf("%s: could not read %s", testname, filename) + } + + var s scanner.Scanner + s.Init(fset.AddFile(filename, -1, len(src)), src, nil, scanner.ScanComments) + var prev token.Pos // position of last non-comment, non-semicolon token + var here token.Pos // position immediately after the token at position prev + + scanFile: + for { + pos, tok, lit := s.Scan() + switch tok { + case token.EOF: + break scanFile + case token.COMMENT: + if lit[1] == '*' { + lit = lit[:len(lit)-2] // strip trailing */ + } + if s := errRx.FindStringSubmatch(lit[2:]); len(s) == 3 { + pos := prev + if s[1] == "HERE" { + pos = here + } + p := fset.Position(pos).String() + errmap[p] = append(errmap[p], strings.TrimSpace(s[2])) + } + case token.SEMICOLON: + // ignore automatically inserted semicolon + if lit == "\n" { + continue scanFile + } + fallthrough + default: + prev = pos + var l int // token length + if tok.IsLiteral() { + l = len(lit) + } else { + l = len(tok.String()) + } + here = prev + token.Pos(l) + } + } + } + + return errmap +} + +func eliminate(t *testing.T, errmap map[string][]string, errlist []error) { + for _, err := range errlist { + pos, gotMsg := splitError(err) + list := errmap[pos] + index := -1 // list index of matching message, if any + // we expect one of the messages in list to match the error at pos + for i, wantRx := range list { + rx, err := regexp.Compile(wantRx) + if err != nil { + t.Errorf("%s: %v", pos, err) + continue + } + if rx.MatchString(gotMsg) { + index = i + break + } + } + if index >= 0 { + // eliminate from list + if n := len(list) - 1; n > 0 { + // not the last entry - swap in last element and shorten list by 1 + list[index] = list[n] + errmap[pos] = list[:n] + } else { + // last entry - remove list from map + delete(errmap, pos) + } + } else { + t.Errorf("%s: no error expected: %q", pos, gotMsg) + } + } +} + +func checkFiles(t *testing.T, testfiles []string) { + // parse files and collect parser errors + files, errlist := parseFiles(t, testfiles) + + pkgName := "" + if len(files) > 0 { + pkgName = files[0].Name.Name + } + + if *listErrors && len(errlist) > 0 { + t.Errorf("--- %s:", pkgName) + for _, err := range errlist { + t.Error(err) + } + } + + // typecheck and collect typechecker errors + var conf Config + conf.Importer = importer.Default() + conf.Error = func(err error) { + if *listErrors { + t.Error(err) + return + } + // Ignore secondary error messages starting with "\t"; + // they are clarifying messages for a primary error. + if !strings.Contains(err.Error(), ": \t") { + errlist = append(errlist, err) + } + } + conf.Check(pkgName, fset, files, nil) + + if *listErrors { + return + } + + // match and eliminate errors; + // we are expecting the following errors + errmap := errMap(t, pkgName, files) + eliminate(t, errmap, errlist) + + // there should be no expected errors left + if len(errmap) > 0 { + t.Errorf("--- %s: %d source positions with expected (but not reported) errors:", pkgName, len(errmap)) + for pos, list := range errmap { + for _, rx := range list { + t.Errorf("%s: %q", pos, rx) + } + } + } +} + +func TestCheck(t *testing.T) { + testenv.MustHaveGoBuild(t) + + // Declare builtins for testing. + DefPredeclaredTestFuncs() + + // If explicit test files are specified, only check those. + if files := *testFiles; files != "" { + checkFiles(t, strings.Split(files, " ")) + return + } + + // Otherwise, run all the tests. + for _, files := range tests { + checkFiles(t, files) + } +} diff --git a/libgo/go/go/types/conversions.go b/libgo/go/go/types/conversions.go new file mode 100644 index 00000000000..74826ce9345 --- /dev/null +++ b/libgo/go/go/types/conversions.go @@ -0,0 +1,146 @@ +// 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 typechecking of conversions. + +package types + +import "go/constant" + +// Conversion type-checks the conversion T(x). +// The result is in x. +func (check *Checker) conversion(x *operand, T Type) { + constArg := x.mode == constant_ + + var ok bool + switch { + case constArg && isConstType(T): + // constant conversion + switch t := T.Underlying().(*Basic); { + case representableConst(x.val, check.conf, t.kind, &x.val): + ok = true + case isInteger(x.typ) && isString(t): + codepoint := int64(-1) + if i, ok := constant.Int64Val(x.val); ok { + codepoint = i + } + // If codepoint < 0 the absolute value is too large (or unknown) for + // conversion. This is the same as converting any other out-of-range + // value - let string(codepoint) do the work. + x.val = constant.MakeString(string(codepoint)) + ok = true + } + case x.convertibleTo(check.conf, T): + // non-constant conversion + x.mode = value + ok = true + } + + if !ok { + check.errorf(x.pos(), "cannot convert %s to %s", x, T) + x.mode = invalid + return + } + + // The conversion argument types are final. For untyped values the + // conversion provides the type, per the spec: "A constant may be + // given a type explicitly by a constant declaration or conversion,...". + final := x.typ + if isUntyped(x.typ) { + final = T + // - For conversions to interfaces, use the argument's default type. + // - For conversions of untyped constants to non-constant types, also + // use the default type (e.g., []byte("foo") should report string + // not []byte as type for the constant "foo"). + // - Keep untyped nil for untyped nil arguments. + if IsInterface(T) || constArg && !isConstType(T) { + final = defaultType(x.typ) + } + check.updateExprType(x.expr, final, true) + } + + x.typ = T +} + +func (x *operand) convertibleTo(conf *Config, T Type) bool { + // "x is assignable to T" + if x.assignableTo(conf, T) { + return true + } + + // "x's type and T have identical underlying types" + V := x.typ + Vu := V.Underlying() + Tu := T.Underlying() + if Identical(Vu, Tu) { + return true + } + + // "x's type and T are unnamed pointer types and their pointer base types have identical underlying types" + if V, ok := V.(*Pointer); ok { + if T, ok := T.(*Pointer); ok { + if Identical(V.base.Underlying(), T.base.Underlying()) { + return true + } + } + } + + // "x's type and T are both integer or floating point types" + if (isInteger(V) || isFloat(V)) && (isInteger(T) || isFloat(T)) { + return true + } + + // "x's type and T are both complex types" + if isComplex(V) && isComplex(T) { + return true + } + + // "x is an integer or a slice of bytes or runes and T is a string type" + if (isInteger(V) || isBytesOrRunes(Vu)) && isString(T) { + return true + } + + // "x is a string and T is a slice of bytes or runes" + if isString(V) && isBytesOrRunes(Tu) { + return true + } + + // package unsafe: + // "any pointer or value of underlying type uintptr can be converted into a unsafe.Pointer" + if (isPointer(Vu) || isUintptr(Vu)) && isUnsafePointer(T) { + return true + } + // "and vice versa" + if isUnsafePointer(V) && (isPointer(Tu) || isUintptr(Tu)) { + return true + } + + return false +} + +func isUintptr(typ Type) bool { + t, ok := typ.Underlying().(*Basic) + return ok && t.kind == Uintptr +} + +func isUnsafePointer(typ Type) bool { + // TODO(gri): Is this (typ.Underlying() instead of just typ) correct? + // The spec does not say so, but gc claims it is. See also + // issue 6326. + t, ok := typ.Underlying().(*Basic) + return ok && t.kind == UnsafePointer +} + +func isPointer(typ Type) bool { + _, ok := typ.Underlying().(*Pointer) + return ok +} + +func isBytesOrRunes(typ Type) bool { + if s, ok := typ.(*Slice); ok { + t, ok := s.elem.Underlying().(*Basic) + return ok && (t.kind == Byte || t.kind == Rune) + } + return false +} diff --git a/libgo/go/go/types/decl.go b/libgo/go/go/types/decl.go new file mode 100644 index 00000000000..8e9e5f36de4 --- /dev/null +++ b/libgo/go/go/types/decl.go @@ -0,0 +1,430 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package types + +import ( + "go/ast" + "go/constant" + "go/token" +) + +func (check *Checker) reportAltDecl(obj Object) { + if pos := obj.Pos(); pos.IsValid() { + // We use "other" rather than "previous" here because + // the first declaration seen may not be textually + // earlier in the source. + check.errorf(pos, "\tother declaration of %s", obj.Name()) // secondary error, \t indented + } +} + +func (check *Checker) declare(scope *Scope, id *ast.Ident, obj Object, pos token.Pos) { + // spec: "The blank identifier, represented by the underscore + // character _, may be used in a declaration like any other + // identifier but the declaration does not introduce a new + // binding." + if obj.Name() != "_" { + if alt := scope.Insert(obj); alt != nil { + check.errorf(obj.Pos(), "%s redeclared in this block", obj.Name()) + check.reportAltDecl(alt) + return + } + obj.setScopePos(pos) + } + if id != nil { + check.recordDef(id, obj) + } +} + +// objDecl type-checks the declaration of obj in its respective (file) context. +// See check.typ for the details on def and path. +func (check *Checker) objDecl(obj Object, def *Named, path []*TypeName) { + if obj.Type() != nil { + return // already checked - nothing to do + } + + if trace { + check.trace(obj.Pos(), "-- declaring %s", obj.Name()) + check.indent++ + defer func() { + check.indent-- + check.trace(obj.Pos(), "=> %s", obj) + }() + } + + d := check.objMap[obj] + if d == nil { + check.dump("%s: %s should have been declared", obj.Pos(), obj.Name()) + unreachable() + } + + // save/restore current context and setup object context + defer func(ctxt context) { + check.context = ctxt + }(check.context) + check.context = context{ + scope: d.file, + } + + // Const and var declarations must not have initialization + // cycles. We track them by remembering the current declaration + // in check.decl. Initialization expressions depending on other + // consts, vars, or functions, add dependencies to the current + // check.decl. + switch obj := obj.(type) { + case *Const: + check.decl = d // new package-level const decl + check.constDecl(obj, d.typ, d.init) + case *Var: + check.decl = d // new package-level var decl + check.varDecl(obj, d.lhs, d.typ, d.init) + case *TypeName: + // invalid recursive types are detected via path + check.typeDecl(obj, d.typ, def, path) + case *Func: + // functions may be recursive - no need to track dependencies + check.funcDecl(obj, d) + default: + unreachable() + } +} + +func (check *Checker) constDecl(obj *Const, typ, init ast.Expr) { + assert(obj.typ == nil) + + if obj.visited { + obj.typ = Typ[Invalid] + return + } + obj.visited = true + + // use the correct value of iota + assert(check.iota == nil) + check.iota = obj.val + defer func() { check.iota = nil }() + + // provide valid constant value under all circumstances + obj.val = constant.MakeUnknown() + + // determine type, if any + if typ != nil { + t := check.typ(typ) + if !isConstType(t) { + check.errorf(typ.Pos(), "invalid constant type %s", t) + obj.typ = Typ[Invalid] + return + } + obj.typ = t + } + + // check initialization + var x operand + if init != nil { + check.expr(&x, init) + } + check.initConst(obj, &x) +} + +func (check *Checker) varDecl(obj *Var, lhs []*Var, typ, init ast.Expr) { + assert(obj.typ == nil) + + if obj.visited { + obj.typ = Typ[Invalid] + return + } + obj.visited = true + + // var declarations cannot use iota + assert(check.iota == nil) + + // determine type, if any + if typ != nil { + obj.typ = check.typ(typ) + } + + // check initialization + if init == nil { + if typ == nil { + // error reported before by arityMatch + obj.typ = Typ[Invalid] + } + return + } + + if lhs == nil || len(lhs) == 1 { + assert(lhs == nil || lhs[0] == obj) + var x operand + check.expr(&x, init) + check.initVar(obj, &x, false) + return + } + + if debug { + // obj must be one of lhs + found := false + for _, lhs := range lhs { + if obj == lhs { + found = true + break + } + } + if !found { + panic("inconsistent lhs") + } + } + check.initVars(lhs, []ast.Expr{init}, token.NoPos) +} + +// underlying returns the underlying type of typ; possibly by following +// forward chains of named types. Such chains only exist while named types +// are incomplete. +func underlying(typ Type) Type { + for { + n, _ := typ.(*Named) + if n == nil { + break + } + typ = n.underlying + } + return typ +} + +func (n *Named) setUnderlying(typ Type) { + if n != nil { + n.underlying = typ + } +} + +func (check *Checker) typeDecl(obj *TypeName, typ ast.Expr, def *Named, path []*TypeName) { + assert(obj.typ == nil) + + // type declarations cannot use iota + assert(check.iota == nil) + + named := &Named{obj: obj} + def.setUnderlying(named) + obj.typ = named // make sure recursive type declarations terminate + + // determine underlying type of named + check.typExpr(typ, named, append(path, obj)) + + // The underlying type of named may be itself a named type that is + // incomplete: + // + // type ( + // A B + // B *C + // C A + // ) + // + // The type of C is the (named) type of A which is incomplete, + // and which has as its underlying type the named type B. + // Determine the (final, unnamed) underlying type by resolving + // any forward chain (they always end in an unnamed type). + named.underlying = underlying(named.underlying) + + // check and add associated methods + // TODO(gri) It's easy to create pathological cases where the + // current approach is incorrect: In general we need to know + // and add all methods _before_ type-checking the type. + // See https://play.golang.org/p/WMpE0q2wK8 + check.addMethodDecls(obj) +} + +func (check *Checker) addMethodDecls(obj *TypeName) { + // get associated methods + methods := check.methods[obj.name] + if len(methods) == 0 { + return // no methods + } + delete(check.methods, obj.name) + + // use an objset to check for name conflicts + var mset objset + + // spec: "If the base type is a struct type, the non-blank method + // and field names must be distinct." + base := obj.typ.(*Named) + if t, _ := base.underlying.(*Struct); t != nil { + for _, fld := range t.fields { + if fld.name != "_" { + assert(mset.insert(fld) == nil) + } + } + } + + // Checker.Files may be called multiple times; additional package files + // may add methods to already type-checked types. Add pre-existing methods + // so that we can detect redeclarations. + for _, m := range base.methods { + assert(m.name != "_") + assert(mset.insert(m) == nil) + } + + // type-check methods + for _, m := range methods { + // spec: "For a base type, the non-blank names of methods bound + // to it must be unique." + if m.name != "_" { + if alt := mset.insert(m); alt != nil { + switch alt.(type) { + case *Var: + check.errorf(m.pos, "field and method with the same name %s", m.name) + case *Func: + check.errorf(m.pos, "method %s already declared for %s", m.name, base) + default: + unreachable() + } + check.reportAltDecl(alt) + continue + } + } + check.objDecl(m, nil, nil) + // methods with blank _ names cannot be found - don't keep them + if m.name != "_" { + base.methods = append(base.methods, m) + } + } +} + +func (check *Checker) funcDecl(obj *Func, decl *declInfo) { + assert(obj.typ == nil) + + // func declarations cannot use iota + assert(check.iota == nil) + + sig := new(Signature) + obj.typ = sig // guard against cycles + fdecl := decl.fdecl + check.funcType(sig, fdecl.Recv, fdecl.Type) + if sig.recv == nil && obj.name == "init" && (sig.params.Len() > 0 || sig.results.Len() > 0) { + check.errorf(fdecl.Pos(), "func init must have no arguments and no return values") + // ok to continue + } + + // function body must be type-checked after global declarations + // (functions implemented elsewhere have no body) + if !check.conf.IgnoreFuncBodies && fdecl.Body != nil { + check.later(obj.name, decl, sig, fdecl.Body) + } +} + +func (check *Checker) declStmt(decl ast.Decl) { + pkg := check.pkg + + switch d := decl.(type) { + case *ast.BadDecl: + // ignore + + case *ast.GenDecl: + var last *ast.ValueSpec // last ValueSpec with type or init exprs seen + for iota, spec := range d.Specs { + switch s := spec.(type) { + case *ast.ValueSpec: + switch d.Tok { + case token.CONST: + // determine which init exprs to use + switch { + case s.Type != nil || len(s.Values) > 0: + last = s + case last == nil: + last = new(ast.ValueSpec) // make sure last exists + } + + // declare all constants + lhs := make([]*Const, len(s.Names)) + for i, name := range s.Names { + obj := NewConst(name.Pos(), pkg, name.Name, nil, constant.MakeInt64(int64(iota))) + lhs[i] = obj + + var init ast.Expr + if i < len(last.Values) { + init = last.Values[i] + } + + check.constDecl(obj, last.Type, init) + } + + check.arityMatch(s, last) + + // spec: "The scope of a constant or variable identifier declared + // inside a function begins at the end of the ConstSpec or VarSpec + // (ShortVarDecl for short variable declarations) and ends at the + // end of the innermost containing block." + scopePos := s.End() + for i, name := range s.Names { + check.declare(check.scope, name, lhs[i], scopePos) + } + + case token.VAR: + lhs0 := make([]*Var, len(s.Names)) + for i, name := range s.Names { + lhs0[i] = NewVar(name.Pos(), pkg, name.Name, nil) + } + + // initialize all variables + for i, obj := range lhs0 { + var lhs []*Var + var init ast.Expr + switch len(s.Values) { + case len(s.Names): + // lhs and rhs match + init = s.Values[i] + case 1: + // rhs is expected to be a multi-valued expression + lhs = lhs0 + init = s.Values[0] + default: + if i < len(s.Values) { + init = s.Values[i] + } + } + check.varDecl(obj, lhs, s.Type, init) + if len(s.Values) == 1 { + // If we have a single lhs variable we are done either way. + // If we have a single rhs expression, it must be a multi- + // valued expression, in which case handling the first lhs + // variable will cause all lhs variables to have a type + // assigned, and we are done as well. + if debug { + for _, obj := range lhs0 { + assert(obj.typ != nil) + } + } + break + } + } + + check.arityMatch(s, nil) + + // declare all variables + // (only at this point are the variable scopes (parents) set) + scopePos := s.End() // see constant declarations + for i, name := range s.Names { + // see constant declarations + check.declare(check.scope, name, lhs0[i], scopePos) + } + + default: + check.invalidAST(s.Pos(), "invalid token %s", d.Tok) + } + + case *ast.TypeSpec: + obj := NewTypeName(s.Name.Pos(), pkg, s.Name.Name, nil) + // spec: "The scope of a type identifier declared inside a function + // begins at the identifier in the TypeSpec and ends at the end of + // the innermost containing block." + scopePos := s.Name.Pos() + check.declare(check.scope, s.Name, obj, scopePos) + check.typeDecl(obj, s.Type, nil, nil) + + default: + check.invalidAST(s.Pos(), "const, type, or var declaration expected") + } + } + + default: + check.invalidAST(d.Pos(), "unknown ast.Decl node %T", d) + } +} diff --git a/libgo/go/go/types/errors.go b/libgo/go/go/types/errors.go new file mode 100644 index 00000000000..0c0049b1f3e --- /dev/null +++ b/libgo/go/go/types/errors.go @@ -0,0 +1,103 @@ +// 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 various error reporters. + +package types + +import ( + "fmt" + "go/ast" + "go/token" + "strings" +) + +func assert(p bool) { + if !p { + panic("assertion failed") + } +} + +func unreachable() { + panic("unreachable") +} + +func (check *Checker) qualifier(pkg *Package) string { + if pkg != check.pkg { + return pkg.path + } + return "" +} + +func (check *Checker) sprintf(format string, args ...interface{}) string { + for i, arg := range args { + switch a := arg.(type) { + case nil: + arg = "" + case operand: + panic("internal error: should always pass *operand") + case *operand: + arg = operandString(a, check.qualifier) + case token.Pos: + arg = check.fset.Position(a).String() + case ast.Expr: + arg = ExprString(a) + case Object: + arg = ObjectString(a, check.qualifier) + case Type: + arg = TypeString(a, check.qualifier) + } + args[i] = arg + } + return fmt.Sprintf(format, args...) +} + +func (check *Checker) trace(pos token.Pos, format string, args ...interface{}) { + fmt.Printf("%s:\t%s%s\n", + check.fset.Position(pos), + strings.Repeat(". ", check.indent), + check.sprintf(format, args...), + ) +} + +// dump is only needed for debugging +func (check *Checker) dump(format string, args ...interface{}) { + fmt.Println(check.sprintf(format, args...)) +} + +func (check *Checker) err(pos token.Pos, msg string, soft bool) { + err := Error{check.fset, pos, msg, soft} + if check.firstErr == nil { + check.firstErr = err + } + f := check.conf.Error + if f == nil { + panic(bailout{}) // report only first error + } + f(err) +} + +func (check *Checker) error(pos token.Pos, msg string) { + check.err(pos, msg, false) +} + +func (check *Checker) errorf(pos token.Pos, format string, args ...interface{}) { + check.err(pos, check.sprintf(format, args...), false) +} + +func (check *Checker) softErrorf(pos token.Pos, format string, args ...interface{}) { + check.err(pos, check.sprintf(format, args...), true) +} + +func (check *Checker) invalidAST(pos token.Pos, format string, args ...interface{}) { + check.errorf(pos, "invalid AST: "+format, args...) +} + +func (check *Checker) invalidArg(pos token.Pos, format string, args ...interface{}) { + check.errorf(pos, "invalid argument: "+format, args...) +} + +func (check *Checker) invalidOp(pos token.Pos, format string, args ...interface{}) { + check.errorf(pos, "invalid operation: "+format, args...) +} diff --git a/libgo/go/go/types/eval.go b/libgo/go/go/types/eval.go new file mode 100644 index 00000000000..7b42ff1a9d0 --- /dev/null +++ b/libgo/go/go/types/eval.go @@ -0,0 +1,83 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package types + +import ( + "fmt" + "go/parser" + "go/token" +) + +// Eval returns the type and, if constant, the value for the +// expression expr, evaluated at position pos of package pkg, +// which must have been derived from type-checking an AST with +// complete position information relative to the provided file +// set. +// +// If the expression contains function literals, their bodies +// are ignored (i.e., the bodies are not type-checked). +// +// If pkg == nil, the Universe scope is used and the provided +// position pos is ignored. If pkg != nil, and pos is invalid, +// the package scope is used. Otherwise, pos must belong to the +// package. +// +// An error is returned if pos is not within the package or +// if the node cannot be evaluated. +// +// Note: Eval should not be used instead of running Check to compute +// types and values, but in addition to Check. Eval will re-evaluate +// its argument each time, and it also does not know about the context +// in which an expression is used (e.g., an assignment). Thus, top- +// level untyped constants will return an untyped type rather then the +// respective context-specific type. +// +func Eval(fset *token.FileSet, pkg *Package, pos token.Pos, expr string) (tv TypeAndValue, err error) { + // determine scope + var scope *Scope + if pkg == nil { + scope = Universe + pos = token.NoPos + } else if !pos.IsValid() { + scope = pkg.scope + } else { + // The package scope extent (position information) may be + // incorrect (files spread accross a wide range of fset + // positions) - ignore it and just consider its children + // (file scopes). + for _, fscope := range pkg.scope.children { + if scope = fscope.Innermost(pos); scope != nil { + break + } + } + if scope == nil || debug { + s := scope + for s != nil && s != pkg.scope { + s = s.parent + } + // s == nil || s == pkg.scope + if s == nil { + return TypeAndValue{}, fmt.Errorf("no position %s found in package %s", fset.Position(pos), pkg.name) + } + } + } + + // parse expressions + node, err := parser.ParseExprFrom(fset, "eval", expr, 0) + if err != nil { + return TypeAndValue{}, err + } + + // initialize checker + check := NewChecker(nil, fset, pkg, nil) + check.scope = scope + check.pos = pos + defer check.handleBailout(&err) + + // evaluate node + var x operand + check.rawExpr(&x, node, nil) + return TypeAndValue{x.mode, x.typ, x.val}, err +} diff --git a/libgo/go/go/types/eval_test.go b/libgo/go/go/types/eval_test.go new file mode 100644 index 00000000000..7e0be43e723 --- /dev/null +++ b/libgo/go/go/types/eval_test.go @@ -0,0 +1,188 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file contains tests for Eval. + +package types_test + +import ( + "go/ast" + "go/importer" + "go/parser" + "go/token" + "internal/testenv" + "strings" + "testing" + + . "go/types" +) + +func testEval(t *testing.T, fset *token.FileSet, pkg *Package, pos token.Pos, expr string, typ Type, typStr, valStr string) { + gotTv, err := Eval(fset, pkg, pos, expr) + if err != nil { + t.Errorf("Eval(%q) failed: %s", expr, err) + return + } + if gotTv.Type == nil { + t.Errorf("Eval(%q) got nil type but no error", expr) + return + } + + // compare types + if typ != nil { + // we have a type, check identity + if !Identical(gotTv.Type, typ) { + t.Errorf("Eval(%q) got type %s, want %s", expr, gotTv.Type, typ) + return + } + } else { + // we have a string, compare type string + gotStr := gotTv.Type.String() + if gotStr != typStr { + t.Errorf("Eval(%q) got type %s, want %s", expr, gotStr, typStr) + return + } + } + + // compare values + gotStr := "" + if gotTv.Value != nil { + gotStr = gotTv.Value.String() + } + if gotStr != valStr { + t.Errorf("Eval(%q) got value %s, want %s", expr, gotStr, valStr) + } +} + +func TestEvalBasic(t *testing.T) { + fset := token.NewFileSet() + for _, typ := range Typ[Bool : String+1] { + testEval(t, fset, nil, token.NoPos, typ.Name(), typ, "", "") + } +} + +func TestEvalComposite(t *testing.T) { + fset := token.NewFileSet() + for _, test := range independentTestTypes { + testEval(t, fset, nil, token.NoPos, test.src, nil, test.str, "") + } +} + +func TestEvalArith(t *testing.T) { + var tests = []string{ + `true`, + `false == false`, + `12345678 + 87654321 == 99999999`, + `10 * 20 == 200`, + `(1<<1000)*2 >> 100 == 2<<900`, + `"foo" + "bar" == "foobar"`, + `"abc" <= "bcd"`, + `len([10]struct{}{}) == 2*5`, + } + fset := token.NewFileSet() + for _, test := range tests { + testEval(t, fset, nil, token.NoPos, test, Typ[UntypedBool], "", "true") + } +} + +func TestEvalPos(t *testing.T) { + testenv.MustHaveGoBuild(t) + + // The contents of /*-style comments are of the form + // expr => value, type + // where value may be the empty string. + // Each expr is evaluated at the position of the comment + // and the result is compared with the expected value + // and type. + var sources = []string{ + ` + package p + import "fmt" + import m "math" + const c = 3.0 + type T []int + func f(a int, s string) float64 { + fmt.Println("calling f") + _ = m.Pi // use package math + const d int = c + 1 + var x int + x = a + len(s) + return float64(x) + /* true => true, untyped bool */ + /* fmt.Println => , func(a ...interface{}) (n int, err error) */ + /* c => 3, untyped float */ + /* T => , p.T */ + /* a => , int */ + /* s => , string */ + /* d => 4, int */ + /* x => , int */ + /* d/c => 1, int */ + /* c/2 => 3/2, untyped float */ + /* m.Pi < m.E => false, untyped bool */ + } + `, + ` + package p + /* c => 3, untyped float */ + type T1 /* T1 => , p.T1 */ struct {} + var v1 /* v1 => , int */ = 42 + func /* f1 => , func(v1 float64) */ f1(v1 float64) { + /* f1 => , func(v1 float64) */ + /* v1 => , float64 */ + var c /* c => 3, untyped float */ = "foo" /* c => , string */ + { + var c struct { + c /* c => , string */ int + } + /* c => , struct{c int} */ + _ = c + } + _ = func(a, b, c int) /* c => , string */ { + /* c => , int */ + } + _ = c + type FT /* FT => , p.FT */ interface{} + } + `, + ` + package p + /* T => , p.T */ + `, + } + + fset := token.NewFileSet() + var files []*ast.File + for i, src := range sources { + file, err := parser.ParseFile(fset, "p", src, parser.ParseComments) + if err != nil { + t.Fatalf("could not parse file %d: %s", i, err) + } + files = append(files, file) + } + + conf := Config{Importer: importer.Default()} + pkg, err := conf.Check("p", fset, files, nil) + if err != nil { + t.Fatal(err) + } + + for _, file := range files { + for _, group := range file.Comments { + for _, comment := range group.List { + s := comment.Text + if len(s) >= 4 && s[:2] == "/*" && s[len(s)-2:] == "*/" { + str, typ := split(s[2:len(s)-2], ", ") + str, val := split(str, "=>") + testEval(t, fset, pkg, comment.Pos(), str, nil, typ, val) + } + } + } + } +} + +// split splits string s at the first occurrence of s. +func split(s, sep string) (string, string) { + i := strings.Index(s, sep) + return strings.TrimSpace(s[:i]), strings.TrimSpace(s[i+len(sep):]) +} diff --git a/libgo/go/go/types/example_test.go b/libgo/go/go/types/example_test.go new file mode 100644 index 00000000000..9daad8765a8 --- /dev/null +++ b/libgo/go/go/types/example_test.go @@ -0,0 +1,312 @@ +// Copyright 2015 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. + +// Only run where builders (build.golang.org) have +// access to compiled packages for import. +// +// +build ignore,!arm,!arm64,!nacl + +package types_test + +// This file shows examples of basic usage of the go/types API. +// +// To locate a Go package, use (*go/build.Context).Import. +// To load, parse, and type-check a complete Go program +// from source, use golang.org/x/tools/go/loader. + +import ( + "bytes" + "fmt" + "go/ast" + "go/format" + "go/importer" + "go/parser" + "go/token" + "go/types" + "log" + "regexp" + "sort" + "strings" +) + +// ExampleScope prints the tree of Scopes of a package created from a +// set of parsed files. +func ExampleScope() { + // Parse the source files for a package. + fset := token.NewFileSet() + var files []*ast.File + for _, file := range []struct{ name, input string }{ + {"main.go", ` +package main +import "fmt" +func main() { + freezing := FToC(-18) + fmt.Println(freezing, Boiling) } +`}, + {"celsius.go", ` +package main +import "fmt" +type Celsius float64 +func (c Celsius) String() string { return fmt.Sprintf("%g°C", c) } +func FToC(f float64) Celsius { return Celsius(f - 32 / 9 * 5) } +const Boiling Celsius = 100 +`}, + } { + f, err := parser.ParseFile(fset, file.name, file.input, 0) + if err != nil { + log.Fatal(err) + } + files = append(files, f) + } + + // Type-check a package consisting of these files. + // Type information for the imported "fmt" package + // comes from $GOROOT/pkg/$GOOS_$GOOARCH/fmt.a. + conf := types.Config{Importer: importer.Default()} + pkg, err := conf.Check("temperature", fset, files, nil) + if err != nil { + log.Fatal(err) + } + + // Print the tree of scopes. + // For determinism, we redact addresses. + var buf bytes.Buffer + pkg.Scope().WriteTo(&buf, 0, true) + rx := regexp.MustCompile(` 0x[a-fA-F0-9]*`) + fmt.Println(rx.ReplaceAllString(buf.String(), "")) + + // Output: + // package "temperature" scope { + // . const temperature.Boiling temperature.Celsius + // . type temperature.Celsius float64 + // . func temperature.FToC(f float64) temperature.Celsius + // . func temperature.main() + // + // . main.go scope { + // . . package fmt + // + // . . function scope { + // . . . var freezing temperature.Celsius + // . . }. } + // . celsius.go scope { + // . . package fmt + // + // . . function scope { + // . . . var c temperature.Celsius + // . . } + // . . function scope { + // . . . var f float64 + // . . }. }} +} + +// ExampleMethodSet prints the method sets of various types. +func ExampleMethodSet() { + // Parse a single source file. + const input = ` +package temperature +import "fmt" +type Celsius float64 +func (c Celsius) String() string { return fmt.Sprintf("%g°C", c) } +func (c *Celsius) SetF(f float64) { *c = Celsius(f - 32 / 9 * 5) } +` + fset := token.NewFileSet() + f, err := parser.ParseFile(fset, "celsius.go", input, 0) + if err != nil { + log.Fatal(err) + } + + // Type-check a package consisting of this file. + // Type information for the imported packages + // comes from $GOROOT/pkg/$GOOS_$GOOARCH/fmt.a. + conf := types.Config{Importer: importer.Default()} + pkg, err := conf.Check("temperature", fset, []*ast.File{f}, nil) + if err != nil { + log.Fatal(err) + } + + // Print the method sets of Celsius and *Celsius. + celsius := pkg.Scope().Lookup("Celsius").Type() + for _, t := range []types.Type{celsius, types.NewPointer(celsius)} { + fmt.Printf("Method set of %s:\n", t) + mset := types.NewMethodSet(t) + for i := 0; i < mset.Len(); i++ { + fmt.Println(mset.At(i)) + } + fmt.Println() + } + + // Output: + // Method set of temperature.Celsius: + // method (temperature.Celsius) String() string + // + // Method set of *temperature.Celsius: + // method (*temperature.Celsius) SetF(f float64) + // method (*temperature.Celsius) String() string +} + +// ExampleInfo prints various facts recorded by the type checker in a +// types.Info struct: definitions of and references to each named object, +// and the type, value, and mode of every expression in the package. +func ExampleInfo() { + // Parse a single source file. + const input = ` +package fib + +type S string + +var a, b, c = len(b), S(c), "hello" + +func fib(x int) int { + if x < 2 { + return x + } + return fib(x-1) - fib(x-2) +}` + fset := token.NewFileSet() + f, err := parser.ParseFile(fset, "fib.go", input, 0) + if err != nil { + log.Fatal(err) + } + + // Type-check the package. + // We create an empty map for each kind of input + // we're interested in, and Check populates them. + info := types.Info{ + Types: make(map[ast.Expr]types.TypeAndValue), + Defs: make(map[*ast.Ident]types.Object), + Uses: make(map[*ast.Ident]types.Object), + } + var conf types.Config + pkg, err := conf.Check("fib", fset, []*ast.File{f}, &info) + if err != nil { + log.Fatal(err) + } + + // Print package-level variables in initialization order. + fmt.Printf("InitOrder: %v\n\n", info.InitOrder) + + // For each named object, print the line and + // column of its definition and each of its uses. + fmt.Println("Defs and Uses of each named object:") + usesByObj := make(map[types.Object][]string) + for id, obj := range info.Uses { + posn := fset.Position(id.Pos()) + lineCol := fmt.Sprintf("%d:%d", posn.Line, posn.Column) + usesByObj[obj] = append(usesByObj[obj], lineCol) + } + var items []string + for obj, uses := range usesByObj { + sort.Strings(uses) + item := fmt.Sprintf("%s:\n defined at %s\n used at %s", + types.ObjectString(obj, types.RelativeTo(pkg)), + fset.Position(obj.Pos()), + strings.Join(uses, ", ")) + items = append(items, item) + } + sort.Strings(items) // sort by line:col, in effect + fmt.Println(strings.Join(items, "\n")) + fmt.Println() + + fmt.Println("Types and Values of each expression:") + items = nil + for expr, tv := range info.Types { + var buf bytes.Buffer + posn := fset.Position(expr.Pos()) + tvstr := tv.Type.String() + if tv.Value != nil { + tvstr += " = " + tv.Value.String() + } + // line:col | expr | mode : type = value + fmt.Fprintf(&buf, "%2d:%2d | %-19s | %-7s : %s", + posn.Line, posn.Column, exprString(fset, expr), + mode(tv), tvstr) + items = append(items, buf.String()) + } + sort.Strings(items) + fmt.Println(strings.Join(items, "\n")) + + // Output: + // InitOrder: [c = "hello" b = S(c) a = len(b)] + // + // Defs and Uses of each named object: + // builtin len: + // defined at - + // used at 6:15 + // func fib(x int) int: + // defined at fib.go:8:6 + // used at 12:20, 12:9 + // type S string: + // defined at fib.go:4:6 + // used at 6:23 + // type int int: + // defined at - + // used at 8:12, 8:17 + // type string string: + // defined at - + // used at 4:8 + // var b S: + // defined at fib.go:6:8 + // used at 6:19 + // var c string: + // defined at fib.go:6:11 + // used at 6:25 + // var x int: + // defined at fib.go:8:10 + // used at 10:10, 12:13, 12:24, 9:5 + // + // Types and Values of each expression: + // 4: 8 | string | type : string + // 6:15 | len | builtin : func(string) int + // 6:15 | len(b) | value : int + // 6:19 | b | var : fib.S + // 6:23 | S | type : fib.S + // 6:23 | S(c) | value : fib.S + // 6:25 | c | var : string + // 6:29 | "hello" | value : string = "hello" + // 8:12 | int | type : int + // 8:17 | int | type : int + // 9: 5 | x | var : int + // 9: 5 | x < 2 | value : untyped bool + // 9: 9 | 2 | value : int = 2 + // 10:10 | x | var : int + // 12: 9 | fib | value : func(x int) int + // 12: 9 | fib(x - 1) | value : int + // 12: 9 | fib(x-1) - fib(x-2) | value : int + // 12:13 | x | var : int + // 12:13 | x - 1 | value : int + // 12:15 | 1 | value : int = 1 + // 12:20 | fib | value : func(x int) int + // 12:20 | fib(x - 2) | value : int + // 12:24 | x | var : int + // 12:24 | x - 2 | value : int + // 12:26 | 2 | value : int = 2 +} + +func mode(tv types.TypeAndValue) string { + switch { + case tv.IsVoid(): + return "void" + case tv.IsType(): + return "type" + case tv.IsBuiltin(): + return "builtin" + case tv.IsNil(): + return "nil" + case tv.Assignable(): + if tv.Addressable() { + return "var" + } + return "mapindex" + case tv.IsValue(): + return "value" + default: + return "unknown" + } +} + +func exprString(fset *token.FileSet, expr ast.Expr) string { + var buf bytes.Buffer + format.Node(&buf, fset, expr) + return buf.String() +} diff --git a/libgo/go/go/types/expr.go b/libgo/go/go/types/expr.go new file mode 100644 index 00000000000..7d00dd5fa5d --- /dev/null +++ b/libgo/go/go/types/expr.go @@ -0,0 +1,1496 @@ +// 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 typechecking of expressions. + +package types + +import ( + "fmt" + "go/ast" + "go/constant" + "go/token" + "math" +) + +/* +Basic algorithm: + +Expressions are checked recursively, top down. Expression checker functions +are generally of the form: + + func f(x *operand, e *ast.Expr, ...) + +where e is the expression to be checked, and x is the result of the check. +The check performed by f may fail in which case x.mode == invalid, and +related error messages will have been issued by f. + +If a hint argument is present, it is the composite literal element type +of an outer composite literal; it is used to type-check composite literal +elements that have no explicit type specification in the source +(e.g.: []T{{...}, {...}}, the hint is the type T in this case). + +All expressions are checked via rawExpr, which dispatches according +to expression kind. Upon returning, rawExpr is recording the types and +constant values for all expressions that have an untyped type (those types +may change on the way up in the expression tree). Usually these are constants, +but the results of comparisons or non-constant shifts of untyped constants +may also be untyped, but not constant. + +Untyped expressions may eventually become fully typed (i.e., not untyped), +typically when the value is assigned to a variable, or is used otherwise. +The updateExprType method is used to record this final type and update +the recorded types: the type-checked expression tree is again traversed down, +and the new type is propagated as needed. Untyped constant expression values +that become fully typed must now be representable by the full type (constant +sub-expression trees are left alone except for their roots). This mechanism +ensures that a client sees the actual (run-time) type an untyped value would +have. It also permits type-checking of lhs shift operands "as if the shift +were not present": when updateExprType visits an untyped lhs shift operand +and assigns it it's final type, that type must be an integer type, and a +constant lhs must be representable as an integer. + +When an expression gets its final type, either on the way out from rawExpr, +on the way down in updateExprType, or at the end of the type checker run, +the type (and constant value, if any) is recorded via Info.Types, if present. +*/ + +type opPredicates map[token.Token]func(Type) bool + +var unaryOpPredicates = opPredicates{ + token.ADD: isNumeric, + token.SUB: isNumeric, + token.XOR: isInteger, + token.NOT: isBoolean, +} + +func (check *Checker) op(m opPredicates, x *operand, op token.Token) bool { + if pred := m[op]; pred != nil { + if !pred(x.typ) { + check.invalidOp(x.pos(), "operator %s not defined for %s", op, x) + return false + } + } else { + check.invalidAST(x.pos(), "unknown operator %s", op) + return false + } + return true +} + +// The unary expression e may be nil. It's passed in for better error messages only. +func (check *Checker) unary(x *operand, e *ast.UnaryExpr, op token.Token) { + switch op { + case token.AND: + // spec: "As an exception to the addressability + // requirement x may also be a composite literal." + if _, ok := unparen(x.expr).(*ast.CompositeLit); !ok && x.mode != variable { + check.invalidOp(x.pos(), "cannot take address of %s", x) + x.mode = invalid + return + } + x.mode = value + x.typ = &Pointer{base: x.typ} + return + + case token.ARROW: + typ, ok := x.typ.Underlying().(*Chan) + if !ok { + check.invalidOp(x.pos(), "cannot receive from non-channel %s", x) + x.mode = invalid + return + } + if typ.dir == SendOnly { + check.invalidOp(x.pos(), "cannot receive from send-only channel %s", x) + x.mode = invalid + return + } + x.mode = commaok + x.typ = typ.elem + check.hasCallOrRecv = true + return + } + + if !check.op(unaryOpPredicates, x, op) { + x.mode = invalid + return + } + + if x.mode == constant_ { + typ := x.typ.Underlying().(*Basic) + var prec uint + if isUnsigned(typ) { + prec = uint(check.conf.sizeof(typ) * 8) + } + x.val = constant.UnaryOp(op, x.val, prec) + // Typed constants must be representable in + // their type after each constant operation. + if isTyped(typ) { + if e != nil { + x.expr = e // for better error message + } + check.representable(x, typ) + } + return + } + + x.mode = value + // x.typ remains unchanged +} + +func isShift(op token.Token) bool { + return op == token.SHL || op == token.SHR +} + +func isComparison(op token.Token) bool { + // Note: tokens are not ordered well to make this much easier + switch op { + case token.EQL, token.NEQ, token.LSS, token.LEQ, token.GTR, token.GEQ: + return true + } + return false +} + +func fitsFloat32(x constant.Value) bool { + f32, _ := constant.Float32Val(x) + f := float64(f32) + return !math.IsInf(f, 0) +} + +func roundFloat32(x constant.Value) constant.Value { + f32, _ := constant.Float32Val(x) + f := float64(f32) + if !math.IsInf(f, 0) { + return constant.MakeFloat64(f) + } + return nil +} + +func fitsFloat64(x constant.Value) bool { + f, _ := constant.Float64Val(x) + return !math.IsInf(f, 0) +} + +func roundFloat64(x constant.Value) constant.Value { + f, _ := constant.Float64Val(x) + if !math.IsInf(f, 0) { + return constant.MakeFloat64(f) + } + return nil +} + +// representableConst reports whether x can be represented as +// value of the given basic type kind and for the configuration +// provided (only needed for int/uint sizes). +// +// If rounded != nil, *rounded is set to the rounded value of x for +// representable floating-point values; it is left alone otherwise. +// It is ok to provide the addressof the first argument for rounded. +func representableConst(x constant.Value, conf *Config, as BasicKind, rounded *constant.Value) bool { + switch x.Kind() { + case constant.Unknown: + return true + + case constant.Bool: + return as == Bool || as == UntypedBool + + case constant.Int: + if x, ok := constant.Int64Val(x); ok { + switch as { + case Int: + var s = uint(conf.sizeof(Typ[as])) * 8 + return int64(-1)<<(s-1) <= x && x <= int64(1)<<(s-1)-1 + case Int8: + const s = 8 + return -1<<(s-1) <= x && x <= 1<<(s-1)-1 + case Int16: + const s = 16 + return -1<<(s-1) <= x && x <= 1<<(s-1)-1 + case Int32: + const s = 32 + return -1<<(s-1) <= x && x <= 1<<(s-1)-1 + case Int64: + return true + case Uint, Uintptr: + if s := uint(conf.sizeof(Typ[as])) * 8; s < 64 { + return 0 <= x && x <= int64(1)<= 0 && n <= int(s) + case Uint64: + return constant.Sign(x) >= 0 && n <= 64 + case Float32, Complex64: + if rounded == nil { + return fitsFloat32(x) + } + r := roundFloat32(x) + if r != nil { + *rounded = r + return true + } + case Float64, Complex128: + if rounded == nil { + return fitsFloat64(x) + } + r := roundFloat64(x) + if r != nil { + *rounded = r + return true + } + case UntypedInt, UntypedFloat, UntypedComplex: + return true + } + + case constant.Float: + switch as { + case Float32, Complex64: + if rounded == nil { + return fitsFloat32(x) + } + r := roundFloat32(x) + if r != nil { + *rounded = r + return true + } + case Float64, Complex128: + if rounded == nil { + return fitsFloat64(x) + } + r := roundFloat64(x) + if r != nil { + *rounded = r + return true + } + case UntypedFloat, UntypedComplex: + return true + } + + case constant.Complex: + switch as { + case Complex64: + if rounded == nil { + return fitsFloat32(constant.Real(x)) && fitsFloat32(constant.Imag(x)) + } + re := roundFloat32(constant.Real(x)) + im := roundFloat32(constant.Imag(x)) + if re != nil && im != nil { + *rounded = constant.BinaryOp(re, token.ADD, constant.MakeImag(im)) + return true + } + case Complex128: + if rounded == nil { + return fitsFloat64(constant.Real(x)) && fitsFloat64(constant.Imag(x)) + } + re := roundFloat64(constant.Real(x)) + im := roundFloat64(constant.Imag(x)) + if re != nil && im != nil { + *rounded = constant.BinaryOp(re, token.ADD, constant.MakeImag(im)) + return true + } + case UntypedComplex: + return true + } + + case constant.String: + return as == String || as == UntypedString + + default: + unreachable() + } + + return false +} + +// representable checks that a constant operand is representable in the given basic type. +func (check *Checker) representable(x *operand, typ *Basic) { + assert(x.mode == constant_) + if !representableConst(x.val, check.conf, typ.kind, &x.val) { + var msg string + if isNumeric(x.typ) && isNumeric(typ) { + // numeric conversion : error msg + // + // integer -> integer : overflows + // integer -> float : overflows (actually not possible) + // float -> integer : truncated + // float -> float : overflows + // + if !isInteger(x.typ) && isInteger(typ) { + msg = "%s truncated to %s" + } else { + msg = "%s overflows %s" + } + } else { + msg = "cannot convert %s to %s" + } + check.errorf(x.pos(), msg, x, typ) + x.mode = invalid + } +} + +// updateExprType updates the type of x to typ and invokes itself +// recursively for the operands of x, depending on expression kind. +// If typ is still an untyped and not the final type, updateExprType +// only updates the recorded untyped type for x and possibly its +// operands. Otherwise (i.e., typ is not an untyped type anymore, +// or it is the final type for x), the type and value are recorded. +// Also, if x is a constant, it must be representable as a value of typ, +// and if x is the (formerly untyped) lhs operand of a non-constant +// shift, it must be an integer value. +// +func (check *Checker) updateExprType(x ast.Expr, typ Type, final bool) { + old, found := check.untyped[x] + if !found { + return // nothing to do + } + + // update operands of x if necessary + switch x := x.(type) { + case *ast.BadExpr, + *ast.FuncLit, + *ast.CompositeLit, + *ast.IndexExpr, + *ast.SliceExpr, + *ast.TypeAssertExpr, + *ast.StarExpr, + *ast.KeyValueExpr, + *ast.ArrayType, + *ast.StructType, + *ast.FuncType, + *ast.InterfaceType, + *ast.MapType, + *ast.ChanType: + // These expression are never untyped - nothing to do. + // The respective sub-expressions got their final types + // upon assignment or use. + if debug { + check.dump("%s: found old type(%s): %s (new: %s)", x.Pos(), x, old.typ, typ) + unreachable() + } + return + + case *ast.CallExpr: + // Resulting in an untyped constant (e.g., built-in complex). + // The respective calls take care of calling updateExprType + // for the arguments if necessary. + + case *ast.Ident, *ast.BasicLit, *ast.SelectorExpr: + // An identifier denoting a constant, a constant literal, + // or a qualified identifier (imported untyped constant). + // No operands to take care of. + + case *ast.ParenExpr: + check.updateExprType(x.X, typ, final) + + case *ast.UnaryExpr: + // If x is a constant, the operands were constants. + // They don't need to be updated since they never + // get "materialized" into a typed value; and they + // will be processed at the end of the type check. + if old.val != nil { + break + } + check.updateExprType(x.X, typ, final) + + case *ast.BinaryExpr: + if old.val != nil { + break // see comment for unary expressions + } + if isComparison(x.Op) { + // The result type is independent of operand types + // and the operand types must have final types. + } else if isShift(x.Op) { + // The result type depends only on lhs operand. + // The rhs type was updated when checking the shift. + check.updateExprType(x.X, typ, final) + } else { + // The operand types match the result type. + check.updateExprType(x.X, typ, final) + check.updateExprType(x.Y, typ, final) + } + + default: + unreachable() + } + + // If the new type is not final and still untyped, just + // update the recorded type. + if !final && isUntyped(typ) { + old.typ = typ.Underlying().(*Basic) + check.untyped[x] = old + return + } + + // Otherwise we have the final (typed or untyped type). + // Remove it from the map of yet untyped expressions. + delete(check.untyped, x) + + // If x is the lhs of a shift, its final type must be integer. + // We already know from the shift check that it is representable + // as an integer if it is a constant. + if old.isLhs && !isInteger(typ) { + check.invalidOp(x.Pos(), "shifted operand %s (type %s) must be integer", x, typ) + return + } + + // Everything's fine, record final type and value for x. + check.recordTypeAndValue(x, old.mode, typ, old.val) +} + +// updateExprVal updates the value of x to val. +func (check *Checker) updateExprVal(x ast.Expr, val constant.Value) { + if info, ok := check.untyped[x]; ok { + info.val = val + check.untyped[x] = info + } +} + +// convertUntyped attempts to set the type of an untyped value to the target type. +func (check *Checker) convertUntyped(x *operand, target Type) { + if x.mode == invalid || isTyped(x.typ) || target == Typ[Invalid] { + return + } + + // TODO(gri) Sloppy code - clean up. This function is central + // to assignment and expression checking. + + if isUntyped(target) { + // both x and target are untyped + xkind := x.typ.(*Basic).kind + tkind := target.(*Basic).kind + if isNumeric(x.typ) && isNumeric(target) { + if xkind < tkind { + x.typ = target + check.updateExprType(x.expr, target, false) + } + } else if xkind != tkind { + goto Error + } + return + } + + // typed target + switch t := target.Underlying().(type) { + case *Basic: + if x.mode == constant_ { + check.representable(x, t) + if x.mode == invalid { + return + } + // expression value may have been rounded - update if needed + // TODO(gri) A floating-point value may silently underflow to + // zero. If it was negative, the sign is lost. See issue 6898. + check.updateExprVal(x.expr, x.val) + } else { + // Non-constant untyped values may appear as the + // result of comparisons (untyped bool), intermediate + // (delayed-checked) rhs operands of shifts, and as + // the value nil. + switch x.typ.(*Basic).kind { + case UntypedBool: + if !isBoolean(target) { + goto Error + } + case UntypedInt, UntypedRune, UntypedFloat, UntypedComplex: + if !isNumeric(target) { + goto Error + } + case UntypedString: + // Non-constant untyped string values are not + // permitted by the spec and should not occur. + unreachable() + case UntypedNil: + // Unsafe.Pointer is a basic type that includes nil. + if !hasNil(target) { + goto Error + } + default: + goto Error + } + } + case *Interface: + if !x.isNil() && !t.Empty() /* empty interfaces are ok */ { + goto Error + } + // Update operand types to the default type rather then + // the target (interface) type: values must have concrete + // dynamic types. If the value is nil, keep it untyped + // (this is important for tools such as go vet which need + // the dynamic type for argument checking of say, print + // functions) + if x.isNil() { + target = Typ[UntypedNil] + } else { + // cannot assign untyped values to non-empty interfaces + if !t.Empty() { + goto Error + } + target = defaultType(x.typ) + } + case *Pointer, *Signature, *Slice, *Map, *Chan: + if !x.isNil() { + goto Error + } + // keep nil untyped - see comment for interfaces, above + target = Typ[UntypedNil] + default: + goto Error + } + + x.typ = target + check.updateExprType(x.expr, target, true) // UntypedNils are final + return + +Error: + check.errorf(x.pos(), "cannot convert %s to %s", x, target) + x.mode = invalid +} + +func (check *Checker) comparison(x, y *operand, op token.Token) { + // spec: "In any comparison, the first operand must be assignable + // to the type of the second operand, or vice versa." + err := "" + if x.assignableTo(check.conf, y.typ) || y.assignableTo(check.conf, x.typ) { + defined := false + switch op { + case token.EQL, token.NEQ: + // spec: "The equality operators == and != apply to operands that are comparable." + defined = Comparable(x.typ) || x.isNil() && hasNil(y.typ) || y.isNil() && hasNil(x.typ) + case token.LSS, token.LEQ, token.GTR, token.GEQ: + // spec: The ordering operators <, <=, >, and >= apply to operands that are ordered." + defined = isOrdered(x.typ) + default: + unreachable() + } + if !defined { + typ := x.typ + if x.isNil() { + typ = y.typ + } + err = check.sprintf("operator %s not defined for %s", op, typ) + } + } else { + err = check.sprintf("mismatched types %s and %s", x.typ, y.typ) + } + + if err != "" { + check.errorf(x.pos(), "cannot compare %s %s %s (%s)", x.expr, op, y.expr, err) + x.mode = invalid + return + } + + if x.mode == constant_ && y.mode == constant_ { + x.val = constant.MakeBool(constant.Compare(x.val, op, y.val)) + // The operands are never materialized; no need to update + // their types. + } else { + x.mode = value + // The operands have now their final types, which at run- + // time will be materialized. Update the expression trees. + // If the current types are untyped, the materialized type + // is the respective default type. + check.updateExprType(x.expr, defaultType(x.typ), true) + check.updateExprType(y.expr, defaultType(y.typ), true) + } + + // spec: "Comparison operators compare two operands and yield + // an untyped boolean value." + x.typ = Typ[UntypedBool] +} + +func (check *Checker) shift(x, y *operand, op token.Token) { + untypedx := isUntyped(x.typ) + + // The lhs must be of integer type or be representable + // as an integer; otherwise the shift has no chance. + if !x.isInteger() { + check.invalidOp(x.pos(), "shifted operand %s must be integer", x) + x.mode = invalid + return + } + + // spec: "The right operand in a shift expression must have unsigned + // integer type or be an untyped constant that can be converted to + // unsigned integer type." + switch { + case isInteger(y.typ) && isUnsigned(y.typ): + // nothing to do + case isUntyped(y.typ): + check.convertUntyped(y, Typ[UntypedInt]) + if y.mode == invalid { + x.mode = invalid + return + } + default: + check.invalidOp(y.pos(), "shift count %s must be unsigned integer", y) + x.mode = invalid + return + } + + if x.mode == constant_ { + if y.mode == constant_ { + // rhs must be an integer value + if !y.isInteger() { + check.invalidOp(y.pos(), "shift count %s must be unsigned integer", y) + x.mode = invalid + return + } + // rhs must be within reasonable bounds + const stupidShift = 1023 - 1 + 52 // so we can express smallestFloat64 + s, ok := constant.Uint64Val(y.val) + if !ok || s > stupidShift { + check.invalidOp(y.pos(), "stupid shift count %s", y) + x.mode = invalid + return + } + // The lhs is representable as an integer but may not be an integer + // (e.g., 2.0, an untyped float) - this can only happen for untyped + // non-integer numeric constants. Correct the type so that the shift + // result is of integer type. + if !isInteger(x.typ) { + x.typ = Typ[UntypedInt] + } + x.val = constant.Shift(x.val, op, uint(s)) + return + } + + // non-constant shift with constant lhs + if untypedx { + // spec: "If the left operand of a non-constant shift + // expression is an untyped constant, the type of the + // constant is what it would be if the shift expression + // were replaced by its left operand alone.". + // + // Delay operand checking until we know the final type: + // The lhs expression must be in the untyped map, mark + // the entry as lhs shift operand. + info, found := check.untyped[x.expr] + assert(found) + info.isLhs = true + check.untyped[x.expr] = info + // keep x's type + x.mode = value + return + } + } + + // constant rhs must be >= 0 + if y.mode == constant_ && constant.Sign(y.val) < 0 { + check.invalidOp(y.pos(), "shift count %s must not be negative", y) + } + + // non-constant shift - lhs must be an integer + if !isInteger(x.typ) { + check.invalidOp(x.pos(), "shifted operand %s must be integer", x) + x.mode = invalid + return + } + + x.mode = value +} + +var binaryOpPredicates = opPredicates{ + token.ADD: func(typ Type) bool { return isNumeric(typ) || isString(typ) }, + token.SUB: isNumeric, + token.MUL: isNumeric, + token.QUO: isNumeric, + token.REM: isInteger, + + token.AND: isInteger, + token.OR: isInteger, + token.XOR: isInteger, + token.AND_NOT: isInteger, + + token.LAND: isBoolean, + token.LOR: isBoolean, +} + +// The binary expression e may be nil. It's passed in for better error messages only. +func (check *Checker) binary(x *operand, e *ast.BinaryExpr, lhs, rhs ast.Expr, op token.Token) { + var y operand + + check.expr(x, lhs) + check.expr(&y, rhs) + + if x.mode == invalid { + return + } + if y.mode == invalid { + x.mode = invalid + x.expr = y.expr + return + } + + if isShift(op) { + check.shift(x, &y, op) + return + } + + check.convertUntyped(x, y.typ) + if x.mode == invalid { + return + } + check.convertUntyped(&y, x.typ) + if y.mode == invalid { + x.mode = invalid + return + } + + if isComparison(op) { + check.comparison(x, &y, op) + return + } + + if !Identical(x.typ, y.typ) { + // only report an error if we have valid types + // (otherwise we had an error reported elsewhere already) + if x.typ != Typ[Invalid] && y.typ != Typ[Invalid] { + check.invalidOp(x.pos(), "mismatched types %s and %s", x.typ, y.typ) + } + x.mode = invalid + return + } + + if !check.op(binaryOpPredicates, x, op) { + x.mode = invalid + return + } + + if (op == token.QUO || op == token.REM) && (x.mode == constant_ || isInteger(x.typ)) && y.mode == constant_ && constant.Sign(y.val) == 0 { + check.invalidOp(y.pos(), "division by zero") + x.mode = invalid + return + } + + if x.mode == constant_ && y.mode == constant_ { + typ := x.typ.Underlying().(*Basic) + // force integer division of integer operands + if op == token.QUO && isInteger(typ) { + op = token.QUO_ASSIGN + } + x.val = constant.BinaryOp(x.val, op, y.val) + // Typed constants must be representable in + // their type after each constant operation. + if isTyped(typ) { + if e != nil { + x.expr = e // for better error message + } + check.representable(x, typ) + } + return + } + + x.mode = value + // x.typ is unchanged +} + +// index checks an index expression for validity. +// If max >= 0, it is the upper bound for index. +// If index is valid and the result i >= 0, then i is the constant value of index. +func (check *Checker) index(index ast.Expr, max int64) (i int64, valid bool) { + var x operand + check.expr(&x, index) + if x.mode == invalid { + return + } + + // an untyped constant must be representable as Int + check.convertUntyped(&x, Typ[Int]) + if x.mode == invalid { + return + } + + // the index must be of integer type + if !isInteger(x.typ) { + check.invalidArg(x.pos(), "index %s must be integer", &x) + return + } + + // a constant index i must be in bounds + if x.mode == constant_ { + if constant.Sign(x.val) < 0 { + check.invalidArg(x.pos(), "index %s must not be negative", &x) + return + } + i, valid = constant.Int64Val(x.val) + if !valid || max >= 0 && i >= max { + check.errorf(x.pos(), "index %s is out of bounds", &x) + return i, false + } + // 0 <= i [ && i < max ] + return i, true + } + + return -1, true +} + +// indexElts checks the elements (elts) of an array or slice composite literal +// against the literal's element type (typ), and the element indices against +// the literal length if known (length >= 0). It returns the length of the +// literal (maximum index value + 1). +// +func (check *Checker) indexedElts(elts []ast.Expr, typ Type, length int64) int64 { + visited := make(map[int64]bool, len(elts)) + var index, max int64 + for _, e := range elts { + // determine and check index + validIndex := false + eval := e + if kv, _ := e.(*ast.KeyValueExpr); kv != nil { + if i, ok := check.index(kv.Key, length); ok { + if i >= 0 { + index = i + validIndex = true + } else { + check.errorf(e.Pos(), "index %s must be integer constant", kv.Key) + } + } + eval = kv.Value + } else if length >= 0 && index >= length { + check.errorf(e.Pos(), "index %d is out of bounds (>= %d)", index, length) + } else { + validIndex = true + } + + // if we have a valid index, check for duplicate entries + if validIndex { + if visited[index] { + check.errorf(e.Pos(), "duplicate index %d in array or slice literal", index) + } + visited[index] = true + } + index++ + if index > max { + max = index + } + + // check element against composite literal element type + var x operand + check.exprWithHint(&x, eval, typ) + if !check.assignment(&x, typ) && x.mode != invalid { + check.errorf(x.pos(), "cannot use %s as %s value in array or slice literal", &x, typ) + } + } + return max +} + +// exprKind describes the kind of an expression; the kind +// determines if an expression is valid in 'statement context'. +type exprKind int + +const ( + conversion exprKind = iota + expression + statement +) + +// rawExpr typechecks expression e and initializes x with the expression +// value or type. If an error occurred, x.mode is set to invalid. +// If hint != nil, it is the type of a composite literal element. +// +func (check *Checker) rawExpr(x *operand, e ast.Expr, hint Type) exprKind { + if trace { + check.trace(e.Pos(), "%s", e) + check.indent++ + defer func() { + check.indent-- + check.trace(e.Pos(), "=> %s", x) + }() + } + + kind := check.exprInternal(x, e, hint) + + // convert x into a user-friendly set of values + // TODO(gri) this code can be simplified + var typ Type + var val constant.Value + switch x.mode { + case invalid: + typ = Typ[Invalid] + case novalue: + typ = (*Tuple)(nil) + case constant_: + typ = x.typ + val = x.val + default: + typ = x.typ + } + assert(x.expr != nil && typ != nil) + + if isUntyped(typ) { + // delay type and value recording until we know the type + // or until the end of type checking + check.rememberUntyped(x.expr, false, x.mode, typ.(*Basic), val) + } else { + check.recordTypeAndValue(e, x.mode, typ, val) + } + + return kind +} + +// exprInternal contains the core of type checking of expressions. +// Must only be called by rawExpr. +// +func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind { + // make sure x has a valid state in case of bailout + // (was issue 5770) + x.mode = invalid + x.typ = Typ[Invalid] + + switch e := e.(type) { + case *ast.BadExpr: + goto Error // error was reported before + + case *ast.Ident: + check.ident(x, e, nil, nil) + + case *ast.Ellipsis: + // ellipses are handled explicitly where they are legal + // (array composite literals and parameter lists) + check.error(e.Pos(), "invalid use of '...'") + goto Error + + case *ast.BasicLit: + x.setConst(e.Kind, e.Value) + if x.mode == invalid { + check.invalidAST(e.Pos(), "invalid literal %v", e.Value) + goto Error + } + + case *ast.FuncLit: + if sig, ok := check.typ(e.Type).(*Signature); ok { + // Anonymous functions are considered part of the + // init expression/func declaration which contains + // them: use existing package-level declaration info. + check.funcBody(check.decl, "", sig, e.Body) + x.mode = value + x.typ = sig + } else { + check.invalidAST(e.Pos(), "invalid function literal %s", e) + goto Error + } + + case *ast.CompositeLit: + typ := hint + openArray := false + if e.Type != nil { + // [...]T array types may only appear with composite literals. + // Check for them here so we don't have to handle ... in general. + typ = nil + if atyp, _ := e.Type.(*ast.ArrayType); atyp != nil && atyp.Len != nil { + if ellip, _ := atyp.Len.(*ast.Ellipsis); ellip != nil && ellip.Elt == nil { + // We have an "open" [...]T array type. + // Create a new ArrayType with unknown length (-1) + // and finish setting it up after analyzing the literal. + typ = &Array{len: -1, elem: check.typ(atyp.Elt)} + openArray = true + } + } + if typ == nil { + typ = check.typ(e.Type) + } + } + if typ == nil { + // TODO(gri) provide better error messages depending on context + check.error(e.Pos(), "missing type in composite literal") + goto Error + } + + switch typ, _ := deref(typ); utyp := typ.Underlying().(type) { + case *Struct: + if len(e.Elts) == 0 { + break + } + fields := utyp.fields + if _, ok := e.Elts[0].(*ast.KeyValueExpr); ok { + // all elements must have keys + visited := make([]bool, len(fields)) + for _, e := range e.Elts { + kv, _ := e.(*ast.KeyValueExpr) + if kv == nil { + check.error(e.Pos(), "mixture of field:value and value elements in struct literal") + continue + } + key, _ := kv.Key.(*ast.Ident) + if key == nil { + check.errorf(kv.Pos(), "invalid field name %s in struct literal", kv.Key) + continue + } + i := fieldIndex(utyp.fields, check.pkg, key.Name) + if i < 0 { + check.errorf(kv.Pos(), "unknown field %s in struct literal", key.Name) + continue + } + fld := fields[i] + check.recordUse(key, fld) + // 0 <= i < len(fields) + if visited[i] { + check.errorf(kv.Pos(), "duplicate field name %s in struct literal", key.Name) + continue + } + visited[i] = true + check.expr(x, kv.Value) + etyp := fld.typ + if !check.assignment(x, etyp) { + if x.mode != invalid { + check.errorf(x.pos(), "cannot use %s as %s value in struct literal", x, etyp) + } + continue + } + } + } else { + // no element must have a key + for i, e := range e.Elts { + if kv, _ := e.(*ast.KeyValueExpr); kv != nil { + check.error(kv.Pos(), "mixture of field:value and value elements in struct literal") + continue + } + check.expr(x, e) + if i >= len(fields) { + check.error(x.pos(), "too many values in struct literal") + break // cannot continue + } + // i < len(fields) + fld := fields[i] + if !fld.Exported() && fld.pkg != check.pkg { + check.errorf(x.pos(), "implicit assignment to unexported field %s in %s literal", fld.name, typ) + continue + } + etyp := fld.typ + if !check.assignment(x, etyp) { + if x.mode != invalid { + check.errorf(x.pos(), "cannot use %s as %s value in struct literal", x, etyp) + } + continue + } + } + if len(e.Elts) < len(fields) { + check.error(e.Rbrace, "too few values in struct literal") + // ok to continue + } + } + + case *Array: + n := check.indexedElts(e.Elts, utyp.elem, utyp.len) + // if we have an "open" [...]T array, set the length now that we know it + if openArray { + utyp.len = n + } + + case *Slice: + check.indexedElts(e.Elts, utyp.elem, -1) + + case *Map: + visited := make(map[interface{}][]Type, len(e.Elts)) + for _, e := range e.Elts { + kv, _ := e.(*ast.KeyValueExpr) + if kv == nil { + check.error(e.Pos(), "missing key in map literal") + continue + } + check.exprWithHint(x, kv.Key, utyp.key) + if !check.assignment(x, utyp.key) { + if x.mode != invalid { + check.errorf(x.pos(), "cannot use %s as %s key in map literal", x, utyp.key) + } + continue + } + if x.mode == constant_ { + duplicate := false + // if the key is of interface type, the type is also significant when checking for duplicates + if _, ok := utyp.key.Underlying().(*Interface); ok { + for _, vtyp := range visited[x.val] { + if Identical(vtyp, x.typ) { + duplicate = true + break + } + } + visited[x.val] = append(visited[x.val], x.typ) + } else { + _, duplicate = visited[x.val] + visited[x.val] = nil + } + if duplicate { + check.errorf(x.pos(), "duplicate key %s in map literal", x.val) + continue + } + } + check.exprWithHint(x, kv.Value, utyp.elem) + if !check.assignment(x, utyp.elem) { + if x.mode != invalid { + check.errorf(x.pos(), "cannot use %s as %s value in map literal", x, utyp.elem) + } + continue + } + } + + default: + // if utyp is invalid, an error was reported before + if utyp != Typ[Invalid] { + check.errorf(e.Pos(), "invalid composite literal type %s", typ) + goto Error + } + } + + x.mode = value + x.typ = typ + + case *ast.ParenExpr: + kind := check.rawExpr(x, e.X, nil) + x.expr = e + return kind + + case *ast.SelectorExpr: + check.selector(x, e) + + case *ast.IndexExpr: + check.expr(x, e.X) + if x.mode == invalid { + goto Error + } + + valid := false + length := int64(-1) // valid if >= 0 + switch typ := x.typ.Underlying().(type) { + case *Basic: + if isString(typ) { + valid = true + if x.mode == constant_ { + length = int64(len(constant.StringVal(x.val))) + } + // an indexed string always yields a byte value + // (not a constant) even if the string and the + // index are constant + x.mode = value + x.typ = universeByte // use 'byte' name + } + + case *Array: + valid = true + length = typ.len + if x.mode != variable { + x.mode = value + } + x.typ = typ.elem + + case *Pointer: + if typ, _ := typ.base.Underlying().(*Array); typ != nil { + valid = true + length = typ.len + x.mode = variable + x.typ = typ.elem + } + + case *Slice: + valid = true + x.mode = variable + x.typ = typ.elem + + case *Map: + var key operand + check.expr(&key, e.Index) + if !check.assignment(&key, typ.key) { + if key.mode != invalid { + check.invalidOp(key.pos(), "cannot use %s as map index of type %s", &key, typ.key) + } + goto Error + } + x.mode = mapindex + x.typ = typ.elem + x.expr = e + return expression + } + + if !valid { + check.invalidOp(x.pos(), "cannot index %s", x) + goto Error + } + + if e.Index == nil { + check.invalidAST(e.Pos(), "missing index for %s", x) + goto Error + } + + check.index(e.Index, length) + // ok to continue + + case *ast.SliceExpr: + check.expr(x, e.X) + if x.mode == invalid { + goto Error + } + + valid := false + length := int64(-1) // valid if >= 0 + switch typ := x.typ.Underlying().(type) { + case *Basic: + if isString(typ) { + if slice3(e) { + check.invalidOp(x.pos(), "3-index slice of string") + goto Error + } + valid = true + if x.mode == constant_ { + length = int64(len(constant.StringVal(x.val))) + } + // spec: "For untyped string operands the result + // is a non-constant value of type string." + if typ.kind == UntypedString { + x.typ = Typ[String] + } + } + + case *Array: + valid = true + length = typ.len + if x.mode != variable { + check.invalidOp(x.pos(), "cannot slice %s (value not addressable)", x) + goto Error + } + x.typ = &Slice{elem: typ.elem} + + case *Pointer: + if typ, _ := typ.base.Underlying().(*Array); typ != nil { + valid = true + length = typ.len + x.typ = &Slice{elem: typ.elem} + } + + case *Slice: + valid = true + // x.typ doesn't change + } + + if !valid { + check.invalidOp(x.pos(), "cannot slice %s", x) + goto Error + } + + x.mode = value + + // spec: "Only the first index may be omitted; it defaults to 0." + if slice3(e) && (e.High == nil || sliceMax(e) == nil) { + check.error(e.Rbrack, "2nd and 3rd index required in 3-index slice") + goto Error + } + + // check indices + var ind [3]int64 + for i, expr := range []ast.Expr{e.Low, e.High, sliceMax(e)} { + x := int64(-1) + switch { + case expr != nil: + // The "capacity" is only known statically for strings, arrays, + // and pointers to arrays, and it is the same as the length for + // those types. + max := int64(-1) + if length >= 0 { + max = length + 1 + } + if t, ok := check.index(expr, max); ok && t >= 0 { + x = t + } + case i == 0: + // default is 0 for the first index + x = 0 + case length >= 0: + // default is length (== capacity) otherwise + x = length + } + ind[i] = x + } + + // constant indices must be in range + // (check.index already checks that existing indices >= 0) + L: + for i, x := range ind[:len(ind)-1] { + if x > 0 { + for _, y := range ind[i+1:] { + if y >= 0 && x > y { + check.errorf(e.Rbrack, "invalid slice indices: %d > %d", x, y) + break L // only report one error, ok to continue + } + } + } + } + + case *ast.TypeAssertExpr: + check.expr(x, e.X) + if x.mode == invalid { + goto Error + } + xtyp, _ := x.typ.Underlying().(*Interface) + if xtyp == nil { + check.invalidOp(x.pos(), "%s is not an interface", x) + goto Error + } + // x.(type) expressions are handled explicitly in type switches + if e.Type == nil { + check.invalidAST(e.Pos(), "use of .(type) outside type switch") + goto Error + } + T := check.typ(e.Type) + if T == Typ[Invalid] { + goto Error + } + check.typeAssertion(x.pos(), x, xtyp, T) + x.mode = commaok + x.typ = T + + case *ast.CallExpr: + return check.call(x, e) + + case *ast.StarExpr: + check.exprOrType(x, e.X) + switch x.mode { + case invalid: + goto Error + case typexpr: + x.typ = &Pointer{base: x.typ} + default: + if typ, ok := x.typ.Underlying().(*Pointer); ok { + x.mode = variable + x.typ = typ.base + } else { + check.invalidOp(x.pos(), "cannot indirect %s", x) + goto Error + } + } + + case *ast.UnaryExpr: + check.expr(x, e.X) + if x.mode == invalid { + goto Error + } + check.unary(x, e, e.Op) + if x.mode == invalid { + goto Error + } + if e.Op == token.ARROW { + x.expr = e + return statement // receive operations may appear in statement context + } + + case *ast.BinaryExpr: + check.binary(x, e, e.X, e.Y, e.Op) + if x.mode == invalid { + goto Error + } + + case *ast.KeyValueExpr: + // key:value expressions are handled in composite literals + check.invalidAST(e.Pos(), "no key:value expected") + goto Error + + case *ast.ArrayType, *ast.StructType, *ast.FuncType, + *ast.InterfaceType, *ast.MapType, *ast.ChanType: + x.mode = typexpr + x.typ = check.typ(e) + // Note: rawExpr (caller of exprInternal) will call check.recordTypeAndValue + // even though check.typ has already called it. This is fine as both + // times the same expression and type are recorded. It is also not a + // performance issue because we only reach here for composite literal + // types, which are comparatively rare. + + default: + panic(fmt.Sprintf("%s: unknown expression type %T", check.fset.Position(e.Pos()), e)) + } + + // everything went well + x.expr = e + return expression + +Error: + x.mode = invalid + x.expr = e + return statement // avoid follow-up errors +} + +// typeAssertion checks that x.(T) is legal; xtyp must be the type of x. +func (check *Checker) typeAssertion(pos token.Pos, x *operand, xtyp *Interface, T Type) { + method, wrongType := assertableTo(xtyp, T) + if method == nil { + return + } + + var msg string + if wrongType { + msg = "wrong type for method" + } else { + msg = "missing method" + } + check.errorf(pos, "%s cannot have dynamic type %s (%s %s)", x, T, msg, method.name) +} + +// expr typechecks expression e and initializes x with the expression value. +// If an error occurred, x.mode is set to invalid. +// +func (check *Checker) expr(x *operand, e ast.Expr) { + check.rawExpr(x, e, nil) + var msg string + switch x.mode { + default: + return + case novalue: + msg = "used as value" + case builtin: + msg = "must be called" + case typexpr: + msg = "is not an expression" + } + check.errorf(x.pos(), "%s %s", x, msg) + x.mode = invalid +} + +// exprWithHint typechecks expression e and initializes x with the expression value. +// If an error occurred, x.mode is set to invalid. +// If hint != nil, it is the type of a composite literal element. +// +func (check *Checker) exprWithHint(x *operand, e ast.Expr, hint Type) { + assert(hint != nil) + check.rawExpr(x, e, hint) + var msg string + switch x.mode { + default: + return + case novalue: + msg = "used as value" + case builtin: + msg = "must be called" + case typexpr: + msg = "is not an expression" + } + check.errorf(x.pos(), "%s %s", x, msg) + x.mode = invalid +} + +// exprOrType typechecks expression or type e and initializes x with the expression value or type. +// If an error occurred, x.mode is set to invalid. +// +func (check *Checker) exprOrType(x *operand, e ast.Expr) { + check.rawExpr(x, e, nil) + if x.mode == novalue { + check.errorf(x.pos(), "%s used as value or type", x) + x.mode = invalid + } +} diff --git a/libgo/go/go/types/exprstring.go b/libgo/go/go/types/exprstring.go new file mode 100644 index 00000000000..370bdf35324 --- /dev/null +++ b/libgo/go/go/types/exprstring.go @@ -0,0 +1,220 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file implements printing of expressions. + +package types + +import ( + "bytes" + "go/ast" +) + +// ExprString returns the (possibly simplified) string representation for x. +func ExprString(x ast.Expr) string { + var buf bytes.Buffer + WriteExpr(&buf, x) + return buf.String() +} + +// WriteExpr writes the (possibly simplified) string representation for x to buf. +func WriteExpr(buf *bytes.Buffer, x ast.Expr) { + // The AST preserves source-level parentheses so there is + // no need to introduce them here to correct for different + // operator precedences. (This assumes that the AST was + // generated by a Go parser.) + + switch x := x.(type) { + default: + buf.WriteString("(bad expr)") // nil, ast.BadExpr, ast.KeyValueExpr + + case *ast.Ident: + buf.WriteString(x.Name) + + case *ast.Ellipsis: + buf.WriteString("...") + if x.Elt != nil { + WriteExpr(buf, x.Elt) + } + + case *ast.BasicLit: + buf.WriteString(x.Value) + + case *ast.FuncLit: + buf.WriteByte('(') + WriteExpr(buf, x.Type) + buf.WriteString(" literal)") // simplified + + case *ast.CompositeLit: + buf.WriteByte('(') + WriteExpr(buf, x.Type) + buf.WriteString(" literal)") // simplified + + case *ast.ParenExpr: + buf.WriteByte('(') + WriteExpr(buf, x.X) + buf.WriteByte(')') + + case *ast.SelectorExpr: + WriteExpr(buf, x.X) + buf.WriteByte('.') + buf.WriteString(x.Sel.Name) + + case *ast.IndexExpr: + WriteExpr(buf, x.X) + buf.WriteByte('[') + WriteExpr(buf, x.Index) + buf.WriteByte(']') + + case *ast.SliceExpr: + WriteExpr(buf, x.X) + buf.WriteByte('[') + if x.Low != nil { + WriteExpr(buf, x.Low) + } + buf.WriteByte(':') + if x.High != nil { + WriteExpr(buf, x.High) + } + if x.Slice3 { + buf.WriteByte(':') + if x.Max != nil { + WriteExpr(buf, x.Max) + } + } + buf.WriteByte(']') + + case *ast.TypeAssertExpr: + WriteExpr(buf, x.X) + buf.WriteString(".(") + WriteExpr(buf, x.Type) + buf.WriteByte(')') + + case *ast.CallExpr: + WriteExpr(buf, x.Fun) + buf.WriteByte('(') + for i, arg := range x.Args { + if i > 0 { + buf.WriteString(", ") + } + WriteExpr(buf, arg) + } + if x.Ellipsis.IsValid() { + buf.WriteString("...") + } + buf.WriteByte(')') + + case *ast.StarExpr: + buf.WriteByte('*') + WriteExpr(buf, x.X) + + case *ast.UnaryExpr: + buf.WriteString(x.Op.String()) + WriteExpr(buf, x.X) + + case *ast.BinaryExpr: + WriteExpr(buf, x.X) + buf.WriteByte(' ') + buf.WriteString(x.Op.String()) + buf.WriteByte(' ') + WriteExpr(buf, x.Y) + + case *ast.ArrayType: + buf.WriteByte('[') + if x.Len != nil { + WriteExpr(buf, x.Len) + } + buf.WriteByte(']') + WriteExpr(buf, x.Elt) + + case *ast.StructType: + buf.WriteString("struct{") + writeFieldList(buf, x.Fields, "; ", false) + buf.WriteByte('}') + + case *ast.FuncType: + buf.WriteString("func") + writeSigExpr(buf, x) + + case *ast.InterfaceType: + buf.WriteString("interface{") + writeFieldList(buf, x.Methods, "; ", true) + buf.WriteByte('}') + + case *ast.MapType: + buf.WriteString("map[") + WriteExpr(buf, x.Key) + buf.WriteByte(']') + WriteExpr(buf, x.Value) + + case *ast.ChanType: + var s string + switch x.Dir { + case ast.SEND: + s = "chan<- " + case ast.RECV: + s = "<-chan " + default: + s = "chan " + } + buf.WriteString(s) + WriteExpr(buf, x.Value) + } +} + +func writeSigExpr(buf *bytes.Buffer, sig *ast.FuncType) { + buf.WriteByte('(') + writeFieldList(buf, sig.Params, ", ", false) + buf.WriteByte(')') + + res := sig.Results + n := res.NumFields() + if n == 0 { + // no result + return + } + + buf.WriteByte(' ') + if n == 1 && len(res.List[0].Names) == 0 { + // single unnamed result + WriteExpr(buf, res.List[0].Type) + return + } + + // multiple or named result(s) + buf.WriteByte('(') + writeFieldList(buf, res, ", ", false) + buf.WriteByte(')') +} + +func writeFieldList(buf *bytes.Buffer, fields *ast.FieldList, sep string, iface bool) { + for i, f := range fields.List { + if i > 0 { + buf.WriteString(sep) + } + + // field list names + for i, name := range f.Names { + if i > 0 { + buf.WriteString(", ") + } + buf.WriteString(name.Name) + } + + // types of interface methods consist of signatures only + if sig, _ := f.Type.(*ast.FuncType); sig != nil && iface { + writeSigExpr(buf, sig) + continue + } + + // named fields are separated with a blank from the field type + if len(f.Names) > 0 { + buf.WriteByte(' ') + } + + WriteExpr(buf, f.Type) + + // ignore tag + } +} diff --git a/libgo/go/go/types/exprstring_test.go b/libgo/go/go/types/exprstring_test.go new file mode 100644 index 00000000000..51102881c9f --- /dev/null +++ b/libgo/go/go/types/exprstring_test.go @@ -0,0 +1,94 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package types_test + +import ( + "go/parser" + "testing" + + . "go/types" +) + +var testExprs = []testEntry{ + // basic type literals + dup("x"), + dup("true"), + dup("42"), + dup("3.1415"), + dup("2.71828i"), + dup(`'a'`), + dup(`"foo"`), + dup("`bar`"), + + // func and composite literals + {"func(){}", "(func() literal)"}, + {"func(x int) complex128 {}", "(func(x int) complex128 literal)"}, + {"[]int{1, 2, 3}", "([]int literal)"}, + + // non-type expressions + dup("(x)"), + dup("x.f"), + dup("a[i]"), + + dup("s[:]"), + dup("s[i:]"), + dup("s[:j]"), + dup("s[i:j]"), + dup("s[:j:k]"), + dup("s[i:j:k]"), + + dup("x.(T)"), + + dup("x.([10]int)"), + dup("x.([...]int)"), + + dup("x.(struct{})"), + dup("x.(struct{x int; y, z float32; E})"), + + dup("x.(func())"), + dup("x.(func(x int))"), + dup("x.(func() int)"), + dup("x.(func(x, y int, z float32) (r int))"), + dup("x.(func(a, b, c int))"), + dup("x.(func(x ...T))"), + + dup("x.(interface{})"), + dup("x.(interface{m(); n(x int); E})"), + dup("x.(interface{m(); n(x int) T; E; F})"), + + dup("x.(map[K]V)"), + + dup("x.(chan E)"), + dup("x.(<-chan E)"), + dup("x.(chan<- chan int)"), + dup("x.(chan<- <-chan int)"), + dup("x.(<-chan chan int)"), + dup("x.(chan (<-chan int))"), + + dup("f()"), + dup("f(x)"), + dup("int(x)"), + dup("f(x, x + y)"), + dup("f(s...)"), + dup("f(a, s...)"), + + dup("*x"), + dup("&x"), + dup("x + y"), + dup("x + y << (2 * s)"), +} + +func TestExprString(t *testing.T) { + for _, test := range testExprs { + x, err := parser.ParseExpr(test.src) + if err != nil { + t.Errorf("%s: %s", test.src, err) + continue + } + if got := ExprString(x); got != test.str { + t.Errorf("%s: got %s, want %s", test.src, got, test.str) + } + } +} diff --git a/libgo/go/go/types/go11.go b/libgo/go/go/types/go11.go new file mode 100644 index 00000000000..cf41cabeeac --- /dev/null +++ b/libgo/go/go/types/go11.go @@ -0,0 +1,17 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !go1.2 + +package types + +import "go/ast" + +func slice3(x *ast.SliceExpr) bool { + return false +} + +func sliceMax(x *ast.SliceExpr) ast.Expr { + return nil +} diff --git a/libgo/go/go/types/go12.go b/libgo/go/go/types/go12.go new file mode 100644 index 00000000000..20174421540 --- /dev/null +++ b/libgo/go/go/types/go12.go @@ -0,0 +1,17 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build go1.2 + +package types + +import "go/ast" + +func slice3(x *ast.SliceExpr) bool { + return x.Slice3 +} + +func sliceMax(x *ast.SliceExpr) ast.Expr { + return x.Max +} diff --git a/libgo/go/go/types/hilbert_test.go b/libgo/go/go/types/hilbert_test.go new file mode 100644 index 00000000000..cfd51b1d649 --- /dev/null +++ b/libgo/go/go/types/hilbert_test.go @@ -0,0 +1,234 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package types_test + +import ( + "bytes" + "flag" + "fmt" + "go/ast" + "go/importer" + "go/parser" + "go/token" + "io/ioutil" + "testing" + + . "go/types" +) + +var ( + H = flag.Int("H", 5, "Hilbert matrix size") + out = flag.String("out", "", "write generated program to out") +) + +func TestHilbert(t *testing.T) { + // generate source + src := program(*H, *out) + if *out != "" { + ioutil.WriteFile(*out, src, 0666) + return + } + + // parse source + fset := token.NewFileSet() + f, err := parser.ParseFile(fset, "hilbert.go", src, 0) + if err != nil { + t.Fatal(err) + } + + // type-check file + DefPredeclaredTestFuncs() // define assert built-in + conf := Config{Importer: importer.Default()} + _, err = conf.Check(f.Name.Name, fset, []*ast.File{f}, nil) + if err != nil { + t.Fatal(err) + } +} + +func program(n int, out string) []byte { + var g gen + + g.p(`// WARNING: GENERATED FILE - DO NOT MODIFY MANUALLY! +// (To generate, in go/types directory: go test -run=Hilbert -H=%d -out=%q) + +// This program tests arbitrary precision constant arithmetic +// by generating the constant elements of a Hilbert matrix H, +// its inverse I, and the product P = H*I. The product should +// be the identity matrix. +package main + +func main() { + if !ok { + printProduct() + return + } + println("PASS") +} + +`, n, out) + g.hilbert(n) + g.inverse(n) + g.product(n) + g.verify(n) + g.printProduct(n) + g.binomials(2*n - 1) + g.factorials(2*n - 1) + + return g.Bytes() +} + +type gen struct { + bytes.Buffer +} + +func (g *gen) p(format string, args ...interface{}) { + fmt.Fprintf(&g.Buffer, format, args...) +} + +func (g *gen) hilbert(n int) { + g.p(`// Hilbert matrix, n = %d +const ( +`, n) + for i := 0; i < n; i++ { + g.p("\t") + for j := 0; j < n; j++ { + if j > 0 { + g.p(", ") + } + g.p("h%d_%d", i, j) + } + if i == 0 { + g.p(" = ") + for j := 0; j < n; j++ { + if j > 0 { + g.p(", ") + } + g.p("1.0/(iota + %d)", j+1) + } + } + g.p("\n") + } + g.p(")\n\n") +} + +func (g *gen) inverse(n int) { + g.p(`// Inverse Hilbert matrix +const ( +`) + for i := 0; i < n; i++ { + for j := 0; j < n; j++ { + s := "+" + if (i+j)&1 != 0 { + s = "-" + } + g.p("\ti%d_%d = %s%d * b%d_%d * b%d_%d * b%d_%d * b%d_%d\n", + i, j, s, i+j+1, n+i, n-j-1, n+j, n-i-1, i+j, i, i+j, i) + } + g.p("\n") + } + g.p(")\n\n") +} + +func (g *gen) product(n int) { + g.p(`// Product matrix +const ( +`) + for i := 0; i < n; i++ { + for j := 0; j < n; j++ { + g.p("\tp%d_%d = ", i, j) + for k := 0; k < n; k++ { + if k > 0 { + g.p(" + ") + } + g.p("h%d_%d*i%d_%d", i, k, k, j) + } + g.p("\n") + } + g.p("\n") + } + g.p(")\n\n") +} + +func (g *gen) verify(n int) { + g.p(`// Verify that product is the identity matrix +const ok = +`) + for i := 0; i < n; i++ { + for j := 0; j < n; j++ { + if j == 0 { + g.p("\t") + } else { + g.p(" && ") + } + v := 0 + if i == j { + v = 1 + } + g.p("p%d_%d == %d", i, j, v) + } + g.p(" &&\n") + } + g.p("\ttrue\n\n") + + // verify ok at type-check time + if *out == "" { + g.p("const _ = assert(ok)\n\n") + } +} + +func (g *gen) printProduct(n int) { + g.p("func printProduct() {\n") + for i := 0; i < n; i++ { + g.p("\tprintln(") + for j := 0; j < n; j++ { + if j > 0 { + g.p(", ") + } + g.p("p%d_%d", i, j) + } + g.p(")\n") + } + g.p("}\n\n") +} + +func (g *gen) mulRange(a, b int) { + if a > b { + g.p("1") + return + } + for i := a; i <= b; i++ { + if i > a { + g.p("*") + } + g.p("%d", i) + } +} + +func (g *gen) binomials(n int) { + g.p(`// Binomials +const ( +`) + for j := 0; j <= n; j++ { + if j > 0 { + g.p("\n") + } + for k := 0; k <= j; k++ { + g.p("\tb%d_%d = f%d / (f%d*f%d)\n", j, k, j, k, j-k) + } + } + g.p(")\n\n") +} + +func (g *gen) factorials(n int) { + g.p(`// Factorials +const ( + f0 = 1 + f1 = 1 +`) + for i := 2; i <= n; i++ { + g.p("\tf%d = f%d * %d\n", i, i-1, i) + } + g.p(")\n\n") +} diff --git a/libgo/go/go/types/initorder.go b/libgo/go/go/types/initorder.go new file mode 100644 index 00000000000..0fd567b2691 --- /dev/null +++ b/libgo/go/go/types/initorder.go @@ -0,0 +1,222 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package types + +import ( + "container/heap" + "fmt" +) + +// initOrder computes the Info.InitOrder for package variables. +func (check *Checker) initOrder() { + // An InitOrder may already have been computed if a package is + // built from several calls to (*Checker).Files. Clear it. + check.Info.InitOrder = check.Info.InitOrder[:0] + + // compute the object dependency graph and + // initialize a priority queue with the list + // of graph nodes + pq := nodeQueue(dependencyGraph(check.objMap)) + heap.Init(&pq) + + const debug = false + if debug { + fmt.Printf("package %s: object dependency graph\n", check.pkg.Name()) + for _, n := range pq { + for _, o := range n.out { + fmt.Printf("\t%s -> %s\n", n.obj.Name(), o.obj.Name()) + } + } + fmt.Println() + fmt.Printf("package %s: initialization order\n", check.pkg.Name()) + } + + // determine initialization order by removing the highest priority node + // (the one with the fewest dependencies) and its edges from the graph, + // repeatedly, until there are no nodes left. + // In a valid Go program, those nodes always have zero dependencies (after + // removing all incoming dependencies), otherwise there are initialization + // cycles. + mark := 0 + emitted := make(map[*declInfo]bool) + for len(pq) > 0 { + // get the next node + n := heap.Pop(&pq).(*objNode) + + // if n still depends on other nodes, we have a cycle + if n.in > 0 { + mark++ // mark nodes using a different value each time + cycle := findPath(n, n, mark) + if i := valIndex(cycle); i >= 0 { + check.reportCycle(cycle, i) + } + // ok to continue, but the variable initialization order + // will be incorrect at this point since it assumes no + // cycle errors + } + + // reduce dependency count of all dependent nodes + // and update priority queue + for _, out := range n.out { + out.in-- + heap.Fix(&pq, out.index) + } + + // record the init order for variables with initializers only + v, _ := n.obj.(*Var) + info := check.objMap[v] + if v == nil || !info.hasInitializer() { + continue + } + + // n:1 variable declarations such as: a, b = f() + // introduce a node for each lhs variable (here: a, b); + // but they all have the same initializer - emit only + // one, for the first variable seen + if emitted[info] { + continue // initializer already emitted, if any + } + emitted[info] = true + + infoLhs := info.lhs // possibly nil (see declInfo.lhs field comment) + if infoLhs == nil { + infoLhs = []*Var{v} + } + init := &Initializer{infoLhs, info.init} + check.Info.InitOrder = append(check.Info.InitOrder, init) + + if debug { + fmt.Printf("\t%s\n", init) + } + } + + if debug { + fmt.Println() + } +} + +// findPath returns the (reversed) list of nodes z, ... c, b, a, +// such that there is a path (list of edges) from a to z. +// If there is no such path, the result is nil. +// Nodes marked with the value mark are considered "visited"; +// unvisited nodes are marked during the graph search. +func findPath(a, z *objNode, mark int) []*objNode { + if a.mark == mark { + return nil // node already seen + } + a.mark = mark + + for _, n := range a.out { + if n == z { + return []*objNode{z} + } + if P := findPath(n, z, mark); P != nil { + return append(P, n) + } + } + + return nil +} + +// valIndex returns the index of the first constant or variable in a, +// if any; or a value < 0. +func valIndex(a []*objNode) int { + for i, n := range a { + switch n.obj.(type) { + case *Const, *Var: + return i + } + } + return -1 +} + +// reportCycle reports an error for the cycle starting at i. +func (check *Checker) reportCycle(cycle []*objNode, i int) { + obj := cycle[i].obj + check.errorf(obj.Pos(), "initialization cycle for %s", obj.Name()) + // print cycle + for _ = range cycle { + check.errorf(obj.Pos(), "\t%s refers to", obj.Name()) // secondary error, \t indented + i++ + if i >= len(cycle) { + i = 0 + } + obj = cycle[i].obj + } + check.errorf(obj.Pos(), "\t%s", obj.Name()) +} + +// An objNode represents a node in the object dependency graph. +// Each node b in a.out represents an edge a->b indicating that +// b depends on a. +// Nodes may be marked for cycle detection. A node n is marked +// if n.mark corresponds to the current mark value. +type objNode struct { + obj Object // object represented by this node + in int // number of nodes this node depends on + out []*objNode // list of nodes that depend on this node + index int // node index in list of nodes + mark int // for cycle detection +} + +// dependencyGraph computes the transposed object dependency graph +// from the given objMap. The transposed graph is returned as a list +// of nodes; an edge d->n indicates that node n depends on node d. +func dependencyGraph(objMap map[Object]*declInfo) []*objNode { + // M maps each object to its corresponding node + M := make(map[Object]*objNode, len(objMap)) + for obj := range objMap { + M[obj] = &objNode{obj: obj} + } + + // G is the graph of nodes n + G := make([]*objNode, len(M)) + i := 0 + for obj, n := range M { + deps := objMap[obj].deps + n.in = len(deps) + for d := range deps { + d := M[d] // node n depends on node d + d.out = append(d.out, n) // add edge d->n + } + + G[i] = n + n.index = i + i++ + } + + return G +} + +// nodeQueue implements the container/heap interface; +// a nodeQueue may be used as a priority queue. +type nodeQueue []*objNode + +func (a nodeQueue) Len() int { return len(a) } + +func (a nodeQueue) Swap(i, j int) { + x, y := a[i], a[j] + a[i], a[j] = y, x + x.index, y.index = j, i +} + +func (a nodeQueue) Less(i, j int) bool { + x, y := a[i], a[j] + // nodes are prioritized by number of incoming dependencies (1st key) + // and source order (2nd key) + return x.in < y.in || x.in == y.in && x.obj.order() < y.obj.order() +} + +func (a *nodeQueue) Push(x interface{}) { + panic("unreachable") +} + +func (a *nodeQueue) Pop() interface{} { + n := len(*a) + x := (*a)[n-1] + x.index = -1 // for safety + *a = (*a)[:n-1] + return x +} diff --git a/libgo/go/go/types/issues_test.go b/libgo/go/go/types/issues_test.go new file mode 100644 index 00000000000..672c78dfc20 --- /dev/null +++ b/libgo/go/go/types/issues_test.go @@ -0,0 +1,206 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file implements tests for various issues. + +package types_test + +import ( + "fmt" + "go/ast" + "go/importer" + "go/parser" + "sort" + "strings" + "testing" + + . "go/types" +) + +func TestIssue5770(t *testing.T) { + src := `package p; type S struct{T}` + f, err := parser.ParseFile(fset, "", src, 0) + if err != nil { + t.Fatal(err) + } + + conf := Config{Importer: importer.Default()} + _, err = conf.Check(f.Name.Name, fset, []*ast.File{f}, nil) // do not crash + want := "undeclared name: T" + if err == nil || !strings.Contains(err.Error(), want) { + t.Errorf("got: %v; want: %s", err, want) + } +} + +func TestIssue5849(t *testing.T) { + src := ` +package p +var ( + s uint + _ = uint8(8) + _ = uint16(16) << s + _ = uint32(32 << s) + _ = uint64(64 << s + s) + _ = (interface{})("foo") + _ = (interface{})(nil) +)` + f, err := parser.ParseFile(fset, "", src, 0) + if err != nil { + t.Fatal(err) + } + + var conf Config + types := make(map[ast.Expr]TypeAndValue) + _, err = conf.Check(f.Name.Name, fset, []*ast.File{f}, &Info{Types: types}) + if err != nil { + t.Fatal(err) + } + + for x, tv := range types { + var want Type + switch x := x.(type) { + case *ast.BasicLit: + switch x.Value { + case `8`: + want = Typ[Uint8] + case `16`: + want = Typ[Uint16] + case `32`: + want = Typ[Uint32] + case `64`: + want = Typ[Uint] // because of "+ s", s is of type uint + case `"foo"`: + want = Typ[String] + } + case *ast.Ident: + if x.Name == "nil" { + want = Typ[UntypedNil] + } + } + if want != nil && !Identical(tv.Type, want) { + t.Errorf("got %s; want %s", tv.Type, want) + } + } +} + +func TestIssue6413(t *testing.T) { + src := ` +package p +func f() int { + defer f() + go f() + return 0 +} +` + f, err := parser.ParseFile(fset, "", src, 0) + if err != nil { + t.Fatal(err) + } + + var conf Config + types := make(map[ast.Expr]TypeAndValue) + _, err = conf.Check(f.Name.Name, fset, []*ast.File{f}, &Info{Types: types}) + if err != nil { + t.Fatal(err) + } + + want := Typ[Int] + n := 0 + for x, tv := range types { + if _, ok := x.(*ast.CallExpr); ok { + if tv.Type != want { + t.Errorf("%s: got %s; want %s", fset.Position(x.Pos()), tv.Type, want) + } + n++ + } + } + + if n != 2 { + t.Errorf("got %d CallExprs; want 2", n) + } +} + +func TestIssue7245(t *testing.T) { + src := ` +package p +func (T) m() (res bool) { return } +type T struct{} // receiver type after method declaration +` + f, err := parser.ParseFile(fset, "", src, 0) + if err != nil { + t.Fatal(err) + } + + var conf Config + defs := make(map[*ast.Ident]Object) + _, err = conf.Check(f.Name.Name, fset, []*ast.File{f}, &Info{Defs: defs}) + if err != nil { + t.Fatal(err) + } + + m := f.Decls[0].(*ast.FuncDecl) + res1 := defs[m.Name].(*Func).Type().(*Signature).Results().At(0) + res2 := defs[m.Type.Results.List[0].Names[0]].(*Var) + + if res1 != res2 { + t.Errorf("got %s (%p) != %s (%p)", res1, res2, res1, res2) + } +} + +// This tests that uses of existing vars on the LHS of an assignment +// are Uses, not Defs; and also that the (illegal) use of a non-var on +// the LHS of an assignment is a Use nonetheless. +func TestIssue7827(t *testing.T) { + const src = ` +package p +func _() { + const w = 1 // defs w + x, y := 2, 3 // defs x, y + w, x, z := 4, 5, 6 // uses w, x, defs z; error: cannot assign to w + _, _, _ = x, y, z // uses x, y, z +} +` + const want = `L3 defs func p._() +L4 defs const w untyped int +L5 defs var x int +L5 defs var y int +L6 defs var z int +L6 uses const w untyped int +L6 uses var x int +L7 uses var x int +L7 uses var y int +L7 uses var z int` + + f, err := parser.ParseFile(fset, "", src, 0) + if err != nil { + t.Fatal(err) + } + + // don't abort at the first error + conf := Config{Error: func(err error) { t.Log(err) }} + defs := make(map[*ast.Ident]Object) + uses := make(map[*ast.Ident]Object) + _, err = conf.Check(f.Name.Name, fset, []*ast.File{f}, &Info{Defs: defs, Uses: uses}) + if s := fmt.Sprint(err); !strings.HasSuffix(s, "cannot assign to w") { + t.Errorf("Check: unexpected error: %s", s) + } + + var facts []string + for id, obj := range defs { + if obj != nil { + fact := fmt.Sprintf("L%d defs %s", fset.Position(id.Pos()).Line, obj) + facts = append(facts, fact) + } + } + for id, obj := range uses { + fact := fmt.Sprintf("L%d uses %s", fset.Position(id.Pos()).Line, obj) + facts = append(facts, fact) + } + sort.Strings(facts) + + got := strings.Join(facts, "\n") + if got != want { + t.Errorf("Unexpected defs/uses\ngot:\n%s\nwant:\n%s", got, want) + } +} diff --git a/libgo/go/go/types/labels.go b/libgo/go/go/types/labels.go new file mode 100644 index 00000000000..7364d4dbe68 --- /dev/null +++ b/libgo/go/go/types/labels.go @@ -0,0 +1,268 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package types + +import ( + "go/ast" + "go/token" +) + +// labels checks correct label use in body. +func (check *Checker) labels(body *ast.BlockStmt) { + // set of all labels in this body + all := NewScope(nil, body.Pos(), body.End(), "label") + + fwdJumps := check.blockBranches(all, nil, nil, body.List) + + // If there are any forward jumps left, no label was found for + // the corresponding goto statements. Either those labels were + // never defined, or they are inside blocks and not reachable + // for the respective gotos. + for _, jmp := range fwdJumps { + var msg string + name := jmp.Label.Name + if alt := all.Lookup(name); alt != nil { + msg = "goto %s jumps into block" + alt.(*Label).used = true // avoid another error + } else { + msg = "label %s not declared" + } + check.errorf(jmp.Label.Pos(), msg, name) + } + + // spec: "It is illegal to define a label that is never used." + for _, obj := range all.elems { + if lbl := obj.(*Label); !lbl.used { + check.softErrorf(lbl.pos, "label %s declared but not used", lbl.name) + } + } +} + +// A block tracks label declarations in a block and its enclosing blocks. +type block struct { + parent *block // enclosing block + lstmt *ast.LabeledStmt // labeled statement to which this block belongs, or nil + labels map[string]*ast.LabeledStmt // allocated lazily +} + +// insert records a new label declaration for the current block. +// The label must not have been declared before in any block. +func (b *block) insert(s *ast.LabeledStmt) { + name := s.Label.Name + if debug { + assert(b.gotoTarget(name) == nil) + } + labels := b.labels + if labels == nil { + labels = make(map[string]*ast.LabeledStmt) + b.labels = labels + } + labels[name] = s +} + +// gotoTarget returns the labeled statement in the current +// or an enclosing block with the given label name, or nil. +func (b *block) gotoTarget(name string) *ast.LabeledStmt { + for s := b; s != nil; s = s.parent { + if t := s.labels[name]; t != nil { + return t + } + } + return nil +} + +// enclosingTarget returns the innermost enclosing labeled +// statement with the given label name, or nil. +func (b *block) enclosingTarget(name string) *ast.LabeledStmt { + for s := b; s != nil; s = s.parent { + if t := s.lstmt; t != nil && t.Label.Name == name { + return t + } + } + return nil +} + +// blockBranches processes a block's statement list and returns the set of outgoing forward jumps. +// all is the scope of all declared labels, parent the set of labels declared in the immediately +// enclosing block, and lstmt is the labeled statement this block is associated with (or nil). +func (check *Checker) blockBranches(all *Scope, parent *block, lstmt *ast.LabeledStmt, list []ast.Stmt) []*ast.BranchStmt { + b := &block{parent: parent, lstmt: lstmt} + + var ( + varDeclPos token.Pos + fwdJumps, badJumps []*ast.BranchStmt + ) + + // All forward jumps jumping over a variable declaration are possibly + // invalid (they may still jump out of the block and be ok). + // recordVarDecl records them for the given position. + recordVarDecl := func(pos token.Pos) { + varDeclPos = pos + badJumps = append(badJumps[:0], fwdJumps...) // copy fwdJumps to badJumps + } + + jumpsOverVarDecl := func(jmp *ast.BranchStmt) bool { + if varDeclPos.IsValid() { + for _, bad := range badJumps { + if jmp == bad { + return true + } + } + } + return false + } + + blockBranches := func(lstmt *ast.LabeledStmt, list []ast.Stmt) { + // Unresolved forward jumps inside the nested block + // become forward jumps in the current block. + fwdJumps = append(fwdJumps, check.blockBranches(all, b, lstmt, list)...) + } + + var stmtBranches func(ast.Stmt) + stmtBranches = func(s ast.Stmt) { + switch s := s.(type) { + case *ast.DeclStmt: + if d, _ := s.Decl.(*ast.GenDecl); d != nil && d.Tok == token.VAR { + recordVarDecl(d.Pos()) + } + + case *ast.LabeledStmt: + // declare non-blank label + if name := s.Label.Name; name != "_" { + lbl := NewLabel(s.Label.Pos(), check.pkg, name) + if alt := all.Insert(lbl); alt != nil { + check.softErrorf(lbl.pos, "label %s already declared", name) + check.reportAltDecl(alt) + // ok to continue + } else { + b.insert(s) + check.recordDef(s.Label, lbl) + } + // resolve matching forward jumps and remove them from fwdJumps + i := 0 + for _, jmp := range fwdJumps { + if jmp.Label.Name == name { + // match + lbl.used = true + check.recordUse(jmp.Label, lbl) + if jumpsOverVarDecl(jmp) { + check.softErrorf( + jmp.Label.Pos(), + "goto %s jumps over variable declaration at line %d", + name, + check.fset.Position(varDeclPos).Line, + ) + // ok to continue + } + } else { + // no match - record new forward jump + fwdJumps[i] = jmp + i++ + } + } + fwdJumps = fwdJumps[:i] + lstmt = s + } + stmtBranches(s.Stmt) + + case *ast.BranchStmt: + if s.Label == nil { + return // checked in 1st pass (check.stmt) + } + + // determine and validate target + name := s.Label.Name + switch s.Tok { + case token.BREAK: + // spec: "If there is a label, it must be that of an enclosing + // "for", "switch", or "select" statement, and that is the one + // whose execution terminates." + valid := false + if t := b.enclosingTarget(name); t != nil { + switch t.Stmt.(type) { + case *ast.SwitchStmt, *ast.TypeSwitchStmt, *ast.SelectStmt, *ast.ForStmt, *ast.RangeStmt: + valid = true + } + } + if !valid { + check.errorf(s.Label.Pos(), "invalid break label %s", name) + return + } + + case token.CONTINUE: + // spec: "If there is a label, it must be that of an enclosing + // "for" statement, and that is the one whose execution advances." + valid := false + if t := b.enclosingTarget(name); t != nil { + switch t.Stmt.(type) { + case *ast.ForStmt, *ast.RangeStmt: + valid = true + } + } + if !valid { + check.errorf(s.Label.Pos(), "invalid continue label %s", name) + return + } + + case token.GOTO: + if b.gotoTarget(name) == nil { + // label may be declared later - add branch to forward jumps + fwdJumps = append(fwdJumps, s) + return + } + + default: + check.invalidAST(s.Pos(), "branch statement: %s %s", s.Tok, name) + return + } + + // record label use + obj := all.Lookup(name) + obj.(*Label).used = true + check.recordUse(s.Label, obj) + + case *ast.AssignStmt: + if s.Tok == token.DEFINE { + recordVarDecl(s.Pos()) + } + + case *ast.BlockStmt: + blockBranches(lstmt, s.List) + + case *ast.IfStmt: + stmtBranches(s.Body) + if s.Else != nil { + stmtBranches(s.Else) + } + + case *ast.CaseClause: + blockBranches(nil, s.Body) + + case *ast.SwitchStmt: + stmtBranches(s.Body) + + case *ast.TypeSwitchStmt: + stmtBranches(s.Body) + + case *ast.CommClause: + blockBranches(nil, s.Body) + + case *ast.SelectStmt: + stmtBranches(s.Body) + + case *ast.ForStmt: + stmtBranches(s.Body) + + case *ast.RangeStmt: + stmtBranches(s.Body) + } + } + + for _, s := range list { + stmtBranches(s) + } + + return fwdJumps +} diff --git a/libgo/go/go/types/lookup.go b/libgo/go/go/types/lookup.go new file mode 100644 index 00000000000..3caca5519b6 --- /dev/null +++ b/libgo/go/go/types/lookup.go @@ -0,0 +1,341 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file implements various field and method lookup functions. + +package types + +// LookupFieldOrMethod looks up a field or method with given package and name +// in T and returns the corresponding *Var or *Func, an index sequence, and a +// bool indicating if there were any pointer indirections on the path to the +// field or method. If addressable is set, T is the type of an addressable +// variable (only matters for method lookups). +// +// The last index entry is the field or method index in the (possibly embedded) +// type where the entry was found, either: +// +// 1) the list of declared methods of a named type; or +// 2) the list of all methods (method set) of an interface type; or +// 3) the list of fields of a struct type. +// +// The earlier index entries are the indices of the anonymous struct fields +// traversed to get to the found entry, starting at depth 0. +// +// If no entry is found, a nil object is returned. In this case, the returned +// index and indirect values have the following meaning: +// +// - If index != nil, the index sequence points to an ambiguous entry +// (the same name appeared more than once at the same embedding level). +// +// - If indirect is set, a method with a pointer receiver type was found +// but there was no pointer on the path from the actual receiver type to +// the method's formal receiver base type, nor was the receiver addressable. +// +func LookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (obj Object, index []int, indirect bool) { + // Methods cannot be associated to a named pointer type + // (spec: "The type denoted by T is called the receiver base type; + // it must not be a pointer or interface type and it must be declared + // in the same package as the method."). + // Thus, if we have a named pointer type, proceed with the underlying + // pointer type but discard the result if it is a method since we would + // not have found it for T (see also issue 8590). + if t, _ := T.(*Named); t != nil { + if p, _ := t.underlying.(*Pointer); p != nil { + obj, index, indirect = lookupFieldOrMethod(p, false, pkg, name) + if _, ok := obj.(*Func); ok { + return nil, nil, false + } + return + } + } + + return lookupFieldOrMethod(T, addressable, pkg, name) +} + +// TODO(gri) The named type consolidation and seen maps below must be +// indexed by unique keys for a given type. Verify that named +// types always have only one representation (even when imported +// indirectly via different packages.) + +func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (obj Object, index []int, indirect bool) { + // WARNING: The code in this function is extremely subtle - do not modify casually! + // This function and NewMethodSet should be kept in sync. + + if name == "_" { + return // blank fields/methods are never found + } + + typ, isPtr := deref(T) + named, _ := typ.(*Named) + + // *typ where typ is an interface has no methods. + if isPtr { + utyp := typ + if named != nil { + utyp = named.underlying + } + if _, ok := utyp.(*Interface); ok { + return + } + } + + // Start with typ as single entry at shallowest depth. + // If typ is not a named type, insert a nil type instead. + current := []embeddedType{{named, nil, isPtr, false}} + + // named types that we have seen already, allocated lazily + var seen map[*Named]bool + + // search current depth + for len(current) > 0 { + var next []embeddedType // embedded types found at current depth + + // look for (pkg, name) in all types at current depth + for _, e := range current { + // The very first time only, e.typ may be nil. + // In this case, we don't have a named type and + // we simply continue with the underlying type. + if e.typ != nil { + if seen[e.typ] { + // We have seen this type before, at a more shallow depth + // (note that multiples of this type at the current depth + // were consolidated before). The type at that depth shadows + // this same type at the current depth, so we can ignore + // this one. + continue + } + if seen == nil { + seen = make(map[*Named]bool) + } + seen[e.typ] = true + + // look for a matching attached method + if i, m := lookupMethod(e.typ.methods, pkg, name); m != nil { + // potential match + assert(m.typ != nil) + index = concat(e.index, i) + if obj != nil || e.multiples { + return nil, index, false // collision + } + obj = m + indirect = e.indirect + continue // we can't have a matching field or interface method + } + + // continue with underlying type + typ = e.typ.underlying + } + + switch t := typ.(type) { + case *Struct: + // look for a matching field and collect embedded types + for i, f := range t.fields { + if f.sameId(pkg, name) { + assert(f.typ != nil) + index = concat(e.index, i) + if obj != nil || e.multiples { + return nil, index, false // collision + } + obj = f + indirect = e.indirect + continue // we can't have a matching interface method + } + // Collect embedded struct fields for searching the next + // lower depth, but only if we have not seen a match yet + // (if we have a match it is either the desired field or + // we have a name collision on the same depth; in either + // case we don't need to look further). + // Embedded fields are always of the form T or *T where + // T is a named type. If e.typ appeared multiple times at + // this depth, f.typ appears multiple times at the next + // depth. + if obj == nil && f.anonymous { + // Ignore embedded basic types - only user-defined + // named types can have methods or struct fields. + typ, isPtr := deref(f.typ) + if t, _ := typ.(*Named); t != nil { + next = append(next, embeddedType{t, concat(e.index, i), e.indirect || isPtr, e.multiples}) + } + } + } + + case *Interface: + // look for a matching method + // TODO(gri) t.allMethods is sorted - use binary search + if i, m := lookupMethod(t.allMethods, pkg, name); m != nil { + assert(m.typ != nil) + index = concat(e.index, i) + if obj != nil || e.multiples { + return nil, index, false // collision + } + obj = m + indirect = e.indirect + } + } + } + + if obj != nil { + // found a potential match + // spec: "A method call x.m() is valid if the method set of (the type of) x + // contains m and the argument list can be assigned to the parameter + // list of m. If x is addressable and &x's method set contains m, x.m() + // is shorthand for (&x).m()". + if f, _ := obj.(*Func); f != nil && ptrRecv(f) && !indirect && !addressable { + return nil, nil, true // pointer/addressable receiver required + } + return + } + + current = consolidateMultiples(next) + } + + return nil, nil, false // not found +} + +// embeddedType represents an embedded named type +type embeddedType struct { + typ *Named // nil means use the outer typ variable instead + index []int // embedded field indices, starting with index at depth 0 + indirect bool // if set, there was a pointer indirection on the path to this field + multiples bool // if set, typ appears multiple times at this depth +} + +// consolidateMultiples collects multiple list entries with the same type +// into a single entry marked as containing multiples. The result is the +// consolidated list. +func consolidateMultiples(list []embeddedType) []embeddedType { + if len(list) <= 1 { + return list // at most one entry - nothing to do + } + + n := 0 // number of entries w/ unique type + prev := make(map[*Named]int) // index at which type was previously seen + for _, e := range list { + if i, found := prev[e.typ]; found { + list[i].multiples = true + // ignore this entry + } else { + prev[e.typ] = n + list[n] = e + n++ + } + } + return list[:n] +} + +// MissingMethod returns (nil, false) if V implements T, otherwise it +// returns a missing method required by T and whether it is missing or +// just has the wrong type. +// +// For non-interface types V, or if static is set, V implements T if all +// methods of T are present in V. Otherwise (V is an interface and static +// is not set), MissingMethod only checks that methods of T which are also +// present in V have matching types (e.g., for a type assertion x.(T) where +// x is of interface type V). +// +func MissingMethod(V Type, T *Interface, static bool) (method *Func, wrongType bool) { + // fast path for common case + if T.Empty() { + return + } + + // TODO(gri) Consider using method sets here. Might be more efficient. + + if ityp, _ := V.Underlying().(*Interface); ityp != nil { + // TODO(gri) allMethods is sorted - can do this more efficiently + for _, m := range T.allMethods { + _, obj := lookupMethod(ityp.allMethods, m.pkg, m.name) + switch { + case obj == nil: + if static { + return m, false + } + case !Identical(obj.Type(), m.typ): + return m, true + } + } + return + } + + // A concrete type implements T if it implements all methods of T. + for _, m := range T.allMethods { + obj, _, _ := lookupFieldOrMethod(V, false, m.pkg, m.name) + + f, _ := obj.(*Func) + if f == nil { + return m, false + } + + if !Identical(f.typ, m.typ) { + return m, true + } + } + + return +} + +// assertableTo reports whether a value of type V can be asserted to have type T. +// It returns (nil, false) as affirmative answer. Otherwise it returns a missing +// method required by V and whether it is missing or just has the wrong type. +func assertableTo(V *Interface, T Type) (method *Func, wrongType bool) { + // no static check is required if T is an interface + // spec: "If T is an interface type, x.(T) asserts that the + // dynamic type of x implements the interface T." + if _, ok := T.Underlying().(*Interface); ok && !strict { + return + } + return MissingMethod(T, V, false) +} + +// deref dereferences typ if it is a *Pointer and returns its base and true. +// Otherwise it returns (typ, false). +func deref(typ Type) (Type, bool) { + if p, _ := typ.(*Pointer); p != nil { + return p.base, true + } + return typ, false +} + +// derefStructPtr dereferences typ if it is a (named or unnamed) pointer to a +// (named or unnamed) struct and returns its base. Otherwise it returns typ. +func derefStructPtr(typ Type) Type { + if p, _ := typ.Underlying().(*Pointer); p != nil { + if _, ok := p.base.Underlying().(*Struct); ok { + return p.base + } + } + return typ +} + +// concat returns the result of concatenating list and i. +// The result does not share its underlying array with list. +func concat(list []int, i int) []int { + var t []int + t = append(t, list...) + return append(t, i) +} + +// fieldIndex returns the index for the field with matching package and name, or a value < 0. +func fieldIndex(fields []*Var, pkg *Package, name string) int { + if name != "_" { + for i, f := range fields { + if f.sameId(pkg, name) { + return i + } + } + } + return -1 +} + +// lookupMethod returns the index of and method with matching package and name, or (-1, nil). +func lookupMethod(methods []*Func, pkg *Package, name string) (int, *Func) { + if name != "_" { + for i, m := range methods { + if m.sameId(pkg, name) { + return i, m + } + } + } + return -1, nil +} diff --git a/libgo/go/go/types/methodset.go b/libgo/go/go/types/methodset.go new file mode 100644 index 00000000000..b27f2dac34a --- /dev/null +++ b/libgo/go/go/types/methodset.go @@ -0,0 +1,268 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file implements method sets. + +package types + +import ( + "bytes" + "fmt" + "sort" +) + +// A MethodSet is an ordered set of concrete or abstract (interface) methods; +// a method is a MethodVal selection, and they are ordered by ascending m.Obj().Id(). +// The zero value for a MethodSet is a ready-to-use empty method set. +type MethodSet struct { + list []*Selection +} + +func (s *MethodSet) String() string { + if s.Len() == 0 { + return "MethodSet {}" + } + + var buf bytes.Buffer + fmt.Fprintln(&buf, "MethodSet {") + for _, f := range s.list { + fmt.Fprintf(&buf, "\t%s\n", f) + } + fmt.Fprintln(&buf, "}") + return buf.String() +} + +// Len returns the number of methods in s. +func (s *MethodSet) Len() int { return len(s.list) } + +// At returns the i'th method in s for 0 <= i < s.Len(). +func (s *MethodSet) At(i int) *Selection { return s.list[i] } + +// Lookup returns the method with matching package and name, or nil if not found. +func (s *MethodSet) Lookup(pkg *Package, name string) *Selection { + if s.Len() == 0 { + return nil + } + + key := Id(pkg, name) + i := sort.Search(len(s.list), func(i int) bool { + m := s.list[i] + return m.obj.Id() >= key + }) + if i < len(s.list) { + m := s.list[i] + if m.obj.Id() == key { + return m + } + } + return nil +} + +// Shared empty method set. +var emptyMethodSet MethodSet + +// NewMethodSet returns the method set for the given type T. +// It always returns a non-nil method set, even if it is empty. +func NewMethodSet(T Type) *MethodSet { + // WARNING: The code in this function is extremely subtle - do not modify casually! + // This function and lookupFieldOrMethod should be kept in sync. + + // method set up to the current depth, allocated lazily + var base methodSet + + typ, isPtr := deref(T) + named, _ := typ.(*Named) + + // *typ where typ is an interface has no methods. + if isPtr { + utyp := typ + if named != nil { + utyp = named.underlying + } + if _, ok := utyp.(*Interface); ok { + return &emptyMethodSet + } + } + + // Start with typ as single entry at shallowest depth. + // If typ is not a named type, insert a nil type instead. + current := []embeddedType{{named, nil, isPtr, false}} + + // named types that we have seen already, allocated lazily + var seen map[*Named]bool + + // collect methods at current depth + for len(current) > 0 { + var next []embeddedType // embedded types found at current depth + + // field and method sets at current depth, allocated lazily + var fset fieldSet + var mset methodSet + + for _, e := range current { + // The very first time only, e.typ may be nil. + // In this case, we don't have a named type and + // we simply continue with the underlying type. + if e.typ != nil { + if seen[e.typ] { + // We have seen this type before, at a more shallow depth + // (note that multiples of this type at the current depth + // were consolidated before). The type at that depth shadows + // this same type at the current depth, so we can ignore + // this one. + continue + } + if seen == nil { + seen = make(map[*Named]bool) + } + seen[e.typ] = true + + mset = mset.add(e.typ.methods, e.index, e.indirect, e.multiples) + + // continue with underlying type + typ = e.typ.underlying + } + + switch t := typ.(type) { + case *Struct: + for i, f := range t.fields { + fset = fset.add(f, e.multiples) + + // Embedded fields are always of the form T or *T where + // T is a named type. If typ appeared multiple times at + // this depth, f.Type appears multiple times at the next + // depth. + if f.anonymous { + // Ignore embedded basic types - only user-defined + // named types can have methods or struct fields. + typ, isPtr := deref(f.typ) + if t, _ := typ.(*Named); t != nil { + next = append(next, embeddedType{t, concat(e.index, i), e.indirect || isPtr, e.multiples}) + } + } + } + + case *Interface: + mset = mset.add(t.allMethods, e.index, true, e.multiples) + } + } + + // Add methods and collisions at this depth to base if no entries with matching + // names exist already. + for k, m := range mset { + if _, found := base[k]; !found { + // Fields collide with methods of the same name at this depth. + if _, found := fset[k]; found { + m = nil // collision + } + if base == nil { + base = make(methodSet) + } + base[k] = m + } + } + + // Multiple fields with matching names collide at this depth and shadow all + // entries further down; add them as collisions to base if no entries with + // matching names exist already. + for k, f := range fset { + if f == nil { + if _, found := base[k]; !found { + if base == nil { + base = make(methodSet) + } + base[k] = nil // collision + } + } + } + + current = consolidateMultiples(next) + } + + if len(base) == 0 { + return &emptyMethodSet + } + + // collect methods + var list []*Selection + for _, m := range base { + if m != nil { + m.recv = T + list = append(list, m) + } + } + sort.Sort(byUniqueName(list)) + return &MethodSet{list} +} + +// A fieldSet is a set of fields and name collisions. +// A collision indicates that multiple fields with the +// same unique id appeared. +type fieldSet map[string]*Var // a nil entry indicates a name collision + +// Add adds field f to the field set s. +// If multiples is set, f appears multiple times +// and is treated as a collision. +func (s fieldSet) add(f *Var, multiples bool) fieldSet { + if s == nil { + s = make(fieldSet) + } + key := f.Id() + // if f is not in the set, add it + if !multiples { + if _, found := s[key]; !found { + s[key] = f + return s + } + } + s[key] = nil // collision + return s +} + +// A methodSet is a set of methods and name collisions. +// A collision indicates that multiple methods with the +// same unique id appeared. +type methodSet map[string]*Selection // a nil entry indicates a name collision + +// Add adds all functions in list to the method set s. +// If multiples is set, every function in list appears multiple times +// and is treated as a collision. +func (s methodSet) add(list []*Func, index []int, indirect bool, multiples bool) methodSet { + if len(list) == 0 { + return s + } + if s == nil { + s = make(methodSet) + } + for i, f := range list { + key := f.Id() + // if f is not in the set, add it + if !multiples { + // TODO(gri) A found method may not be added because it's not in the method set + // (!indirect && ptrRecv(f)). A 2nd method on the same level may be in the method + // set and may not collide with the first one, thus leading to a false positive. + // Is that possible? Investigate. + if _, found := s[key]; !found && (indirect || !ptrRecv(f)) { + s[key] = &Selection{MethodVal, nil, f, concat(index, i), indirect} + continue + } + } + s[key] = nil // collision + } + return s +} + +// ptrRecv reports whether the receiver is of the form *T. +// The receiver must exist. +func ptrRecv(f *Func) bool { + _, isPtr := deref(f.typ.(*Signature).recv.typ) + return isPtr +} + +// byUniqueName function lists can be sorted by their unique names. +type byUniqueName []*Selection + +func (a byUniqueName) Len() int { return len(a) } +func (a byUniqueName) Less(i, j int) bool { return a[i].obj.Id() < a[j].obj.Id() } +func (a byUniqueName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } diff --git a/libgo/go/go/types/object.go b/libgo/go/go/types/object.go new file mode 100644 index 00000000000..b835c6e53e8 --- /dev/null +++ b/libgo/go/go/types/object.go @@ -0,0 +1,360 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package types + +import ( + "bytes" + "fmt" + "go/ast" + "go/constant" + "go/token" +) + +// TODO(gri) Document factory, accessor methods, and fields. General clean-up. + +// An Object describes a named language entity such as a package, +// constant, type, variable, function (incl. methods), or label. +// All objects implement the Object interface. +// +type Object interface { + Parent() *Scope // scope in which this object is declared + Pos() token.Pos // position of object identifier in declaration + Pkg() *Package // nil for objects in the Universe scope and labels + Name() string // package local object name + Type() Type // object type + Exported() bool // reports whether the name starts with a capital letter + Id() string // object id (see Id below) + + // String returns a human-readable string of the object. + String() string + + // order reflects a package-level object's source order: if object + // a is before object b in the source, then a.order() < b.order(). + // order returns a value > 0 for package-level objects; it returns + // 0 for all other objects (including objects in file scopes). + order() uint32 + + // setOrder sets the order number of the object. It must be > 0. + setOrder(uint32) + + // setParent sets the parent scope of the object. + setParent(*Scope) + + // sameId reports whether obj.Id() and Id(pkg, name) are the same. + sameId(pkg *Package, name string) bool + + // scopePos returns the start position of the scope of this Object + scopePos() token.Pos + + // setScopePos sets the start position of the scope for this Object. + setScopePos(pos token.Pos) +} + +// Id returns name if it is exported, otherwise it +// returns the name qualified with the package path. +func Id(pkg *Package, name string) string { + if ast.IsExported(name) { + return name + } + // unexported names need the package path for differentiation + // (if there's no package, make sure we don't start with '.' + // as that may change the order of methods between a setup + // inside a package and outside a package - which breaks some + // tests) + path := "_" + // TODO(gri): shouldn't !ast.IsExported(name) => pkg != nil be an precondition? + // if pkg == nil { + // panic("nil package in lookup of unexported name") + // } + if pkg != nil { + path = pkg.path + if path == "" { + path = "_" + } + } + return path + "." + name +} + +// An object implements the common parts of an Object. +type object struct { + parent *Scope + pos token.Pos + pkg *Package + name string + typ Type + order_ uint32 + scopePos_ token.Pos +} + +func (obj *object) Parent() *Scope { return obj.parent } +func (obj *object) Pos() token.Pos { return obj.pos } +func (obj *object) Pkg() *Package { return obj.pkg } +func (obj *object) Name() string { return obj.name } +func (obj *object) Type() Type { return obj.typ } +func (obj *object) Exported() bool { return ast.IsExported(obj.name) } +func (obj *object) Id() string { return Id(obj.pkg, obj.name) } +func (obj *object) String() string { panic("abstract") } +func (obj *object) order() uint32 { return obj.order_ } +func (obj *object) scopePos() token.Pos { return obj.scopePos_ } + +func (obj *object) setParent(parent *Scope) { obj.parent = parent } +func (obj *object) setOrder(order uint32) { assert(order > 0); obj.order_ = order } +func (obj *object) setScopePos(pos token.Pos) { obj.scopePos_ = pos } + +func (obj *object) sameId(pkg *Package, name string) bool { + // spec: + // "Two identifiers are different if they are spelled differently, + // or if they appear in different packages and are not exported. + // Otherwise, they are the same." + if name != obj.name { + return false + } + // obj.Name == name + if obj.Exported() { + return true + } + // not exported, so packages must be the same (pkg == nil for + // fields in Universe scope; this can only happen for types + // introduced via Eval) + if pkg == nil || obj.pkg == nil { + return pkg == obj.pkg + } + // pkg != nil && obj.pkg != nil + return pkg.path == obj.pkg.path +} + +// A PkgName represents an imported Go package. +type PkgName struct { + object + imported *Package + used bool // set if the package was used +} + +func NewPkgName(pos token.Pos, pkg *Package, name string, imported *Package) *PkgName { + return &PkgName{object{nil, pos, pkg, name, Typ[Invalid], 0, token.NoPos}, imported, false} +} + +// Imported returns the package that was imported. +// It is distinct from Pkg(), which is the package containing the import statement. +func (obj *PkgName) Imported() *Package { return obj.imported } + +// A Const represents a declared constant. +type Const struct { + object + val constant.Value + visited bool // for initialization cycle detection +} + +func NewConst(pos token.Pos, pkg *Package, name string, typ Type, val constant.Value) *Const { + return &Const{object{nil, pos, pkg, name, typ, 0, token.NoPos}, val, false} +} + +func (obj *Const) Val() constant.Value { return obj.val } + +// A TypeName represents a declared type. +type TypeName struct { + object +} + +func NewTypeName(pos token.Pos, pkg *Package, name string, typ Type) *TypeName { + return &TypeName{object{nil, pos, pkg, name, typ, 0, token.NoPos}} +} + +// A Variable represents a declared variable (including function parameters and results, and struct fields). +type Var struct { + object + anonymous bool // if set, the variable is an anonymous struct field, and name is the type name + visited bool // for initialization cycle detection + isField bool // var is struct field + used bool // set if the variable was used +} + +func NewVar(pos token.Pos, pkg *Package, name string, typ Type) *Var { + return &Var{object: object{nil, pos, pkg, name, typ, 0, token.NoPos}} +} + +func NewParam(pos token.Pos, pkg *Package, name string, typ Type) *Var { + return &Var{object: object{nil, pos, pkg, name, typ, 0, token.NoPos}, used: true} // parameters are always 'used' +} + +func NewField(pos token.Pos, pkg *Package, name string, typ Type, anonymous bool) *Var { + return &Var{object: object{nil, pos, pkg, name, typ, 0, token.NoPos}, anonymous: anonymous, isField: true} +} + +func (obj *Var) Anonymous() bool { return obj.anonymous } + +func (obj *Var) IsField() bool { return obj.isField } + +// A Func represents a declared function, concrete method, or abstract +// (interface) method. Its Type() is always a *Signature. +// An abstract method may belong to many interfaces due to embedding. +type Func struct { + object +} + +func NewFunc(pos token.Pos, pkg *Package, name string, sig *Signature) *Func { + // don't store a nil signature + var typ Type + if sig != nil { + typ = sig + } + return &Func{object{nil, pos, pkg, name, typ, 0, token.NoPos}} +} + +// FullName returns the package- or receiver-type-qualified name of +// function or method obj. +func (obj *Func) FullName() string { + var buf bytes.Buffer + writeFuncName(&buf, obj, nil) + return buf.String() +} + +func (obj *Func) Scope() *Scope { + return obj.typ.(*Signature).scope +} + +// A Label represents a declared label. +type Label struct { + object + used bool // set if the label was used +} + +func NewLabel(pos token.Pos, pkg *Package, name string) *Label { + return &Label{object{pos: pos, pkg: pkg, name: name, typ: Typ[Invalid]}, false} +} + +// A Builtin represents a built-in function. +// Builtins don't have a valid type. +type Builtin struct { + object + id builtinId +} + +func newBuiltin(id builtinId) *Builtin { + return &Builtin{object{name: predeclaredFuncs[id].name, typ: Typ[Invalid]}, id} +} + +// Nil represents the predeclared value nil. +type Nil struct { + object +} + +func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) { + typ := obj.Type() + switch obj := obj.(type) { + case *PkgName: + fmt.Fprintf(buf, "package %s", obj.Name()) + if path := obj.imported.path; path != "" && path != obj.name { + fmt.Fprintf(buf, " (%q)", path) + } + return + + case *Const: + buf.WriteString("const") + + case *TypeName: + buf.WriteString("type") + typ = typ.Underlying() + + case *Var: + if obj.isField { + buf.WriteString("field") + } else { + buf.WriteString("var") + } + + case *Func: + buf.WriteString("func ") + writeFuncName(buf, obj, qf) + if typ != nil { + WriteSignature(buf, typ.(*Signature), qf) + } + return + + case *Label: + buf.WriteString("label") + typ = nil + + case *Builtin: + buf.WriteString("builtin") + typ = nil + + case *Nil: + buf.WriteString("nil") + return + + default: + panic(fmt.Sprintf("writeObject(%T)", obj)) + } + + buf.WriteByte(' ') + + // For package-level objects, qualify the name. + if obj.Pkg() != nil && obj.Pkg().scope.Lookup(obj.Name()) == obj { + writePackage(buf, obj.Pkg(), qf) + } + buf.WriteString(obj.Name()) + if typ != nil { + buf.WriteByte(' ') + WriteType(buf, typ, qf) + } +} + +func writePackage(buf *bytes.Buffer, pkg *Package, qf Qualifier) { + if pkg == nil { + return + } + var s string + if qf != nil { + s = qf(pkg) + } else { + s = pkg.Path() + } + if s != "" { + buf.WriteString(s) + buf.WriteByte('.') + } +} + +// ObjectString returns the string form of obj. +// The Qualifier controls the printing of +// package-level objects, and may be nil. +func ObjectString(obj Object, qf Qualifier) string { + var buf bytes.Buffer + writeObject(&buf, obj, qf) + return buf.String() +} + +func (obj *PkgName) String() string { return ObjectString(obj, nil) } +func (obj *Const) String() string { return ObjectString(obj, nil) } +func (obj *TypeName) String() string { return ObjectString(obj, nil) } +func (obj *Var) String() string { return ObjectString(obj, nil) } +func (obj *Func) String() string { return ObjectString(obj, nil) } +func (obj *Label) String() string { return ObjectString(obj, nil) } +func (obj *Builtin) String() string { return ObjectString(obj, nil) } +func (obj *Nil) String() string { return ObjectString(obj, nil) } + +func writeFuncName(buf *bytes.Buffer, f *Func, qf Qualifier) { + if f.typ != nil { + sig := f.typ.(*Signature) + if recv := sig.Recv(); recv != nil { + buf.WriteByte('(') + if _, ok := recv.Type().(*Interface); ok { + // gcimporter creates abstract methods of + // named interfaces using the interface type + // (not the named type) as the receiver. + // Don't print it in full. + buf.WriteString("interface") + } else { + WriteType(buf, recv.Type(), qf) + } + buf.WriteByte(')') + buf.WriteByte('.') + } else if f.pkg != nil { + writePackage(buf, f.pkg, qf) + } + } + buf.WriteString(f.name) +} diff --git a/libgo/go/go/types/objset.go b/libgo/go/go/types/objset.go new file mode 100644 index 00000000000..55eb74addba --- /dev/null +++ b/libgo/go/go/types/objset.go @@ -0,0 +1,31 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file implements objsets. +// +// An objset is similar to a Scope but objset elements +// are identified by their unique id, instead of their +// object name. + +package types + +// An objset is a set of objects identified by their unique id. +// The zero value for objset is a ready-to-use empty objset. +type objset map[string]Object // initialized lazily + +// insert attempts to insert an object obj into objset s. +// If s already contains an alternative object alt with +// the same name, insert leaves s unchanged and returns alt. +// Otherwise it inserts obj and returns nil. +func (s *objset) insert(obj Object) Object { + id := obj.Id() + if alt := (*s)[id]; alt != nil { + return alt + } + if *s == nil { + *s = make(map[string]Object) + } + (*s)[id] = obj + return nil +} diff --git a/libgo/go/go/types/operand.go b/libgo/go/go/types/operand.go new file mode 100644 index 00000000000..d3bab51b04a --- /dev/null +++ b/libgo/go/go/types/operand.go @@ -0,0 +1,287 @@ +// 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 defines operands and associated operations. + +package types + +import ( + "bytes" + "go/ast" + "go/constant" + "go/token" +) + +// An operandMode specifies the (addressing) mode of an operand. +type operandMode byte + +const ( + invalid operandMode = iota // operand is invalid + novalue // operand represents no value (result of a function call w/o result) + builtin // operand is a built-in function + typexpr // operand is a type + constant_ // operand is a constant; the operand's typ is a Basic type + variable // operand is an addressable variable + mapindex // operand is a map index expression (acts like a variable on lhs, commaok on rhs of an assignment) + value // operand is a computed value + commaok // like value, but operand may be used in a comma,ok expression +) + +var operandModeString = [...]string{ + invalid: "invalid operand", + novalue: "no value", + builtin: "built-in", + typexpr: "type", + constant_: "constant", + variable: "variable", + mapindex: "map index expression", + value: "value", + commaok: "comma, ok expression", +} + +// An operand represents an intermediate value during type checking. +// Operands have an (addressing) mode, the expression evaluating to +// the operand, the operand's type, a value for constants, and an id +// for built-in functions. +// The zero value of operand is a ready to use invalid operand. +// +type operand struct { + mode operandMode + expr ast.Expr + typ Type + val constant.Value + id builtinId +} + +// pos returns the position of the expression corresponding to x. +// If x is invalid the position is token.NoPos. +// +func (x *operand) pos() token.Pos { + // x.expr may not be set if x is invalid + if x.expr == nil { + return token.NoPos + } + return x.expr.Pos() +} + +// Operand string formats +// (not all "untyped" cases can appear due to the type system, +// but they fall out naturally here) +// +// mode format +// +// invalid ( ) +// novalue ( ) +// builtin ( ) +// typexpr ( ) +// +// constant ( ) +// constant ( of type ) +// constant ( ) +// constant ( of type ) +// +// variable ( ) +// variable ( of type ) +// +// mapindex ( ) +// mapindex ( of type ) +// +// value ( ) +// value ( of type ) +// +// commaok ( ) +// commaok ( of type ) +// +func operandString(x *operand, qf Qualifier) string { + var buf bytes.Buffer + + var expr string + if x.expr != nil { + expr = ExprString(x.expr) + } else { + switch x.mode { + case builtin: + expr = predeclaredFuncs[x.id].name + case typexpr: + expr = TypeString(x.typ, qf) + case constant_: + expr = x.val.String() + } + } + + // ( + if expr != "" { + buf.WriteString(expr) + buf.WriteString(" (") + } + + // + hasType := false + switch x.mode { + case invalid, novalue, builtin, typexpr: + // no type + default: + // has type + if isUntyped(x.typ) { + buf.WriteString(x.typ.(*Basic).name) + buf.WriteByte(' ') + break + } + hasType = true + } + + // + buf.WriteString(operandModeString[x.mode]) + + // + if x.mode == constant_ { + if s := x.val.String(); s != expr { + buf.WriteByte(' ') + buf.WriteString(s) + } + } + + // + if hasType { + if x.typ != Typ[Invalid] { + buf.WriteString(" of type ") + WriteType(&buf, x.typ, qf) + } else { + buf.WriteString(" with invalid type") + } + } + + // ) + if expr != "" { + buf.WriteByte(')') + } + + return buf.String() +} + +func (x *operand) String() string { + return operandString(x, nil) +} + +// setConst sets x to the untyped constant for literal lit. +func (x *operand) setConst(tok token.Token, lit string) { + val := constant.MakeFromLiteral(lit, tok, 0) + if val == nil { + // TODO(gri) Should we make it an unknown constant instead? + x.mode = invalid + return + } + + var kind BasicKind + switch tok { + case token.INT: + kind = UntypedInt + case token.FLOAT: + kind = UntypedFloat + case token.IMAG: + kind = UntypedComplex + case token.CHAR: + kind = UntypedRune + case token.STRING: + kind = UntypedString + } + + x.mode = constant_ + x.typ = Typ[kind] + x.val = val +} + +// isNil reports whether x is the nil value. +func (x *operand) isNil() bool { + return x.mode == value && x.typ == Typ[UntypedNil] +} + +// TODO(gri) The functions operand.assignableTo, checker.convertUntyped, +// checker.representable, and checker.assignment are +// overlapping in functionality. Need to simplify and clean up. + +// assignableTo reports whether x is assignable to a variable of type T. +func (x *operand) assignableTo(conf *Config, T Type) bool { + if x.mode == invalid || T == Typ[Invalid] { + return true // avoid spurious errors + } + + V := x.typ + + // x's type is identical to T + if Identical(V, T) { + return true + } + + Vu := V.Underlying() + Tu := T.Underlying() + + // T is an interface type and x implements T + // (Do this check first as it might succeed early.) + if Ti, ok := Tu.(*Interface); ok { + if Implements(x.typ, Ti) { + return true + } + } + + // x's type V and T have identical underlying types + // and at least one of V or T is not a named type + if Identical(Vu, Tu) && (!isNamed(V) || !isNamed(T)) { + return true + } + + // x is a bidirectional channel value, T is a channel + // type, x's type V and T have identical element types, + // and at least one of V or T is not a named type + if Vc, ok := Vu.(*Chan); ok && Vc.dir == SendRecv { + if Tc, ok := Tu.(*Chan); ok && Identical(Vc.elem, Tc.elem) { + return !isNamed(V) || !isNamed(T) + } + } + + // x is the predeclared identifier nil and T is a pointer, + // function, slice, map, channel, or interface type + if x.isNil() { + switch t := Tu.(type) { + case *Basic: + if t.kind == UnsafePointer { + return true + } + case *Pointer, *Signature, *Slice, *Map, *Chan, *Interface: + return true + } + return false + } + + // x is an untyped constant representable by a value of type T + // TODO(gri) This is borrowing from checker.convertUntyped and + // checker.representable. Need to clean up. + if isUntyped(Vu) { + switch t := Tu.(type) { + case *Basic: + if x.mode == constant_ { + return representableConst(x.val, conf, t.kind, nil) + } + // The result of a comparison is an untyped boolean, + // but may not be a constant. + if Vb, _ := Vu.(*Basic); Vb != nil { + return Vb.kind == UntypedBool && isBoolean(Tu) + } + case *Interface: + return x.isNil() || t.Empty() + case *Pointer, *Signature, *Slice, *Map, *Chan: + return x.isNil() + } + } + + return false +} + +// isInteger reports whether x is value of integer type +// or an untyped constant representable as an integer. +func (x *operand) isInteger() bool { + return x.mode == invalid || + isInteger(x.typ) || + isUntyped(x.typ) && x.mode == constant_ && representableConst(x.val, nil, UntypedInt, nil) // no *Config required for UntypedInt +} diff --git a/libgo/go/go/types/ordering.go b/libgo/go/go/types/ordering.go new file mode 100644 index 00000000000..6bb98f2dc10 --- /dev/null +++ b/libgo/go/go/types/ordering.go @@ -0,0 +1,127 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file implements resolveOrder. + +package types + +import ( + "go/ast" + "sort" +) + +// resolveOrder computes the order in which package-level objects +// must be type-checked. +// +// Interface types appear first in the list, sorted topologically +// by dependencies on embedded interfaces that are also declared +// in this package, followed by all other objects sorted in source +// order. +// +// TODO(gri) Consider sorting all types by dependencies here, and +// in the process check _and_ report type cycles. This may simplify +// the full type-checking phase. +// +func (check *Checker) resolveOrder() []Object { + var ifaces, others []Object + + // collect interface types with their dependencies, and all other objects + for obj := range check.objMap { + if ityp := check.interfaceFor(obj); ityp != nil { + ifaces = append(ifaces, obj) + // determine dependencies on embedded interfaces + for _, f := range ityp.Methods.List { + if len(f.Names) == 0 { + // Embedded interface: The type must be a (possibly + // qualified) identifier denoting another interface. + // Imported interfaces are already fully resolved, + // so we can ignore qualified identifiers. + if ident, _ := f.Type.(*ast.Ident); ident != nil { + embedded := check.pkg.scope.Lookup(ident.Name) + if check.interfaceFor(embedded) != nil { + check.objMap[obj].addDep(embedded) + } + } + } + } + } else { + others = append(others, obj) + } + } + + // final object order + var order []Object + + // sort interface types topologically by dependencies, + // and in source order if there are no dependencies + sort.Sort(inSourceOrder(ifaces)) + if debug { + for _, obj := range ifaces { + assert(check.objMap[obj].mark == 0) + } + } + for _, obj := range ifaces { + check.appendInPostOrder(&order, obj) + } + + // sort everything else in source order + sort.Sort(inSourceOrder(others)) + + return append(order, others...) +} + +// interfaceFor returns the AST interface denoted by obj, or nil. +func (check *Checker) interfaceFor(obj Object) *ast.InterfaceType { + tname, _ := obj.(*TypeName) + if tname == nil { + return nil // not a type + } + d := check.objMap[obj] + if d == nil { + check.dump("%s: %s should have been declared", obj.Pos(), obj.Name()) + unreachable() + } + if d.typ == nil { + return nil // invalid AST - ignore (will be handled later) + } + ityp, _ := d.typ.(*ast.InterfaceType) + return ityp +} + +func (check *Checker) appendInPostOrder(order *[]Object, obj Object) { + d := check.objMap[obj] + if d.mark != 0 { + // We've already seen this object; either because it's + // already added to order, or because we have a cycle. + // In both cases we stop. Cycle errors are reported + // when type-checking types. + return + } + d.mark = 1 + + for _, obj := range orderedSetObjects(d.deps) { + check.appendInPostOrder(order, obj) + } + + *order = append(*order, obj) +} + +func orderedSetObjects(set map[Object]bool) []Object { + list := make([]Object, len(set)) + i := 0 + for obj := range set { + // we don't care about the map element value + list[i] = obj + i++ + } + sort.Sort(inSourceOrder(list)) + return list +} + +// inSourceOrder implements the sort.Sort interface. +type inSourceOrder []Object + +func (a inSourceOrder) Len() int { return len(a) } +func (a inSourceOrder) Less(i, j int) bool { return a[i].order() < a[j].order() } +func (a inSourceOrder) Swap(i, j int) { a[i], a[j] = a[j], a[i] } diff --git a/libgo/go/go/types/package.go b/libgo/go/go/types/package.go new file mode 100644 index 00000000000..48fe8398fe6 --- /dev/null +++ b/libgo/go/go/types/package.go @@ -0,0 +1,65 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package types + +import ( + "fmt" + "go/token" +) + +// A Package describes a Go package. +type Package struct { + path string + name string + scope *Scope + complete bool + imports []*Package + fake bool // scope lookup errors are silently dropped if package is fake (internal use only) +} + +// NewPackage returns a new Package for the given package path and name; +// the name must not be the blank identifier. +// The package is not complete and contains no explicit imports. +func NewPackage(path, name string) *Package { + if name == "_" { + panic("invalid package name _") + } + scope := NewScope(Universe, token.NoPos, token.NoPos, fmt.Sprintf("package %q", path)) + return &Package{path: path, name: name, scope: scope} +} + +// Path returns the package path. +func (pkg *Package) Path() string { return pkg.path } + +// Name returns the package name. +func (pkg *Package) Name() string { return pkg.name } + +// Scope returns the (complete or incomplete) package scope +// holding the objects declared at package level (TypeNames, +// Consts, Vars, and Funcs). +func (pkg *Package) Scope() *Scope { return pkg.scope } + +// A package is complete if its scope contains (at least) all +// exported objects; otherwise it is incomplete. +func (pkg *Package) Complete() bool { return pkg.complete } + +// MarkComplete marks a package as complete. +func (pkg *Package) MarkComplete() { pkg.complete = true } + +// Imports returns the list of packages directly imported by +// pkg; the list is in source order. Package unsafe is excluded. +// +// If pkg was loaded from export data, Imports includes packages that +// provide package-level objects referenced by pkg. This may be more or +// less than the set of packages directly imported by pkg's source code. +func (pkg *Package) Imports() []*Package { return pkg.imports } + +// SetImports sets the list of explicitly imported packages to list. +// It is the caller's responsibility to make sure list elements are unique. +func (pkg *Package) SetImports(list []*Package) { pkg.imports = list } + +func (pkg *Package) String() string { + return fmt.Sprintf("package %s (%q)", pkg.name, pkg.path) +} diff --git a/libgo/go/go/types/predicates.go b/libgo/go/go/types/predicates.go new file mode 100644 index 00000000000..993c6d290b1 --- /dev/null +++ b/libgo/go/go/types/predicates.go @@ -0,0 +1,309 @@ +// 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 commonly used type predicates. + +package types + +import "sort" + +func isNamed(typ Type) bool { + if _, ok := typ.(*Basic); ok { + return ok + } + _, ok := typ.(*Named) + return ok +} + +func isBoolean(typ Type) bool { + t, ok := typ.Underlying().(*Basic) + return ok && t.info&IsBoolean != 0 +} + +func isInteger(typ Type) bool { + t, ok := typ.Underlying().(*Basic) + return ok && t.info&IsInteger != 0 +} + +func isUnsigned(typ Type) bool { + t, ok := typ.Underlying().(*Basic) + return ok && t.info&IsUnsigned != 0 +} + +func isFloat(typ Type) bool { + t, ok := typ.Underlying().(*Basic) + return ok && t.info&IsFloat != 0 +} + +func isComplex(typ Type) bool { + t, ok := typ.Underlying().(*Basic) + return ok && t.info&IsComplex != 0 +} + +func isNumeric(typ Type) bool { + t, ok := typ.Underlying().(*Basic) + return ok && t.info&IsNumeric != 0 +} + +func isString(typ Type) bool { + t, ok := typ.Underlying().(*Basic) + return ok && t.info&IsString != 0 +} + +func isTyped(typ Type) bool { + t, ok := typ.Underlying().(*Basic) + return !ok || t.info&IsUntyped == 0 +} + +func isUntyped(typ Type) bool { + t, ok := typ.Underlying().(*Basic) + return ok && t.info&IsUntyped != 0 +} + +func isOrdered(typ Type) bool { + t, ok := typ.Underlying().(*Basic) + return ok && t.info&IsOrdered != 0 +} + +func isConstType(typ Type) bool { + t, ok := typ.Underlying().(*Basic) + return ok && t.info&IsConstType != 0 +} + +// IsInterface reports whether typ is an interface type. +func IsInterface(typ Type) bool { + _, ok := typ.Underlying().(*Interface) + return ok +} + +// Comparable reports whether values of type T are comparable. +func Comparable(T Type) bool { + switch t := T.Underlying().(type) { + case *Basic: + // assume invalid types to be comparable + // to avoid follow-up errors + return t.kind != UntypedNil + case *Pointer, *Interface, *Chan: + return true + case *Struct: + for _, f := range t.fields { + if !Comparable(f.typ) { + return false + } + } + return true + case *Array: + return Comparable(t.elem) + } + return false +} + +// hasNil reports whether a type includes the nil value. +func hasNil(typ Type) bool { + switch t := typ.Underlying().(type) { + case *Basic: + return t.kind == UnsafePointer + case *Slice, *Pointer, *Signature, *Interface, *Map, *Chan: + return true + } + return false +} + +// Identical reports whether x and y are identical. +func Identical(x, y Type) bool { + return identical(x, y, nil) +} + +// An ifacePair is a node in a stack of interface type pairs compared for identity. +type ifacePair struct { + x, y *Interface + prev *ifacePair +} + +func (p *ifacePair) identical(q *ifacePair) bool { + return p.x == q.x && p.y == q.y || p.x == q.y && p.y == q.x +} + +func identical(x, y Type, p *ifacePair) bool { + if x == y { + return true + } + + switch x := x.(type) { + case *Basic: + // Basic types are singletons except for the rune and byte + // aliases, thus we cannot solely rely on the x == y check + // above. + if y, ok := y.(*Basic); ok { + return x.kind == y.kind + } + + case *Array: + // Two array types are identical if they have identical element types + // and the same array length. + if y, ok := y.(*Array); ok { + return x.len == y.len && identical(x.elem, y.elem, p) + } + + case *Slice: + // Two slice types are identical if they have identical element types. + if y, ok := y.(*Slice); ok { + return identical(x.elem, y.elem, p) + } + + case *Struct: + // Two struct types are identical if they have the same sequence of fields, + // and if corresponding fields have the same names, and identical types, + // and identical tags. Two anonymous fields are considered to have the same + // name. Lower-case field names from different packages are always different. + if y, ok := y.(*Struct); ok { + if x.NumFields() == y.NumFields() { + for i, f := range x.fields { + g := y.fields[i] + if f.anonymous != g.anonymous || + x.Tag(i) != y.Tag(i) || + !f.sameId(g.pkg, g.name) || + !identical(f.typ, g.typ, p) { + return false + } + } + return true + } + } + + case *Pointer: + // Two pointer types are identical if they have identical base types. + if y, ok := y.(*Pointer); ok { + return identical(x.base, y.base, p) + } + + case *Tuple: + // Two tuples types are identical if they have the same number of elements + // and corresponding elements have identical types. + if y, ok := y.(*Tuple); ok { + if x.Len() == y.Len() { + if x != nil { + for i, v := range x.vars { + w := y.vars[i] + if !identical(v.typ, w.typ, p) { + return false + } + } + } + return true + } + } + + case *Signature: + // Two function types are identical if they have the same number of parameters + // and result values, corresponding parameter and result types are identical, + // and either both functions are variadic or neither is. Parameter and result + // names are not required to match. + if y, ok := y.(*Signature); ok { + return x.variadic == y.variadic && + identical(x.params, y.params, p) && + identical(x.results, y.results, p) + } + + case *Interface: + // Two interface types are identical if they have the same set of methods with + // the same names and identical function types. Lower-case method names from + // different packages are always different. The order of the methods is irrelevant. + if y, ok := y.(*Interface); ok { + a := x.allMethods + b := y.allMethods + if len(a) == len(b) { + // Interface types are the only types where cycles can occur + // that are not "terminated" via named types; and such cycles + // can only be created via method parameter types that are + // anonymous interfaces (directly or indirectly) embedding + // the current interface. Example: + // + // type T interface { + // m() interface{T} + // } + // + // If two such (differently named) interfaces are compared, + // endless recursion occurs if the cycle is not detected. + // + // If x and y were compared before, they must be equal + // (if they were not, the recursion would have stopped); + // search the ifacePair stack for the same pair. + // + // This is a quadratic algorithm, but in practice these stacks + // are extremely short (bounded by the nesting depth of interface + // type declarations that recur via parameter types, an extremely + // rare occurrence). An alternative implementation might use a + // "visited" map, but that is probably less efficient overall. + q := &ifacePair{x, y, p} + for p != nil { + if p.identical(q) { + return true // same pair was compared before + } + p = p.prev + } + if debug { + assert(sort.IsSorted(byUniqueMethodName(a))) + assert(sort.IsSorted(byUniqueMethodName(b))) + } + for i, f := range a { + g := b[i] + if f.Id() != g.Id() || !identical(f.typ, g.typ, q) { + return false + } + } + return true + } + } + + case *Map: + // Two map types are identical if they have identical key and value types. + if y, ok := y.(*Map); ok { + return identical(x.key, y.key, p) && identical(x.elem, y.elem, p) + } + + case *Chan: + // Two channel types are identical if they have identical value types + // and the same direction. + if y, ok := y.(*Chan); ok { + return x.dir == y.dir && identical(x.elem, y.elem, p) + } + + case *Named: + // Two named types are identical if their type names originate + // in the same type declaration. + if y, ok := y.(*Named); ok { + return x.obj == y.obj + } + + default: + unreachable() + } + + return false +} + +// defaultType returns the default "typed" type for an "untyped" type; +// it returns the incoming type for all other types. The default type +// for untyped nil is untyped nil. +// +func defaultType(typ Type) Type { + if t, ok := typ.(*Basic); ok { + switch t.kind { + case UntypedBool: + return Typ[Bool] + case UntypedInt: + return Typ[Int] + case UntypedRune: + return universeRune // use 'rune' name + case UntypedFloat: + return Typ[Float64] + case UntypedComplex: + return Typ[Complex128] + case UntypedString: + return Typ[String] + } + } + return typ +} diff --git a/libgo/go/go/types/resolver.go b/libgo/go/go/types/resolver.go new file mode 100644 index 00000000000..c31ef423d9a --- /dev/null +++ b/libgo/go/go/types/resolver.go @@ -0,0 +1,445 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package types + +import ( + "fmt" + "go/ast" + "go/constant" + "go/token" + pathLib "path" + "strconv" + "strings" + "unicode" +) + +// A declInfo describes a package-level const, type, var, or func declaration. +type declInfo struct { + file *Scope // scope of file containing this declaration + lhs []*Var // lhs of n:1 variable declarations, or nil + typ ast.Expr // type, or nil + init ast.Expr // init expression, or nil + fdecl *ast.FuncDecl // func declaration, or nil + + deps map[Object]bool // type and init dependencies; lazily allocated + mark int // for dependency analysis +} + +// hasInitializer reports whether the declared object has an initialization +// expression or function body. +func (d *declInfo) hasInitializer() bool { + return d.init != nil || d.fdecl != nil && d.fdecl.Body != nil +} + +// addDep adds obj as a dependency to d. +func (d *declInfo) addDep(obj Object) { + m := d.deps + if m == nil { + m = make(map[Object]bool) + d.deps = m + } + m[obj] = true +} + +// arityMatch checks that the lhs and rhs of a const or var decl +// have the appropriate number of names and init exprs. For const +// decls, init is the value spec providing the init exprs; for +// var decls, init is nil (the init exprs are in s in this case). +func (check *Checker) arityMatch(s, init *ast.ValueSpec) { + l := len(s.Names) + r := len(s.Values) + if init != nil { + r = len(init.Values) + } + + switch { + case init == nil && r == 0: + // var decl w/o init expr + if s.Type == nil { + check.errorf(s.Pos(), "missing type or init expr") + } + case l < r: + if l < len(s.Values) { + // init exprs from s + n := s.Values[l] + check.errorf(n.Pos(), "extra init expr %s", n) + // TODO(gri) avoid declared but not used error here + } else { + // init exprs "inherited" + check.errorf(s.Pos(), "extra init expr at %s", init.Pos()) + // TODO(gri) avoid declared but not used error here + } + case l > r && (init != nil || r != 1): + n := s.Names[r] + check.errorf(n.Pos(), "missing init expr for %s", n) + } +} + +func validatedImportPath(path string) (string, error) { + s, err := strconv.Unquote(path) + if err != nil { + return "", err + } + if s == "" { + return "", fmt.Errorf("empty string") + } + const illegalChars = `!"#$%&'()*,:;<=>?[\]^{|}` + "`\uFFFD" + for _, r := range s { + if !unicode.IsGraphic(r) || unicode.IsSpace(r) || strings.ContainsRune(illegalChars, r) { + return s, fmt.Errorf("invalid character %#U", r) + } + } + return s, nil +} + +// declarePkgObj declares obj in the package scope, records its ident -> obj mapping, +// and updates check.objMap. The object must not be a function or method. +func (check *Checker) declarePkgObj(ident *ast.Ident, obj Object, d *declInfo) { + assert(ident.Name == obj.Name()) + + // spec: "A package-scope or file-scope identifier with name init + // may only be declared to be a function with this (func()) signature." + if ident.Name == "init" { + check.errorf(ident.Pos(), "cannot declare init - must be func") + return + } + + check.declare(check.pkg.scope, ident, obj, token.NoPos) + check.objMap[obj] = d + obj.setOrder(uint32(len(check.objMap))) +} + +// filename returns a filename suitable for debugging output. +func (check *Checker) filename(fileNo int) string { + file := check.files[fileNo] + if pos := file.Pos(); pos.IsValid() { + return check.fset.File(pos).Name() + } + return fmt.Sprintf("file[%d]", fileNo) +} + +// collectObjects collects all file and package objects and inserts them +// into their respective scopes. It also performs imports and associates +// methods with receiver base type names. +func (check *Checker) collectObjects() { + pkg := check.pkg + + // pkgImports is the set of packages already imported by any package file seen + // so far. Used to avoid duplicate entries in pkg.imports. Allocate and populate + // it (pkg.imports may not be empty if we are checking test files incrementally). + var pkgImports = make(map[*Package]bool) + for _, imp := range pkg.imports { + pkgImports[imp] = true + } + + for fileNo, file := range check.files { + // The package identifier denotes the current package, + // but there is no corresponding package object. + check.recordDef(file.Name, nil) + + // Use the actual source file extent rather than *ast.File extent since the + // latter doesn't include comments which appear at the start or end of the file. + // Be conservative and use the *ast.File extent if we don't have a *token.File. + pos, end := file.Pos(), file.End() + if f := check.fset.File(file.Pos()); f != nil { + pos, end = token.Pos(f.Base()), token.Pos(f.Base()+f.Size()) + } + fileScope := NewScope(check.pkg.scope, pos, end, check.filename(fileNo)) + check.recordScope(file, fileScope) + + for _, decl := range file.Decls { + switch d := decl.(type) { + case *ast.BadDecl: + // ignore + + case *ast.GenDecl: + var last *ast.ValueSpec // last ValueSpec with type or init exprs seen + for iota, spec := range d.Specs { + switch s := spec.(type) { + case *ast.ImportSpec: + // import package + var imp *Package + path, err := validatedImportPath(s.Path.Value) + if err != nil { + check.errorf(s.Path.Pos(), "invalid import path (%s)", err) + continue + } + if path == "C" && check.conf.FakeImportC { + // TODO(gri) shouldn't create a new one each time + imp = NewPackage("C", "C") + imp.fake = true + } else if path == "unsafe" { + // package "unsafe" is known to the language + imp = Unsafe + } else { + if importer := check.conf.Importer; importer != nil { + imp, err = importer.Import(path) + if imp == nil && err == nil { + err = fmt.Errorf("Config.Importer.Import(%s) returned nil but no error", path) + } + } else { + err = fmt.Errorf("Config.Importer not installed") + } + if err != nil { + check.errorf(s.Path.Pos(), "could not import %s (%s)", path, err) + continue + } + } + + // add package to list of explicit imports + // (this functionality is provided as a convenience + // for clients; it is not needed for type-checking) + if !pkgImports[imp] { + pkgImports[imp] = true + if imp != Unsafe { + pkg.imports = append(pkg.imports, imp) + } + } + + // local name overrides imported package name + name := imp.name + if s.Name != nil { + name = s.Name.Name + if name == "init" { + check.errorf(s.Name.Pos(), "cannot declare init - must be func") + continue + } + } + + obj := NewPkgName(s.Pos(), pkg, name, imp) + if s.Name != nil { + // in a dot-import, the dot represents the package + check.recordDef(s.Name, obj) + } else { + check.recordImplicit(s, obj) + } + + // add import to file scope + if name == "." { + // merge imported scope with file scope + for _, obj := range imp.scope.elems { + // A package scope may contain non-exported objects, + // do not import them! + if obj.Exported() { + // TODO(gri) When we import a package, we create + // a new local package object. We should do the + // same for each dot-imported object. That way + // they can have correct position information. + // (We must not modify their existing position + // information because the same package - found + // via Config.Packages - may be dot-imported in + // another package!) + check.declare(fileScope, nil, obj, token.NoPos) + check.recordImplicit(s, obj) + } + } + // add position to set of dot-import positions for this file + // (this is only needed for "imported but not used" errors) + check.addUnusedDotImport(fileScope, imp, s.Pos()) + } else { + // declare imported package object in file scope + check.declare(fileScope, nil, obj, token.NoPos) + } + + case *ast.ValueSpec: + switch d.Tok { + case token.CONST: + // determine which initialization expressions to use + switch { + case s.Type != nil || len(s.Values) > 0: + last = s + case last == nil: + last = new(ast.ValueSpec) // make sure last exists + } + + // declare all constants + for i, name := range s.Names { + obj := NewConst(name.Pos(), pkg, name.Name, nil, constant.MakeInt64(int64(iota))) + + var init ast.Expr + if i < len(last.Values) { + init = last.Values[i] + } + + d := &declInfo{file: fileScope, typ: last.Type, init: init} + check.declarePkgObj(name, obj, d) + } + + check.arityMatch(s, last) + + case token.VAR: + lhs := make([]*Var, len(s.Names)) + // If there's exactly one rhs initializer, use + // the same declInfo d1 for all lhs variables + // so that each lhs variable depends on the same + // rhs initializer (n:1 var declaration). + var d1 *declInfo + if len(s.Values) == 1 { + // The lhs elements are only set up after the for loop below, + // but that's ok because declareVar only collects the declInfo + // for a later phase. + d1 = &declInfo{file: fileScope, lhs: lhs, typ: s.Type, init: s.Values[0]} + } + + // declare all variables + for i, name := range s.Names { + obj := NewVar(name.Pos(), pkg, name.Name, nil) + lhs[i] = obj + + d := d1 + if d == nil { + // individual assignments + var init ast.Expr + if i < len(s.Values) { + init = s.Values[i] + } + d = &declInfo{file: fileScope, typ: s.Type, init: init} + } + + check.declarePkgObj(name, obj, d) + } + + check.arityMatch(s, nil) + + default: + check.invalidAST(s.Pos(), "invalid token %s", d.Tok) + } + + case *ast.TypeSpec: + obj := NewTypeName(s.Name.Pos(), pkg, s.Name.Name, nil) + check.declarePkgObj(s.Name, obj, &declInfo{file: fileScope, typ: s.Type}) + + default: + check.invalidAST(s.Pos(), "unknown ast.Spec node %T", s) + } + } + + case *ast.FuncDecl: + name := d.Name.Name + obj := NewFunc(d.Name.Pos(), pkg, name, nil) + if d.Recv == nil { + // regular function + if name == "init" { + // don't declare init functions in the package scope - they are invisible + obj.parent = pkg.scope + check.recordDef(d.Name, obj) + // init functions must have a body + if d.Body == nil { + check.softErrorf(obj.pos, "missing function body") + } + } else { + check.declare(pkg.scope, d.Name, obj, token.NoPos) + } + } else { + // method + check.recordDef(d.Name, obj) + // Associate method with receiver base type name, if possible. + // Ignore methods that have an invalid receiver, or a blank _ + // receiver name. They will be type-checked later, with regular + // functions. + if list := d.Recv.List; len(list) > 0 { + typ := list[0].Type + if ptr, _ := typ.(*ast.StarExpr); ptr != nil { + typ = ptr.X + } + if base, _ := typ.(*ast.Ident); base != nil && base.Name != "_" { + check.assocMethod(base.Name, obj) + } + } + } + info := &declInfo{file: fileScope, fdecl: d} + check.objMap[obj] = info + obj.setOrder(uint32(len(check.objMap))) + + default: + check.invalidAST(d.Pos(), "unknown ast.Decl node %T", d) + } + } + } + + // verify that objects in package and file scopes have different names + for _, scope := range check.pkg.scope.children /* file scopes */ { + for _, obj := range scope.elems { + if alt := pkg.scope.Lookup(obj.Name()); alt != nil { + if pkg, ok := obj.(*PkgName); ok { + check.errorf(alt.Pos(), "%s already declared through import of %s", alt.Name(), pkg.Imported()) + check.reportAltDecl(pkg) + } else { + check.errorf(alt.Pos(), "%s already declared through dot-import of %s", alt.Name(), obj.Pkg()) + // TODO(gri) dot-imported objects don't have a position; reportAltDecl won't print anything + check.reportAltDecl(obj) + } + } + } + } +} + +// packageObjects typechecks all package objects in objList, but not function bodies. +func (check *Checker) packageObjects(objList []Object) { + // add new methods to already type-checked types (from a prior Checker.Files call) + for _, obj := range objList { + if obj, _ := obj.(*TypeName); obj != nil && obj.typ != nil { + check.addMethodDecls(obj) + } + } + + // pre-allocate space for type declaration paths so that the underlying array is reused + typePath := make([]*TypeName, 0, 8) + + for _, obj := range objList { + check.objDecl(obj, nil, typePath) + } + + // At this point we may have a non-empty check.methods map; this means that not all + // entries were deleted at the end of typeDecl because the respective receiver base + // types were not found. In that case, an error was reported when declaring those + // methods. We can now safely discard this map. + check.methods = nil +} + +// functionBodies typechecks all function bodies. +func (check *Checker) functionBodies() { + for _, f := range check.funcs { + check.funcBody(f.decl, f.name, f.sig, f.body) + } +} + +// unusedImports checks for unused imports. +func (check *Checker) unusedImports() { + // if function bodies are not checked, packages' uses are likely missing - don't check + if check.conf.IgnoreFuncBodies { + return + } + + // spec: "It is illegal (...) to directly import a package without referring to + // any of its exported identifiers. To import a package solely for its side-effects + // (initialization), use the blank identifier as explicit package name." + + // check use of regular imported packages + for _, scope := range check.pkg.scope.children /* file scopes */ { + for _, obj := range scope.elems { + if obj, ok := obj.(*PkgName); ok { + // Unused "blank imports" are automatically ignored + // since _ identifiers are not entered into scopes. + if !obj.used { + path := obj.imported.path + base := pathLib.Base(path) + if obj.name == base { + check.softErrorf(obj.pos, "%q imported but not used", path) + } else { + check.softErrorf(obj.pos, "%q imported but not used as %s", path, obj.name) + } + } + } + } + } + + // check use of dot-imported packages + for _, unusedDotImports := range check.unusedDotImports { + for pkg, pos := range unusedDotImports { + check.softErrorf(pos, "%q imported but not used", pkg.path) + } + } +} diff --git a/libgo/go/go/types/resolver_test.go b/libgo/go/go/types/resolver_test.go new file mode 100644 index 00000000000..34deae268e3 --- /dev/null +++ b/libgo/go/go/types/resolver_test.go @@ -0,0 +1,209 @@ +// 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 types_test + +import ( + "fmt" + "go/ast" + "go/importer" + "go/parser" + "go/token" + "internal/testenv" + "sort" + "testing" + + . "go/types" +) + +type resolveTestImporter struct { + importer Importer + imported map[string]bool +} + +func (imp *resolveTestImporter) Import(path string) (*Package, error) { + if imp.importer == nil { + imp.importer = importer.Default() + imp.imported = make(map[string]bool) + } + pkg, err := imp.importer.Import(path) + if err != nil { + return nil, err + } + imp.imported[path] = true + return pkg, nil +} + +func TestResolveIdents(t *testing.T) { + testenv.MustHaveGoBuild(t) + + sources := []string{ + ` + package p + import "fmt" + import "math" + const pi = math.Pi + func sin(x float64) float64 { + return math.Sin(x) + } + var Println = fmt.Println + `, + ` + package p + import "fmt" + type errorStringer struct { fmt.Stringer; error } + func f() string { + _ = "foo" + return fmt.Sprintf("%d", g()) + } + func g() (x int) { return } + `, + ` + package p + import . "go/parser" + import "sync" + func h() Mode { return ImportsOnly } + var _, x int = 1, 2 + func init() {} + type T struct{ *sync.Mutex; a, b, c int} + type I interface{ m() } + var _ = T{a: 1, b: 2, c: 3} + func (_ T) m() {} + func (T) _() {} + var i I + var _ = i.m + func _(s []int) { for i, x := range s { _, _ = i, x } } + func _(x interface{}) { + switch x := x.(type) { + case int: + _ = x + } + switch {} // implicit 'true' tag + } + `, + ` + package p + type S struct{} + func (T) _() {} + func (T) _() {} + `, + ` + package p + func _() { + L0: + L1: + goto L0 + for { + goto L1 + } + if true { + goto L2 + } + L2: + } + `, + } + + pkgnames := []string{ + "fmt", + "math", + } + + // parse package files + fset := token.NewFileSet() + var files []*ast.File + for i, src := range sources { + f, err := parser.ParseFile(fset, fmt.Sprintf("sources[%d]", i), src, parser.DeclarationErrors) + if err != nil { + t.Fatal(err) + } + files = append(files, f) + } + + // resolve and type-check package AST + importer := new(resolveTestImporter) + conf := Config{Importer: importer} + uses := make(map[*ast.Ident]Object) + defs := make(map[*ast.Ident]Object) + _, err := conf.Check("testResolveIdents", fset, files, &Info{Defs: defs, Uses: uses}) + if err != nil { + t.Fatal(err) + } + + // check that all packages were imported + for _, name := range pkgnames { + if !importer.imported[name] { + t.Errorf("package %s not imported", name) + } + } + + // check that qualified identifiers are resolved + for _, f := range files { + ast.Inspect(f, func(n ast.Node) bool { + if s, ok := n.(*ast.SelectorExpr); ok { + if x, ok := s.X.(*ast.Ident); ok { + obj := uses[x] + if obj == nil { + t.Errorf("%s: unresolved qualified identifier %s", fset.Position(x.Pos()), x.Name) + return false + } + if _, ok := obj.(*PkgName); ok && uses[s.Sel] == nil { + t.Errorf("%s: unresolved selector %s", fset.Position(s.Sel.Pos()), s.Sel.Name) + return false + } + return false + } + return false + } + return true + }) + } + + for id, obj := range uses { + if obj == nil { + t.Errorf("%s: Uses[%s] == nil", fset.Position(id.Pos()), id.Name) + } + } + + // check that each identifier in the source is found in uses or defs or both + var both []string + for _, f := range files { + ast.Inspect(f, func(n ast.Node) bool { + if x, ok := n.(*ast.Ident); ok { + var objects int + if _, found := uses[x]; found { + objects |= 1 + delete(uses, x) + } + if _, found := defs[x]; found { + objects |= 2 + delete(defs, x) + } + if objects == 0 { + t.Errorf("%s: unresolved identifier %s", fset.Position(x.Pos()), x.Name) + } else if objects == 3 { + both = append(both, x.Name) + } + return false + } + return true + }) + } + + // check the expected set of idents that are simultaneously uses and defs + sort.Strings(both) + if got, want := fmt.Sprint(both), "[Mutex Stringer error]"; got != want { + t.Errorf("simultaneous uses/defs = %s, want %s", got, want) + } + + // any left-over identifiers didn't exist in the source + for x := range uses { + t.Errorf("%s: identifier %s not present in source", fset.Position(x.Pos()), x.Name) + } + for x := range defs { + t.Errorf("%s: identifier %s not present in source", fset.Position(x.Pos()), x.Name) + } + + // TODO(gri) add tests to check ImplicitObj callbacks +} diff --git a/libgo/go/go/types/return.go b/libgo/go/go/types/return.go new file mode 100644 index 00000000000..66289852147 --- /dev/null +++ b/libgo/go/go/types/return.go @@ -0,0 +1,185 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file implements isTerminating. + +package types + +import ( + "go/ast" + "go/token" +) + +// isTerminating reports if s is a terminating statement. +// If s is labeled, label is the label name; otherwise s +// is "". +func (check *Checker) isTerminating(s ast.Stmt, label string) bool { + switch s := s.(type) { + default: + unreachable() + + case *ast.BadStmt, *ast.DeclStmt, *ast.EmptyStmt, *ast.SendStmt, + *ast.IncDecStmt, *ast.AssignStmt, *ast.GoStmt, *ast.DeferStmt, + *ast.RangeStmt: + // no chance + + case *ast.LabeledStmt: + return check.isTerminating(s.Stmt, s.Label.Name) + + case *ast.ExprStmt: + // the predeclared (possibly parenthesized) panic() function is terminating + if call, _ := unparen(s.X).(*ast.CallExpr); call != nil { + if id, _ := call.Fun.(*ast.Ident); id != nil { + if _, obj := check.scope.LookupParent(id.Name, token.NoPos); obj != nil { + if b, _ := obj.(*Builtin); b != nil && b.id == _Panic { + return true + } + } + } + } + + case *ast.ReturnStmt: + return true + + case *ast.BranchStmt: + if s.Tok == token.GOTO || s.Tok == token.FALLTHROUGH { + return true + } + + case *ast.BlockStmt: + return check.isTerminatingList(s.List, "") + + case *ast.IfStmt: + if s.Else != nil && + check.isTerminating(s.Body, "") && + check.isTerminating(s.Else, "") { + return true + } + + case *ast.SwitchStmt: + return check.isTerminatingSwitch(s.Body, label) + + case *ast.TypeSwitchStmt: + return check.isTerminatingSwitch(s.Body, label) + + case *ast.SelectStmt: + for _, s := range s.Body.List { + cc := s.(*ast.CommClause) + if !check.isTerminatingList(cc.Body, "") || hasBreakList(cc.Body, label, true) { + return false + } + + } + return true + + case *ast.ForStmt: + if s.Cond == nil && !hasBreak(s.Body, label, true) { + return true + } + } + + return false +} + +func (check *Checker) isTerminatingList(list []ast.Stmt, label string) bool { + n := len(list) + return n > 0 && check.isTerminating(list[n-1], label) +} + +func (check *Checker) isTerminatingSwitch(body *ast.BlockStmt, label string) bool { + hasDefault := false + for _, s := range body.List { + cc := s.(*ast.CaseClause) + if cc.List == nil { + hasDefault = true + } + if !check.isTerminatingList(cc.Body, "") || hasBreakList(cc.Body, label, true) { + return false + } + } + return hasDefault +} + +// TODO(gri) For nested breakable statements, the current implementation of hasBreak +// will traverse the same subtree repeatedly, once for each label. Replace +// with a single-pass label/break matching phase. + +// hasBreak reports if s is or contains a break statement +// referring to the label-ed statement or implicit-ly the +// closest outer breakable statement. +func hasBreak(s ast.Stmt, label string, implicit bool) bool { + switch s := s.(type) { + default: + unreachable() + + case *ast.BadStmt, *ast.DeclStmt, *ast.EmptyStmt, *ast.ExprStmt, + *ast.SendStmt, *ast.IncDecStmt, *ast.AssignStmt, *ast.GoStmt, + *ast.DeferStmt, *ast.ReturnStmt: + // no chance + + case *ast.LabeledStmt: + return hasBreak(s.Stmt, label, implicit) + + case *ast.BranchStmt: + if s.Tok == token.BREAK { + if s.Label == nil { + return implicit + } + if s.Label.Name == label { + return true + } + } + + case *ast.BlockStmt: + return hasBreakList(s.List, label, implicit) + + case *ast.IfStmt: + if hasBreak(s.Body, label, implicit) || + s.Else != nil && hasBreak(s.Else, label, implicit) { + return true + } + + case *ast.CaseClause: + return hasBreakList(s.Body, label, implicit) + + case *ast.SwitchStmt: + if label != "" && hasBreak(s.Body, label, false) { + return true + } + + case *ast.TypeSwitchStmt: + if label != "" && hasBreak(s.Body, label, false) { + return true + } + + case *ast.CommClause: + return hasBreakList(s.Body, label, implicit) + + case *ast.SelectStmt: + if label != "" && hasBreak(s.Body, label, false) { + return true + } + + case *ast.ForStmt: + if label != "" && hasBreak(s.Body, label, false) { + return true + } + + case *ast.RangeStmt: + if label != "" && hasBreak(s.Body, label, false) { + return true + } + } + + return false +} + +func hasBreakList(list []ast.Stmt, label string, implicit bool) bool { + for _, s := range list { + if hasBreak(s, label, implicit) { + return true + } + } + return false +} diff --git a/libgo/go/go/types/scope.go b/libgo/go/go/types/scope.go new file mode 100644 index 00000000000..3502840225f --- /dev/null +++ b/libgo/go/go/types/scope.go @@ -0,0 +1,190 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file implements Scopes. + +package types + +import ( + "bytes" + "fmt" + "go/token" + "io" + "sort" + "strings" +) + +// TODO(gri) Provide scopes with a name or other mechanism so that +// objects can use that information for better printing. + +// A Scope maintains a set of objects and links to its containing +// (parent) and contained (children) scopes. Objects may be inserted +// and looked up by name. The zero value for Scope is a ready-to-use +// empty scope. +type Scope struct { + parent *Scope + children []*Scope + elems map[string]Object // lazily allocated + pos, end token.Pos // scope extent; may be invalid + comment string // for debugging only +} + +// NewScope returns a new, empty scope contained in the given parent +// scope, if any. The comment is for debugging only. +func NewScope(parent *Scope, pos, end token.Pos, comment string) *Scope { + s := &Scope{parent, nil, nil, pos, end, comment} + // don't add children to Universe scope! + if parent != nil && parent != Universe { + parent.children = append(parent.children, s) + } + return s +} + +// Parent returns the scope's containing (parent) scope. +func (s *Scope) Parent() *Scope { return s.parent } + +// Len() returns the number of scope elements. +func (s *Scope) Len() int { return len(s.elems) } + +// Names returns the scope's element names in sorted order. +func (s *Scope) Names() []string { + names := make([]string, len(s.elems)) + i := 0 + for name := range s.elems { + names[i] = name + i++ + } + sort.Strings(names) + return names +} + +// NumChildren() returns the number of scopes nested in s. +func (s *Scope) NumChildren() int { return len(s.children) } + +// Child returns the i'th child scope for 0 <= i < NumChildren(). +func (s *Scope) Child(i int) *Scope { return s.children[i] } + +// Lookup returns the object in scope s with the given name if such an +// object exists; otherwise the result is nil. +func (s *Scope) Lookup(name string) Object { + return s.elems[name] +} + +// LookupParent follows the parent chain of scopes starting with s until +// it finds a scope where Lookup(name) returns a non-nil object, and then +// returns that scope and object. If a valid position pos is provided, +// only objects that were declared at or before pos are considered. +// If no such scope and object exists, the result is (nil, nil). +// +// Note that obj.Parent() may be different from the returned scope if the +// object was inserted into the scope and already had a parent at that +// time (see Insert, below). This can only happen for dot-imported objects +// whose scope is the scope of the package that exported them. +func (s *Scope) LookupParent(name string, pos token.Pos) (*Scope, Object) { + for ; s != nil; s = s.parent { + if obj := s.elems[name]; obj != nil && (!pos.IsValid() || obj.scopePos() <= pos) { + return s, obj + } + } + return nil, nil +} + +// Insert attempts to insert an object obj into scope s. +// If s already contains an alternative object alt with +// the same name, Insert leaves s unchanged and returns alt. +// Otherwise it inserts obj, sets the object's parent scope +// if not already set, and returns nil. +func (s *Scope) Insert(obj Object) Object { + name := obj.Name() + if alt := s.elems[name]; alt != nil { + return alt + } + if s.elems == nil { + s.elems = make(map[string]Object) + } + s.elems[name] = obj + if obj.Parent() == nil { + obj.setParent(s) + } + return nil +} + +// Pos and End describe the scope's source code extent [pos, end). +// The results are guaranteed to be valid only if the type-checked +// AST has complete position information. The extent is undefined +// for Universe and package scopes. +func (s *Scope) Pos() token.Pos { return s.pos } +func (s *Scope) End() token.Pos { return s.end } + +// Contains returns true if pos is within the scope's extent. +// The result is guaranteed to be valid only if the type-checked +// AST has complete position information. +func (s *Scope) Contains(pos token.Pos) bool { + return s.pos <= pos && pos < s.end +} + +// Innermost returns the innermost (child) scope containing +// pos. If pos is not within any scope, the result is nil. +// The result is also nil for the Universe scope. +// The result is guaranteed to be valid only if the type-checked +// AST has complete position information. +func (s *Scope) Innermost(pos token.Pos) *Scope { + // Package scopes do not have extents since they may be + // discontiguous, so iterate over the package's files. + if s.parent == Universe { + for _, s := range s.children { + if inner := s.Innermost(pos); inner != nil { + return inner + } + } + } + + if s.Contains(pos) { + for _, s := range s.children { + if s.Contains(pos) { + return s.Innermost(pos) + } + } + return s + } + return nil +} + +// WriteTo writes a string representation of the scope to w, +// with the scope elements sorted by name. +// The level of indentation is controlled by n >= 0, with +// n == 0 for no indentation. +// If recurse is set, it also writes nested (children) scopes. +func (s *Scope) WriteTo(w io.Writer, n int, recurse bool) { + const ind = ". " + indn := strings.Repeat(ind, n) + + fmt.Fprintf(w, "%s%s scope %p {", indn, s.comment, s) + if len(s.elems) == 0 { + fmt.Fprintf(w, "}\n") + return + } + + fmt.Fprintln(w) + indn1 := indn + ind + for _, name := range s.Names() { + fmt.Fprintf(w, "%s%s\n", indn1, s.elems[name]) + } + + if recurse { + for _, s := range s.children { + fmt.Fprintln(w) + s.WriteTo(w, n+1, recurse) + } + } + + fmt.Fprintf(w, "%s}", indn) +} + +// String returns a string representation of the scope, for debugging. +func (s *Scope) String() string { + var buf bytes.Buffer + s.WriteTo(&buf, 0, false) + return buf.String() +} diff --git a/libgo/go/go/types/selection.go b/libgo/go/go/types/selection.go new file mode 100644 index 00000000000..124e0d39f02 --- /dev/null +++ b/libgo/go/go/types/selection.go @@ -0,0 +1,143 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file implements Selections. + +package types + +import ( + "bytes" + "fmt" +) + +// SelectionKind describes the kind of a selector expression x.f +// (excluding qualified identifiers). +type SelectionKind int + +const ( + FieldVal SelectionKind = iota // x.f is a struct field selector + MethodVal // x.f is a method selector + MethodExpr // x.f is a method expression +) + +// A Selection describes a selector expression x.f. +// For the declarations: +// +// type T struct{ x int; E } +// type E struct{} +// func (e E) m() {} +// var p *T +// +// the following relations exist: +// +// Selector Kind Recv Obj Type Index Indirect +// +// p.x FieldVal T x int {0} true +// p.m MethodVal *T m func (e *T) m() {1, 0} true +// T.m MethodExpr T m func m(_ T) {1, 0} false +// +type Selection struct { + kind SelectionKind + recv Type // type of x + obj Object // object denoted by x.f + index []int // path from x to x.f + indirect bool // set if there was any pointer indirection on the path +} + +// Kind returns the selection kind. +func (s *Selection) Kind() SelectionKind { return s.kind } + +// Recv returns the type of x in x.f. +func (s *Selection) Recv() Type { return s.recv } + +// Obj returns the object denoted by x.f; a *Var for +// a field selection, and a *Func in all other cases. +func (s *Selection) Obj() Object { return s.obj } + +// Type returns the type of x.f, which may be different from the type of f. +// See Selection for more information. +func (s *Selection) Type() Type { + switch s.kind { + case MethodVal: + // The type of x.f is a method with its receiver type set + // to the type of x. + sig := *s.obj.(*Func).typ.(*Signature) + recv := *sig.recv + recv.typ = s.recv + sig.recv = &recv + return &sig + + case MethodExpr: + // The type of x.f is a function (without receiver) + // and an additional first argument with the same type as x. + // TODO(gri) Similar code is already in call.go - factor! + // TODO(gri) Compute this eagerly to avoid allocations. + sig := *s.obj.(*Func).typ.(*Signature) + arg0 := *sig.recv + sig.recv = nil + arg0.typ = s.recv + var params []*Var + if sig.params != nil { + params = sig.params.vars + } + sig.params = NewTuple(append([]*Var{&arg0}, params...)...) + return &sig + } + + // In all other cases, the type of x.f is the type of x. + return s.obj.Type() +} + +// Index describes the path from x to f in x.f. +// The last index entry is the field or method index of the type declaring f; +// either: +// +// 1) the list of declared methods of a named type; or +// 2) the list of methods of an interface type; or +// 3) the list of fields of a struct type. +// +// The earlier index entries are the indices of the embedded fields implicitly +// traversed to get from (the type of) x to f, starting at embedding depth 0. +func (s *Selection) Index() []int { return s.index } + +// Indirect reports whether any pointer indirection was required to get from +// x to f in x.f. +func (s *Selection) Indirect() bool { return s.indirect } + +func (s *Selection) String() string { return SelectionString(s, nil) } + +// SelectionString returns the string form of s. +// The Qualifier controls the printing of +// package-level objects, and may be nil. +// +// Examples: +// "field (T) f int" +// "method (T) f(X) Y" +// "method expr (T) f(X) Y" +// +func SelectionString(s *Selection, qf Qualifier) string { + var k string + switch s.kind { + case FieldVal: + k = "field " + case MethodVal: + k = "method " + case MethodExpr: + k = "method expr " + default: + unreachable() + } + var buf bytes.Buffer + buf.WriteString(k) + buf.WriteByte('(') + WriteType(&buf, s.Recv(), qf) + fmt.Fprintf(&buf, ") %s", s.obj.Name()) + if T := s.Type(); s.kind == FieldVal { + buf.WriteByte(' ') + WriteType(&buf, T, qf) + } else { + WriteSignature(&buf, T.(*Signature), qf) + } + return buf.String() +} diff --git a/libgo/go/go/types/self_test.go b/libgo/go/go/types/self_test.go new file mode 100644 index 00000000000..10ad06fbca1 --- /dev/null +++ b/libgo/go/go/types/self_test.go @@ -0,0 +1,102 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package types_test + +import ( + "flag" + "fmt" + "go/ast" + "go/importer" + "go/parser" + "go/token" + "path/filepath" + "testing" + "time" + + . "go/types" +) + +var benchmark = flag.Bool("b", false, "run benchmarks") + +func TestSelf(t *testing.T) { + fset := token.NewFileSet() + files, err := pkgFiles(fset, ".") + if err != nil { + t.Fatal(err) + } + + conf := Config{Importer: importer.Default()} + _, err = conf.Check("go/types", fset, files, nil) + if err != nil { + // Importing go/constant doesn't work in the + // build dashboard environment. Don't report an error + // for now so that the build remains green. + // TODO(gri) fix this + t.Log(err) // replace w/ t.Fatal eventually + return + } +} + +func TestBenchmark(t *testing.T) { + if !*benchmark { + return + } + + // We're not using testing's benchmarking mechanism directly + // because we want custom output. + + for _, p := range []string{"types", "constant", filepath.Join("internal", "gcimporter")} { + path := filepath.Join("..", p) + runbench(t, path, false) + runbench(t, path, true) + fmt.Println() + } +} + +func runbench(t *testing.T, path string, ignoreFuncBodies bool) { + fset := token.NewFileSet() + files, err := pkgFiles(fset, path) + if err != nil { + t.Fatal(err) + } + + b := testing.Benchmark(func(b *testing.B) { + for i := 0; i < b.N; i++ { + conf := Config{IgnoreFuncBodies: ignoreFuncBodies} + conf.Check(path, fset, files, nil) + } + }) + + // determine line count + lines := 0 + fset.Iterate(func(f *token.File) bool { + lines += f.LineCount() + return true + }) + + d := time.Duration(b.NsPerOp()) + fmt.Printf( + "%s: %s for %d lines (%d lines/s), ignoreFuncBodies = %v\n", + filepath.Base(path), d, lines, int64(float64(lines)/d.Seconds()), ignoreFuncBodies, + ) +} + +func pkgFiles(fset *token.FileSet, path string) ([]*ast.File, error) { + filenames, err := pkgFilenames(path) // from stdlib_test.go + if err != nil { + return nil, err + } + + var files []*ast.File + for _, filename := range filenames { + file, err := parser.ParseFile(fset, filename, nil, 0) + if err != nil { + return nil, err + } + files = append(files, file) + } + + return files, nil +} diff --git a/libgo/go/go/types/sizes.go b/libgo/go/go/types/sizes.go new file mode 100644 index 00000000000..56fb310c294 --- /dev/null +++ b/libgo/go/go/types/sizes.go @@ -0,0 +1,211 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file implements Sizes. + +package types + +// Sizes defines the sizing functions for package unsafe. +type Sizes interface { + // Alignof returns the alignment of a variable of type T. + // Alignof must implement the alignment guarantees required by the spec. + Alignof(T Type) int64 + + // Offsetsof returns the offsets of the given struct fields, in bytes. + // Offsetsof must implement the offset guarantees required by the spec. + Offsetsof(fields []*Var) []int64 + + // Sizeof returns the size of a variable of type T. + // Sizeof must implement the size guarantees required by the spec. + Sizeof(T Type) int64 +} + +// StdSizes is a convenience type for creating commonly used Sizes. +// It makes the following simplifying assumptions: +// +// - The size of explicitly sized basic types (int16, etc.) is the +// specified size. +// - The size of strings and interfaces is 2*WordSize. +// - The size of slices is 3*WordSize. +// - The size of an array of n elements corresponds to the size of +// a struct of n consecutive fields of the array's element type. +// - The size of a struct is the offset of the last field plus that +// field's size. As with all element types, if the struct is used +// in an array its size must first be aligned to a multiple of the +// struct's alignment. +// - All other types have size WordSize. +// - Arrays and structs are aligned per spec definition; all other +// types are naturally aligned with a maximum alignment MaxAlign. +// +// *StdSizes implements Sizes. +// +type StdSizes struct { + WordSize int64 // word size in bytes - must be >= 4 (32bits) + MaxAlign int64 // maximum alignment in bytes - must be >= 1 +} + +func (s *StdSizes) Alignof(T Type) int64 { + // For arrays and structs, alignment is defined in terms + // of alignment of the elements and fields, respectively. + switch t := T.Underlying().(type) { + case *Array: + // spec: "For a variable x of array type: unsafe.Alignof(x) + // is the same as unsafe.Alignof(x[0]), but at least 1." + return s.Alignof(t.elem) + case *Struct: + // spec: "For a variable x of struct type: unsafe.Alignof(x) + // is the largest of the values unsafe.Alignof(x.f) for each + // field f of x, but at least 1." + max := int64(1) + for _, f := range t.fields { + if a := s.Alignof(f.typ); a > max { + max = a + } + } + return max + } + a := s.Sizeof(T) // may be 0 + // spec: "For a variable x of any type: unsafe.Alignof(x) is at least 1." + if a < 1 { + return 1 + } + if a > s.MaxAlign { + return s.MaxAlign + } + return a +} + +func (s *StdSizes) Offsetsof(fields []*Var) []int64 { + offsets := make([]int64, len(fields)) + var o int64 + for i, f := range fields { + a := s.Alignof(f.typ) + o = align(o, a) + offsets[i] = o + o += s.Sizeof(f.typ) + } + return offsets +} + +var basicSizes = [...]byte{ + Bool: 1, + Int8: 1, + Int16: 2, + Int32: 4, + Int64: 8, + Uint8: 1, + Uint16: 2, + Uint32: 4, + Uint64: 8, + Float32: 4, + Float64: 8, + Complex64: 8, + Complex128: 16, +} + +func (s *StdSizes) Sizeof(T Type) int64 { + switch t := T.Underlying().(type) { + case *Basic: + assert(isTyped(T)) + k := t.kind + if int(k) < len(basicSizes) { + if s := basicSizes[k]; s > 0 { + return int64(s) + } + } + if k == String { + return s.WordSize * 2 + } + case *Array: + n := t.len + if n == 0 { + return 0 + } + a := s.Alignof(t.elem) + z := s.Sizeof(t.elem) + return align(z, a)*(n-1) + z + case *Slice: + return s.WordSize * 3 + case *Struct: + n := t.NumFields() + if n == 0 { + return 0 + } + offsets := t.offsets + if t.offsets == nil { + // compute offsets on demand + offsets = s.Offsetsof(t.fields) + t.offsets = offsets + } + return offsets[n-1] + s.Sizeof(t.fields[n-1].typ) + case *Interface: + return s.WordSize * 2 + } + return s.WordSize // catch-all +} + +// stdSizes is used if Config.Sizes == nil. +var stdSizes = StdSizes{8, 8} + +func (conf *Config) alignof(T Type) int64 { + if s := conf.Sizes; s != nil { + if a := s.Alignof(T); a >= 1 { + return a + } + panic("Config.Sizes.Alignof returned an alignment < 1") + } + return stdSizes.Alignof(T) +} + +func (conf *Config) offsetsof(T *Struct) []int64 { + offsets := T.offsets + if offsets == nil && T.NumFields() > 0 { + // compute offsets on demand + if s := conf.Sizes; s != nil { + offsets = s.Offsetsof(T.fields) + // sanity checks + if len(offsets) != T.NumFields() { + panic("Config.Sizes.Offsetsof returned the wrong number of offsets") + } + for _, o := range offsets { + if o < 0 { + panic("Config.Sizes.Offsetsof returned an offset < 0") + } + } + } else { + offsets = stdSizes.Offsetsof(T.fields) + } + T.offsets = offsets + } + return offsets +} + +// offsetof returns the offset of the field specified via +// the index sequence relative to typ. All embedded fields +// must be structs (rather than pointer to structs). +func (conf *Config) offsetof(typ Type, index []int) int64 { + var o int64 + for _, i := range index { + s := typ.Underlying().(*Struct) + o += conf.offsetsof(s)[i] + typ = s.fields[i].typ + } + return o +} + +func (conf *Config) sizeof(T Type) int64 { + if s := conf.Sizes; s != nil { + if z := s.Sizeof(T); z >= 0 { + return z + } + panic("Config.Sizes.Sizeof returned a size < 0") + } + return stdSizes.Sizeof(T) +} + +// align returns the smallest y >= x such that y % a == 0. +func align(x, a int64) int64 { + y := x + a - 1 + return y - y%a +} diff --git a/libgo/go/go/types/stdlib_test.go b/libgo/go/go/types/stdlib_test.go new file mode 100644 index 00000000000..c6c946e976a --- /dev/null +++ b/libgo/go/go/types/stdlib_test.go @@ -0,0 +1,279 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file tests types.Check by using it to +// typecheck the standard library and tests. + +package types_test + +import ( + "fmt" + "go/ast" + "go/build" + "go/importer" + "go/parser" + "go/scanner" + "go/token" + "internal/testenv" + "io/ioutil" + "os" + "path/filepath" + "runtime" + "strings" + "testing" + "time" + + . "go/types" +) + +var ( + pkgCount int // number of packages processed + start time.Time + + // Use the same importer for all std lib tests to + // avoid repeated importing of the same packages. + stdLibImporter = importer.Default() +) + +func TestStdlib(t *testing.T) { + testenv.MustHaveGoBuild(t) + + start = time.Now() + walkDirs(t, filepath.Join(runtime.GOROOT(), "src")) + if testing.Verbose() { + fmt.Println(pkgCount, "packages typechecked in", time.Since(start)) + } +} + +// firstComment returns the contents of the first comment in +// the given file, assuming there's one within the first KB. +func firstComment(filename string) string { + f, err := os.Open(filename) + if err != nil { + return "" + } + defer f.Close() + + var src [1 << 10]byte // read at most 1KB + n, _ := f.Read(src[:]) + + var s scanner.Scanner + s.Init(fset.AddFile("", fset.Base(), n), src[:n], nil, scanner.ScanComments) + for { + _, tok, lit := s.Scan() + switch tok { + case token.COMMENT: + // remove trailing */ of multi-line comment + if lit[1] == '*' { + lit = lit[:len(lit)-2] + } + return strings.TrimSpace(lit[2:]) + case token.EOF: + return "" + } + } +} + +func testTestDir(t *testing.T, path string, ignore ...string) { + files, err := ioutil.ReadDir(path) + if err != nil { + t.Fatal(err) + } + + excluded := make(map[string]bool) + for _, filename := range ignore { + excluded[filename] = true + } + + fset := token.NewFileSet() + for _, f := range files { + // filter directory contents + if f.IsDir() || !strings.HasSuffix(f.Name(), ".go") || excluded[f.Name()] { + continue + } + + // get per-file instructions + expectErrors := false + filename := filepath.Join(path, f.Name()) + if cmd := firstComment(filename); cmd != "" { + switch cmd { + case "skip", "compiledir": + continue // ignore this file + case "errorcheck": + expectErrors = true + } + } + + // parse and type-check file + file, err := parser.ParseFile(fset, filename, nil, 0) + if err == nil { + conf := Config{Importer: stdLibImporter} + _, err = conf.Check(filename, fset, []*ast.File{file}, nil) + } + + if expectErrors { + if err == nil { + t.Errorf("expected errors but found none in %s", filename) + } + } else { + if err != nil { + t.Error(err) + } + } + } +} + +func TestStdTest(t *testing.T) { + testenv.MustHaveGoBuild(t) + + // test/recover4.go is only built for Linux and Darwin. + // TODO(gri) Remove once tests consider +build tags (issue 10370). + if runtime.GOOS != "linux" && runtime.GOOS != "darwin" { + return + } + + testTestDir(t, filepath.Join(runtime.GOROOT(), "test"), + "cmplxdivide.go", // also needs file cmplxdivide1.go - ignore + "sigchld.go", // don't work on Windows; testTestDir should consult build tags + ) +} + +func TestStdFixed(t *testing.T) { + testenv.MustHaveGoBuild(t) + + testTestDir(t, filepath.Join(runtime.GOROOT(), "test", "fixedbugs"), + "bug248.go", "bug302.go", "bug369.go", // complex test instructions - ignore + "bug459.go", // possibly incorrect test - see issue 6703 (pending spec clarification) + "issue3924.go", // possibly incorrect test - see issue 6671 (pending spec clarification) + "issue6889.go", // gc-specific test + "issue7746.go", // large constants - consumes too much memory + "issue11326.go", // large constants + "issue11326b.go", // large constants + ) +} + +func TestStdKen(t *testing.T) { + testenv.MustHaveGoBuild(t) + + testTestDir(t, filepath.Join(runtime.GOROOT(), "test", "ken")) +} + +// Package paths of excluded packages. +var excluded = map[string]bool{ + "builtin": true, +} + +// typecheck typechecks the given package files. +func typecheck(t *testing.T, path string, filenames []string) { + fset := token.NewFileSet() + + // parse package files + var files []*ast.File + for _, filename := range filenames { + file, err := parser.ParseFile(fset, filename, nil, parser.AllErrors) + if err != nil { + // the parser error may be a list of individual errors; report them all + if list, ok := err.(scanner.ErrorList); ok { + for _, err := range list { + t.Error(err) + } + return + } + t.Error(err) + return + } + + if testing.Verbose() { + if len(files) == 0 { + fmt.Println("package", file.Name.Name) + } + fmt.Println("\t", filename) + } + + files = append(files, file) + } + + // typecheck package files + conf := Config{ + Error: func(err error) { t.Error(err) }, + Importer: stdLibImporter, + } + info := Info{Uses: make(map[*ast.Ident]Object)} + conf.Check(path, fset, files, &info) + pkgCount++ + + // Perform checks of API invariants. + + // All Objects have a package, except predeclared ones. + errorError := Universe.Lookup("error").Type().Underlying().(*Interface).ExplicitMethod(0) // (error).Error + for id, obj := range info.Uses { + predeclared := obj == Universe.Lookup(obj.Name()) || obj == errorError + if predeclared == (obj.Pkg() != nil) { + posn := fset.Position(id.Pos()) + if predeclared { + t.Errorf("%s: predeclared object with package: %s", posn, obj) + } else { + t.Errorf("%s: user-defined object without package: %s", posn, obj) + } + } + } +} + +// pkgFilenames returns the list of package filenames for the given directory. +func pkgFilenames(dir string) ([]string, error) { + ctxt := build.Default + ctxt.CgoEnabled = false + pkg, err := ctxt.ImportDir(dir, 0) + if err != nil { + if _, nogo := err.(*build.NoGoError); nogo { + return nil, nil // no *.go files, not an error + } + return nil, err + } + if excluded[pkg.ImportPath] { + return nil, nil + } + var filenames []string + for _, name := range pkg.GoFiles { + filenames = append(filenames, filepath.Join(pkg.Dir, name)) + } + for _, name := range pkg.TestGoFiles { + filenames = append(filenames, filepath.Join(pkg.Dir, name)) + } + return filenames, nil +} + +// Note: Could use filepath.Walk instead of walkDirs but that wouldn't +// necessarily be shorter or clearer after adding the code to +// terminate early for -short tests. + +func walkDirs(t *testing.T, dir string) { + // limit run time for short tests + if testing.Short() && time.Since(start) >= 750*time.Millisecond { + return + } + + fis, err := ioutil.ReadDir(dir) + if err != nil { + t.Error(err) + return + } + + // typecheck package in directory + files, err := pkgFilenames(dir) + if err != nil { + t.Error(err) + return + } + if files != nil { + typecheck(t, dir, files) + } + + // traverse subdirectories, but don't walk into testdata + for _, fi := range fis { + if fi.IsDir() && fi.Name() != "testdata" { + walkDirs(t, filepath.Join(dir, fi.Name())) + } + } +} diff --git a/libgo/go/go/types/stmt.go b/libgo/go/go/types/stmt.go new file mode 100644 index 00000000000..88a1d9b8668 --- /dev/null +++ b/libgo/go/go/types/stmt.go @@ -0,0 +1,744 @@ +// 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 typechecking of statements. + +package types + +import ( + "fmt" + "go/ast" + "go/constant" + "go/token" +) + +func (check *Checker) funcBody(decl *declInfo, name string, sig *Signature, body *ast.BlockStmt) { + if trace { + if name == "" { + name = "" + } + fmt.Printf("--- %s: %s {\n", name, sig) + defer fmt.Println("--- ") + } + + // set function scope extent + sig.scope.pos = body.Pos() + sig.scope.end = body.End() + + // save/restore current context and setup function context + // (and use 0 indentation at function start) + defer func(ctxt context, indent int) { + check.context = ctxt + check.indent = indent + }(check.context, check.indent) + check.context = context{ + decl: decl, + scope: sig.scope, + sig: sig, + } + check.indent = 0 + + check.stmtList(0, body.List) + + if check.hasLabel { + check.labels(body) + } + + if sig.results.Len() > 0 && !check.isTerminating(body, "") { + check.error(body.Rbrace, "missing return") + } + + // spec: "Implementation restriction: A compiler may make it illegal to + // declare a variable inside a function body if the variable is never used." + // (One could check each scope after use, but that distributes this check + // over several places because CloseScope is not always called explicitly.) + check.usage(sig.scope) +} + +func (check *Checker) usage(scope *Scope) { + for _, obj := range scope.elems { + if v, _ := obj.(*Var); v != nil && !v.used { + check.softErrorf(v.pos, "%s declared but not used", v.name) + } + } + for _, scope := range scope.children { + check.usage(scope) + } +} + +// stmtContext is a bitset describing which +// control-flow statements are permissible. +type stmtContext uint + +const ( + breakOk stmtContext = 1 << iota + continueOk + fallthroughOk +) + +func (check *Checker) simpleStmt(s ast.Stmt) { + if s != nil { + check.stmt(0, s) + } +} + +func (check *Checker) stmtList(ctxt stmtContext, list []ast.Stmt) { + ok := ctxt&fallthroughOk != 0 + inner := ctxt &^ fallthroughOk + for i, s := range list { + inner := inner + if ok && i+1 == len(list) { + inner |= fallthroughOk + } + check.stmt(inner, s) + } +} + +func (check *Checker) multipleDefaults(list []ast.Stmt) { + var first ast.Stmt + for _, s := range list { + var d ast.Stmt + switch c := s.(type) { + case *ast.CaseClause: + if len(c.List) == 0 { + d = s + } + case *ast.CommClause: + if c.Comm == nil { + d = s + } + default: + check.invalidAST(s.Pos(), "case/communication clause expected") + } + if d != nil { + if first != nil { + check.errorf(d.Pos(), "multiple defaults (first at %s)", first.Pos()) + } else { + first = d + } + } + } +} + +func (check *Checker) openScope(s ast.Stmt, comment string) { + scope := NewScope(check.scope, s.Pos(), s.End(), comment) + check.recordScope(s, scope) + check.scope = scope +} + +func (check *Checker) closeScope() { + check.scope = check.scope.Parent() +} + +func assignOp(op token.Token) token.Token { + // token_test.go verifies the token ordering this function relies on + if token.ADD_ASSIGN <= op && op <= token.AND_NOT_ASSIGN { + return op + (token.ADD - token.ADD_ASSIGN) + } + return token.ILLEGAL +} + +func (check *Checker) suspendedCall(keyword string, call *ast.CallExpr) { + var x operand + var msg string + switch check.rawExpr(&x, call, nil) { + case conversion: + msg = "requires function call, not conversion" + case expression: + msg = "discards result of" + case statement: + return + default: + unreachable() + } + check.errorf(x.pos(), "%s %s %s", keyword, msg, &x) +} + +func (check *Checker) caseValues(x operand /* copy argument (not *operand!) */, values []ast.Expr) { + // No duplicate checking for now. See issue 4524. + for _, e := range values { + var y operand + check.expr(&y, e) + if y.mode == invalid { + return + } + // TODO(gri) The convertUntyped call pair below appears in other places. Factor! + // Order matters: By comparing y against x, error positions are at the case values. + check.convertUntyped(&y, x.typ) + if y.mode == invalid { + return + } + check.convertUntyped(&x, y.typ) + if x.mode == invalid { + return + } + check.comparison(&y, &x, token.EQL) + } +} + +func (check *Checker) caseTypes(x *operand, xtyp *Interface, types []ast.Expr, seen map[Type]token.Pos) (T Type) { +L: + for _, e := range types { + T = check.typOrNil(e) + if T == Typ[Invalid] { + continue + } + // complain about duplicate types + // TODO(gri) use a type hash to avoid quadratic algorithm + for t, pos := range seen { + if T == nil && t == nil || T != nil && t != nil && Identical(T, t) { + // talk about "case" rather than "type" because of nil case + check.error(e.Pos(), "duplicate case in type switch") + check.errorf(pos, "\tprevious case %s", T) // secondary error, \t indented + continue L + } + } + seen[T] = e.Pos() + if T != nil { + check.typeAssertion(e.Pos(), x, xtyp, T) + } + } + return +} + +// stmt typechecks statement s. +func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) { + // statements cannot use iota in general + // (constant declarations set it explicitly) + assert(check.iota == nil) + + // statements must end with the same top scope as they started with + if debug { + defer func(scope *Scope) { + // don't check if code is panicking + if p := recover(); p != nil { + panic(p) + } + assert(scope == check.scope) + }(check.scope) + } + + inner := ctxt &^ fallthroughOk + switch s := s.(type) { + case *ast.BadStmt, *ast.EmptyStmt: + // ignore + + case *ast.DeclStmt: + check.declStmt(s.Decl) + + case *ast.LabeledStmt: + check.hasLabel = true + check.stmt(ctxt, s.Stmt) + + case *ast.ExprStmt: + // spec: "With the exception of specific built-in functions, + // function and method calls and receive operations can appear + // in statement context. Such statements may be parenthesized." + var x operand + kind := check.rawExpr(&x, s.X, nil) + var msg string + switch x.mode { + default: + if kind == statement { + return + } + msg = "is not used" + case builtin: + msg = "must be called" + case typexpr: + msg = "is not an expression" + } + check.errorf(x.pos(), "%s %s", &x, msg) + + case *ast.SendStmt: + var ch, x operand + check.expr(&ch, s.Chan) + check.expr(&x, s.Value) + if ch.mode == invalid || x.mode == invalid { + return + } + if tch, ok := ch.typ.Underlying().(*Chan); !ok || tch.dir == RecvOnly || !check.assignment(&x, tch.elem) { + if x.mode != invalid { + check.invalidOp(ch.pos(), "cannot send %s to channel %s", &x, &ch) + } + } + + case *ast.IncDecStmt: + var op token.Token + switch s.Tok { + case token.INC: + op = token.ADD + case token.DEC: + op = token.SUB + default: + check.invalidAST(s.TokPos, "unknown inc/dec operation %s", s.Tok) + return + } + var x operand + Y := &ast.BasicLit{ValuePos: s.X.Pos(), Kind: token.INT, Value: "1"} // use x's position + check.binary(&x, nil, s.X, Y, op) + if x.mode == invalid { + return + } + check.assignVar(s.X, &x) + + case *ast.AssignStmt: + switch s.Tok { + case token.ASSIGN, token.DEFINE: + if len(s.Lhs) == 0 { + check.invalidAST(s.Pos(), "missing lhs in assignment") + return + } + if s.Tok == token.DEFINE { + check.shortVarDecl(s.TokPos, s.Lhs, s.Rhs) + } else { + // regular assignment + check.assignVars(s.Lhs, s.Rhs) + } + + default: + // assignment operations + if len(s.Lhs) != 1 || len(s.Rhs) != 1 { + check.errorf(s.TokPos, "assignment operation %s requires single-valued expressions", s.Tok) + return + } + op := assignOp(s.Tok) + if op == token.ILLEGAL { + check.invalidAST(s.TokPos, "unknown assignment operation %s", s.Tok) + return + } + var x operand + check.binary(&x, nil, s.Lhs[0], s.Rhs[0], op) + if x.mode == invalid { + return + } + check.assignVar(s.Lhs[0], &x) + } + + case *ast.GoStmt: + check.suspendedCall("go", s.Call) + + case *ast.DeferStmt: + check.suspendedCall("defer", s.Call) + + case *ast.ReturnStmt: + res := check.sig.results + if res.Len() > 0 { + // function returns results + // (if one, say the first, result parameter is named, all of them are named) + if len(s.Results) == 0 && res.vars[0].name != "" { + // spec: "Implementation restriction: A compiler may disallow an empty expression + // list in a "return" statement if a different entity (constant, type, or variable) + // with the same name as a result parameter is in scope at the place of the return." + for _, obj := range res.vars { + if _, alt := check.scope.LookupParent(obj.name, check.pos); alt != nil && alt != obj { + check.errorf(s.Pos(), "result parameter %s not in scope at return", obj.name) + check.errorf(alt.Pos(), "\tinner declaration of %s", obj) + // ok to continue + } + } + } else { + // return has results or result parameters are unnamed + check.initVars(res.vars, s.Results, s.Return) + } + } else if len(s.Results) > 0 { + check.error(s.Results[0].Pos(), "no result values expected") + check.use(s.Results...) + } + + case *ast.BranchStmt: + if s.Label != nil { + check.hasLabel = true + return // checked in 2nd pass (check.labels) + } + switch s.Tok { + case token.BREAK: + if ctxt&breakOk == 0 { + check.error(s.Pos(), "break not in for, switch, or select statement") + } + case token.CONTINUE: + if ctxt&continueOk == 0 { + check.error(s.Pos(), "continue not in for statement") + } + case token.FALLTHROUGH: + if ctxt&fallthroughOk == 0 { + check.error(s.Pos(), "fallthrough statement out of place") + } + default: + check.invalidAST(s.Pos(), "branch statement: %s", s.Tok) + } + + case *ast.BlockStmt: + check.openScope(s, "block") + defer check.closeScope() + + check.stmtList(inner, s.List) + + case *ast.IfStmt: + check.openScope(s, "if") + defer check.closeScope() + + check.simpleStmt(s.Init) + var x operand + check.expr(&x, s.Cond) + if x.mode != invalid && !isBoolean(x.typ) { + check.error(s.Cond.Pos(), "non-boolean condition in if statement") + } + check.stmt(inner, s.Body) + if s.Else != nil { + check.stmt(inner, s.Else) + } + + case *ast.SwitchStmt: + inner |= breakOk + check.openScope(s, "switch") + defer check.closeScope() + + check.simpleStmt(s.Init) + var x operand + if s.Tag != nil { + check.expr(&x, s.Tag) + } else { + // spec: "A missing switch expression is + // equivalent to the boolean value true." + x.mode = constant_ + x.typ = Typ[Bool] + x.val = constant.MakeBool(true) + x.expr = &ast.Ident{NamePos: s.Body.Lbrace, Name: "true"} + } + + check.multipleDefaults(s.Body.List) + + for i, c := range s.Body.List { + clause, _ := c.(*ast.CaseClause) + if clause == nil { + check.invalidAST(c.Pos(), "incorrect expression switch case") + continue + } + if x.mode != invalid { + check.caseValues(x, clause.List) + } + check.openScope(clause, "case") + inner := inner + if i+1 < len(s.Body.List) { + inner |= fallthroughOk + } + check.stmtList(inner, clause.Body) + check.closeScope() + } + + case *ast.TypeSwitchStmt: + inner |= breakOk + check.openScope(s, "type switch") + defer check.closeScope() + + check.simpleStmt(s.Init) + + // A type switch guard must be of the form: + // + // TypeSwitchGuard = [ identifier ":=" ] PrimaryExpr "." "(" "type" ")" . + // + // The parser is checking syntactic correctness; + // remaining syntactic errors are considered AST errors here. + // TODO(gri) better factoring of error handling (invalid ASTs) + // + var lhs *ast.Ident // lhs identifier or nil + var rhs ast.Expr + switch guard := s.Assign.(type) { + case *ast.ExprStmt: + rhs = guard.X + case *ast.AssignStmt: + if len(guard.Lhs) != 1 || guard.Tok != token.DEFINE || len(guard.Rhs) != 1 { + check.invalidAST(s.Pos(), "incorrect form of type switch guard") + return + } + + lhs, _ = guard.Lhs[0].(*ast.Ident) + if lhs == nil { + check.invalidAST(s.Pos(), "incorrect form of type switch guard") + return + } + + if lhs.Name == "_" { + // _ := x.(type) is an invalid short variable declaration + check.softErrorf(lhs.Pos(), "no new variable on left side of :=") + lhs = nil // avoid declared but not used error below + } else { + check.recordDef(lhs, nil) // lhs variable is implicitly declared in each cause clause + } + + rhs = guard.Rhs[0] + + default: + check.invalidAST(s.Pos(), "incorrect form of type switch guard") + return + } + + // rhs must be of the form: expr.(type) and expr must be an interface + expr, _ := rhs.(*ast.TypeAssertExpr) + if expr == nil || expr.Type != nil { + check.invalidAST(s.Pos(), "incorrect form of type switch guard") + return + } + var x operand + check.expr(&x, expr.X) + if x.mode == invalid { + return + } + xtyp, _ := x.typ.Underlying().(*Interface) + if xtyp == nil { + check.errorf(x.pos(), "%s is not an interface", &x) + return + } + + check.multipleDefaults(s.Body.List) + + var lhsVars []*Var // list of implicitly declared lhs variables + seen := make(map[Type]token.Pos) // map of seen types to positions + for _, s := range s.Body.List { + clause, _ := s.(*ast.CaseClause) + if clause == nil { + check.invalidAST(s.Pos(), "incorrect type switch case") + continue + } + // Check each type in this type switch case. + T := check.caseTypes(&x, xtyp, clause.List, seen) + check.openScope(clause, "case") + // If lhs exists, declare a corresponding variable in the case-local scope. + if lhs != nil { + // spec: "The TypeSwitchGuard may include a short variable declaration. + // When that form is used, the variable is declared at the beginning of + // the implicit block in each clause. In clauses with a case listing + // exactly one type, the variable has that type; otherwise, the variable + // has the type of the expression in the TypeSwitchGuard." + if len(clause.List) != 1 || T == nil { + T = x.typ + } + obj := NewVar(lhs.Pos(), check.pkg, lhs.Name, T) + scopePos := clause.End() + if len(clause.Body) > 0 { + scopePos = clause.Body[0].Pos() + } + check.declare(check.scope, nil, obj, scopePos) + check.recordImplicit(clause, obj) + // For the "declared but not used" error, all lhs variables act as + // one; i.e., if any one of them is 'used', all of them are 'used'. + // Collect them for later analysis. + lhsVars = append(lhsVars, obj) + } + check.stmtList(inner, clause.Body) + check.closeScope() + } + + // If lhs exists, we must have at least one lhs variable that was used. + if lhs != nil { + var used bool + for _, v := range lhsVars { + if v.used { + used = true + } + v.used = true // avoid usage error when checking entire function + } + if !used { + check.softErrorf(lhs.Pos(), "%s declared but not used", lhs.Name) + } + } + + case *ast.SelectStmt: + inner |= breakOk + + check.multipleDefaults(s.Body.List) + + for _, s := range s.Body.List { + clause, _ := s.(*ast.CommClause) + if clause == nil { + continue // error reported before + } + + // clause.Comm must be a SendStmt, RecvStmt, or default case + valid := false + var rhs ast.Expr // rhs of RecvStmt, or nil + switch s := clause.Comm.(type) { + case nil, *ast.SendStmt: + valid = true + case *ast.AssignStmt: + if len(s.Rhs) == 1 { + rhs = s.Rhs[0] + } + case *ast.ExprStmt: + rhs = s.X + } + + // if present, rhs must be a receive operation + if rhs != nil { + if x, _ := unparen(rhs).(*ast.UnaryExpr); x != nil && x.Op == token.ARROW { + valid = true + } + } + + if !valid { + check.error(clause.Comm.Pos(), "select case must be send or receive (possibly with assignment)") + continue + } + + check.openScope(s, "case") + if clause.Comm != nil { + check.stmt(inner, clause.Comm) + } + check.stmtList(inner, clause.Body) + check.closeScope() + } + + case *ast.ForStmt: + inner |= breakOk | continueOk + check.openScope(s, "for") + defer check.closeScope() + + check.simpleStmt(s.Init) + if s.Cond != nil { + var x operand + check.expr(&x, s.Cond) + if x.mode != invalid && !isBoolean(x.typ) { + check.error(s.Cond.Pos(), "non-boolean condition in for statement") + } + } + check.simpleStmt(s.Post) + // spec: "The init statement may be a short variable + // declaration, but the post statement must not." + if s, _ := s.Post.(*ast.AssignStmt); s != nil && s.Tok == token.DEFINE { + check.softErrorf(s.Pos(), "cannot declare in post statement") + check.use(s.Lhs...) // avoid follow-up errors + } + check.stmt(inner, s.Body) + + case *ast.RangeStmt: + inner |= breakOk | continueOk + check.openScope(s, "for") + defer check.closeScope() + + // check expression to iterate over + var x operand + check.expr(&x, s.X) + + // determine key/value types + var key, val Type + if x.mode != invalid { + switch typ := x.typ.Underlying().(type) { + case *Basic: + if isString(typ) { + key = Typ[Int] + val = universeRune // use 'rune' name + } + case *Array: + key = Typ[Int] + val = typ.elem + case *Slice: + key = Typ[Int] + val = typ.elem + case *Pointer: + if typ, _ := typ.base.Underlying().(*Array); typ != nil { + key = Typ[Int] + val = typ.elem + } + case *Map: + key = typ.key + val = typ.elem + case *Chan: + key = typ.elem + val = Typ[Invalid] + if typ.dir == SendOnly { + check.errorf(x.pos(), "cannot range over send-only channel %s", &x) + // ok to continue + } + if s.Value != nil { + check.errorf(s.Value.Pos(), "iteration over %s permits only one iteration variable", &x) + // ok to continue + } + } + } + + if key == nil { + check.errorf(x.pos(), "cannot range over %s", &x) + // ok to continue + } + + // check assignment to/declaration of iteration variables + // (irregular assignment, cannot easily map to existing assignment checks) + + // lhs expressions and initialization value (rhs) types + lhs := [2]ast.Expr{s.Key, s.Value} + rhs := [2]Type{key, val} // key, val may be nil + + if s.Tok == token.DEFINE { + // short variable declaration; variable scope starts after the range clause + // (the for loop opens a new scope, so variables on the lhs never redeclare + // previously declared variables) + var vars []*Var + for i, lhs := range lhs { + if lhs == nil { + continue + } + + // determine lhs variable + var obj *Var + if ident, _ := lhs.(*ast.Ident); ident != nil { + // declare new variable + name := ident.Name + obj = NewVar(ident.Pos(), check.pkg, name, nil) + check.recordDef(ident, obj) + // _ variables don't count as new variables + if name != "_" { + vars = append(vars, obj) + } + } else { + check.errorf(lhs.Pos(), "cannot declare %s", lhs) + obj = NewVar(lhs.Pos(), check.pkg, "_", nil) // dummy variable + } + + // initialize lhs variable + if typ := rhs[i]; typ != nil { + x.mode = value + x.expr = lhs // we don't have a better rhs expression to use here + x.typ = typ + check.initVar(obj, &x, false) + } else { + obj.typ = Typ[Invalid] + obj.used = true // don't complain about unused variable + } + } + + // declare variables + if len(vars) > 0 { + for _, obj := range vars { + // spec: "The scope of a constant or variable identifier declared inside + // a function begins at the end of the ConstSpec or VarSpec (ShortVarDecl + // for short variable declarations) and ends at the end of the innermost + // containing block." + scopePos := s.End() + check.declare(check.scope, nil /* recordDef already called */, obj, scopePos) + } + } else { + check.error(s.TokPos, "no new variables on left side of :=") + } + } else { + // ordinary assignment + for i, lhs := range lhs { + if lhs == nil { + continue + } + if typ := rhs[i]; typ != nil { + x.mode = value + x.expr = lhs // we don't have a better rhs expression to use here + x.typ = typ + check.assignVar(lhs, &x) + } + } + } + + check.stmt(inner, s.Body) + + default: + check.error(s.Pos(), "invalid statement") + } +} diff --git a/libgo/go/go/types/token_test.go b/libgo/go/go/types/token_test.go new file mode 100644 index 00000000000..705bb295a16 --- /dev/null +++ b/libgo/go/go/types/token_test.go @@ -0,0 +1,47 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file checks invariants of token.Token ordering that we rely on +// since package go/token doesn't provide any guarantees at the moment. + +package types + +import ( + "go/token" + "testing" +) + +var assignOps = map[token.Token]token.Token{ + token.ADD_ASSIGN: token.ADD, + token.SUB_ASSIGN: token.SUB, + token.MUL_ASSIGN: token.MUL, + token.QUO_ASSIGN: token.QUO, + token.REM_ASSIGN: token.REM, + token.AND_ASSIGN: token.AND, + token.OR_ASSIGN: token.OR, + token.XOR_ASSIGN: token.XOR, + token.SHL_ASSIGN: token.SHL, + token.SHR_ASSIGN: token.SHR, + token.AND_NOT_ASSIGN: token.AND_NOT, +} + +func TestZeroTok(t *testing.T) { + // zero value for token.Token must be token.ILLEGAL + var zero token.Token + if token.ILLEGAL != zero { + t.Errorf("%s == %d; want 0", token.ILLEGAL, zero) + } +} + +func TestAssignOp(t *testing.T) { + // there are fewer than 256 tokens + for i := 0; i < 256; i++ { + tok := token.Token(i) + got := assignOp(tok) + want := assignOps[tok] + if got != want { + t.Errorf("for assignOp(%s): got %s; want %s", tok, got, want) + } + } +} diff --git a/libgo/go/go/types/type.go b/libgo/go/go/types/type.go new file mode 100644 index 00000000000..1df8b45b285 --- /dev/null +++ b/libgo/go/go/types/type.go @@ -0,0 +1,454 @@ +// 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 types + +import "sort" + +// TODO(gri) Revisit factory functions - make sure they have all relevant parameters. + +// A Type represents a type of Go. +// All types implement the Type interface. +type Type interface { + // Underlying returns the underlying type of a type. + Underlying() Type + + // String returns a string representation of a type. + String() string +} + +// BasicKind describes the kind of basic type. +type BasicKind int + +const ( + Invalid BasicKind = iota // type is invalid + + // predeclared types + Bool + Int + Int8 + Int16 + Int32 + Int64 + Uint + Uint8 + Uint16 + Uint32 + Uint64 + Uintptr + Float32 + Float64 + Complex64 + Complex128 + String + UnsafePointer + + // types for untyped values + UntypedBool + UntypedInt + UntypedRune + UntypedFloat + UntypedComplex + UntypedString + UntypedNil + + // aliases + Byte = Uint8 + Rune = Int32 +) + +// BasicInfo is a set of flags describing properties of a basic type. +type BasicInfo int + +// Properties of basic types. +const ( + IsBoolean BasicInfo = 1 << iota + IsInteger + IsUnsigned + IsFloat + IsComplex + IsString + IsUntyped + + IsOrdered = IsInteger | IsFloat | IsString + IsNumeric = IsInteger | IsFloat | IsComplex + IsConstType = IsBoolean | IsNumeric | IsString +) + +// A Basic represents a basic type. +type Basic struct { + kind BasicKind + info BasicInfo + name string +} + +// Kind returns the kind of basic type b. +func (b *Basic) Kind() BasicKind { return b.kind } + +// Info returns information about properties of basic type b. +func (b *Basic) Info() BasicInfo { return b.info } + +// Name returns the name of basic type b. +func (b *Basic) Name() string { return b.name } + +// An Array represents an array type. +type Array struct { + len int64 + elem Type +} + +// NewArray returns a new array type for the given element type and length. +func NewArray(elem Type, len int64) *Array { return &Array{len, elem} } + +// Len returns the length of array a. +func (a *Array) Len() int64 { return a.len } + +// Elem returns element type of array a. +func (a *Array) Elem() Type { return a.elem } + +// A Slice represents a slice type. +type Slice struct { + elem Type +} + +// NewSlice returns a new slice type for the given element type. +func NewSlice(elem Type) *Slice { return &Slice{elem} } + +// Elem returns the element type of slice s. +func (s *Slice) Elem() Type { return s.elem } + +// A Struct represents a struct type. +type Struct struct { + fields []*Var + tags []string // field tags; nil if there are no tags + // TODO(gri) access to offsets is not threadsafe - fix this + offsets []int64 // field offsets in bytes, lazily initialized +} + +// NewStruct returns a new struct with the given fields and corresponding field tags. +// If a field with index i has a tag, tags[i] must be that tag, but len(tags) may be +// only as long as required to hold the tag with the largest index i. Consequently, +// if no field has a tag, tags may be nil. +func NewStruct(fields []*Var, tags []string) *Struct { + var fset objset + for _, f := range fields { + if f.name != "_" && fset.insert(f) != nil { + panic("multiple fields with the same name") + } + } + if len(tags) > len(fields) { + panic("more tags than fields") + } + return &Struct{fields: fields, tags: tags} +} + +// NumFields returns the number of fields in the struct (including blank and anonymous fields). +func (s *Struct) NumFields() int { return len(s.fields) } + +// Field returns the i'th field for 0 <= i < NumFields(). +func (s *Struct) Field(i int) *Var { return s.fields[i] } + +// Tag returns the i'th field tag for 0 <= i < NumFields(). +func (s *Struct) Tag(i int) string { + if i < len(s.tags) { + return s.tags[i] + } + return "" +} + +// A Pointer represents a pointer type. +type Pointer struct { + base Type // element type +} + +// NewPointer returns a new pointer type for the given element (base) type. +func NewPointer(elem Type) *Pointer { return &Pointer{base: elem} } + +// Elem returns the element type for the given pointer p. +func (p *Pointer) Elem() Type { return p.base } + +// A Tuple represents an ordered list of variables; a nil *Tuple is a valid (empty) tuple. +// Tuples are used as components of signatures and to represent the type of multiple +// assignments; they are not first class types of Go. +type Tuple struct { + vars []*Var +} + +// NewTuple returns a new tuple for the given variables. +func NewTuple(x ...*Var) *Tuple { + if len(x) > 0 { + return &Tuple{x} + } + return nil +} + +// Len returns the number variables of tuple t. +func (t *Tuple) Len() int { + if t != nil { + return len(t.vars) + } + return 0 +} + +// At returns the i'th variable of tuple t. +func (t *Tuple) At(i int) *Var { return t.vars[i] } + +// A Signature represents a (non-builtin) function or method type. +type Signature struct { + // We need to keep the scope in Signature (rather than passing it around + // and store it in the Func Object) because when type-checking a function + // literal we call the general type checker which returns a general Type. + // We then unpack the *Signature and use the scope for the literal body. + scope *Scope // function scope, present for package-local signatures + recv *Var // nil if not a method + params *Tuple // (incoming) parameters from left to right; or nil + results *Tuple // (outgoing) results from left to right; or nil + variadic bool // true if the last parameter's type is of the form ...T (or string, for append built-in only) +} + +// NewSignature returns a new function type for the given receiver, parameters, +// and results, either of which may be nil. If variadic is set, the function +// is variadic, it must have at least one parameter, and the last parameter +// must be of unnamed slice type. +func NewSignature(recv *Var, params, results *Tuple, variadic bool) *Signature { + if variadic { + n := params.Len() + if n == 0 { + panic("types.NewSignature: variadic function must have at least one parameter") + } + if _, ok := params.At(n - 1).typ.(*Slice); !ok { + panic("types.NewSignature: variadic parameter must be of unnamed slice type") + } + } + return &Signature{nil, recv, params, results, variadic} +} + +// Recv returns the receiver of signature s (if a method), or nil if a +// function. +// +// For an abstract method, Recv returns the enclosing interface either +// as a *Named or an *Interface. Due to embedding, an interface may +// contain methods whose receiver type is a different interface. +func (s *Signature) Recv() *Var { return s.recv } + +// Params returns the parameters of signature s, or nil. +func (s *Signature) Params() *Tuple { return s.params } + +// Results returns the results of signature s, or nil. +func (s *Signature) Results() *Tuple { return s.results } + +// Variadic reports whether the signature s is variadic. +func (s *Signature) Variadic() bool { return s.variadic } + +// An Interface represents an interface type. +type Interface struct { + methods []*Func // ordered list of explicitly declared methods + embeddeds []*Named // ordered list of explicitly embedded types + + allMethods []*Func // ordered list of methods declared with or embedded in this interface (TODO(gri): replace with mset) +} + +// NewInterface returns a new interface for the given methods and embedded types. +func NewInterface(methods []*Func, embeddeds []*Named) *Interface { + typ := new(Interface) + + var mset objset + for _, m := range methods { + if mset.insert(m) != nil { + panic("multiple methods with the same name") + } + // set receiver + // TODO(gri) Ideally, we should use a named type here instead of + // typ, for less verbose printing of interface method signatures. + m.typ.(*Signature).recv = NewVar(m.pos, m.pkg, "", typ) + } + sort.Sort(byUniqueMethodName(methods)) + + if embeddeds == nil { + sort.Sort(byUniqueTypeName(embeddeds)) + } + + typ.methods = methods + typ.embeddeds = embeddeds + return typ +} + +// NumExplicitMethods returns the number of explicitly declared methods of interface t. +func (t *Interface) NumExplicitMethods() int { return len(t.methods) } + +// ExplicitMethod returns the i'th explicitly declared method of interface t for 0 <= i < t.NumExplicitMethods(). +// The methods are ordered by their unique Id. +func (t *Interface) ExplicitMethod(i int) *Func { return t.methods[i] } + +// NumEmbeddeds returns the number of embedded types in interface t. +func (t *Interface) NumEmbeddeds() int { return len(t.embeddeds) } + +// Embedded returns the i'th embedded type of interface t for 0 <= i < t.NumEmbeddeds(). +// The types are ordered by the corresponding TypeName's unique Id. +func (t *Interface) Embedded(i int) *Named { return t.embeddeds[i] } + +// NumMethods returns the total number of methods of interface t. +func (t *Interface) NumMethods() int { return len(t.allMethods) } + +// Method returns the i'th method of interface t for 0 <= i < t.NumMethods(). +// The methods are ordered by their unique Id. +func (t *Interface) Method(i int) *Func { return t.allMethods[i] } + +// Empty returns true if t is the empty interface. +func (t *Interface) Empty() bool { return len(t.allMethods) == 0 } + +// Complete computes the interface's method set. It must be called by users of +// NewInterface after the interface's embedded types are fully defined and +// before using the interface type in any way other than to form other types. +// Complete returns the receiver. +func (t *Interface) Complete() *Interface { + if t.allMethods != nil { + return t + } + + var allMethods []*Func + if t.embeddeds == nil { + if t.methods == nil { + allMethods = make([]*Func, 0, 1) + } else { + allMethods = t.methods + } + } else { + allMethods = append(allMethods, t.methods...) + for _, et := range t.embeddeds { + it := et.Underlying().(*Interface) + it.Complete() + for _, tm := range it.allMethods { + // Make a copy of the method and adjust its receiver type. + newm := *tm + newmtyp := *tm.typ.(*Signature) + newm.typ = &newmtyp + newmtyp.recv = NewVar(newm.pos, newm.pkg, "", t) + allMethods = append(allMethods, &newm) + } + } + sort.Sort(byUniqueMethodName(allMethods)) + } + t.allMethods = allMethods + + return t +} + +// A Map represents a map type. +type Map struct { + key, elem Type +} + +// NewMap returns a new map for the given key and element types. +func NewMap(key, elem Type) *Map { + return &Map{key, elem} +} + +// Key returns the key type of map m. +func (m *Map) Key() Type { return m.key } + +// Elem returns the element type of map m. +func (m *Map) Elem() Type { return m.elem } + +// A Chan represents a channel type. +type Chan struct { + dir ChanDir + elem Type +} + +// A ChanDir value indicates a channel direction. +type ChanDir int + +// The direction of a channel is indicated by one of the following constants. +const ( + SendRecv ChanDir = iota + SendOnly + RecvOnly +) + +// NewChan returns a new channel type for the given direction and element type. +func NewChan(dir ChanDir, elem Type) *Chan { + return &Chan{dir, elem} +} + +// Dir returns the direction of channel c. +func (c *Chan) Dir() ChanDir { return c.dir } + +// Elem returns the element type of channel c. +func (c *Chan) Elem() Type { return c.elem } + +// A Named represents a named type. +type Named struct { + obj *TypeName // corresponding declared object + underlying Type // possibly a *Named during setup; never a *Named once set up completely + methods []*Func // methods declared for this type (not the method set of this type) +} + +// NewNamed returns a new named type for the given type name, underlying type, and associated methods. +// The underlying type must not be a *Named. +func NewNamed(obj *TypeName, underlying Type, methods []*Func) *Named { + if _, ok := underlying.(*Named); ok { + panic("types.NewNamed: underlying type must not be *Named") + } + typ := &Named{obj: obj, underlying: underlying, methods: methods} + if obj.typ == nil { + obj.typ = typ + } + return typ +} + +// TypeName returns the type name for the named type t. +func (t *Named) Obj() *TypeName { return t.obj } + +// NumMethods returns the number of explicit methods whose receiver is named type t. +func (t *Named) NumMethods() int { return len(t.methods) } + +// Method returns the i'th method of named type t for 0 <= i < t.NumMethods(). +func (t *Named) Method(i int) *Func { return t.methods[i] } + +// SetUnderlying sets the underlying type and marks t as complete. +// TODO(gri) determine if there's a better solution rather than providing this function +func (t *Named) SetUnderlying(underlying Type) { + if underlying == nil { + panic("types.Named.SetUnderlying: underlying type must not be nil") + } + if _, ok := underlying.(*Named); ok { + panic("types.Named.SetUnderlying: underlying type must not be *Named") + } + t.underlying = underlying +} + +// AddMethod adds method m unless it is already in the method list. +// TODO(gri) find a better solution instead of providing this function +func (t *Named) AddMethod(m *Func) { + if i, _ := lookupMethod(t.methods, m.pkg, m.name); i < 0 { + t.methods = append(t.methods, m) + } +} + +// Implementations for Type methods. + +func (t *Basic) Underlying() Type { return t } +func (t *Array) Underlying() Type { return t } +func (t *Slice) Underlying() Type { return t } +func (t *Struct) Underlying() Type { return t } +func (t *Pointer) Underlying() Type { return t } +func (t *Tuple) Underlying() Type { return t } +func (t *Signature) Underlying() Type { return t } +func (t *Interface) Underlying() Type { return t } +func (t *Map) Underlying() Type { return t } +func (t *Chan) Underlying() Type { return t } +func (t *Named) Underlying() Type { return t.underlying } + +func (t *Basic) String() string { return TypeString(t, nil) } +func (t *Array) String() string { return TypeString(t, nil) } +func (t *Slice) String() string { return TypeString(t, nil) } +func (t *Struct) String() string { return TypeString(t, nil) } +func (t *Pointer) String() string { return TypeString(t, nil) } +func (t *Tuple) String() string { return TypeString(t, nil) } +func (t *Signature) String() string { return TypeString(t, nil) } +func (t *Interface) String() string { return TypeString(t, nil) } +func (t *Map) String() string { return TypeString(t, nil) } +func (t *Chan) String() string { return TypeString(t, nil) } +func (t *Named) String() string { return TypeString(t, nil) } diff --git a/libgo/go/go/types/typestring.go b/libgo/go/go/types/typestring.go new file mode 100644 index 00000000000..bd62f4dc229 --- /dev/null +++ b/libgo/go/go/types/typestring.go @@ -0,0 +1,296 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file implements printing of types. + +package types + +import ( + "bytes" + "fmt" +) + +// A Qualifier controls how named package-level objects are printed in +// calls to TypeString, ObjectString, and SelectionString. +// +// These three formatting routines call the Qualifier for each +// package-level object O, and if the Qualifier returns a non-empty +// string p, the object is printed in the form p.O. +// If it returns an empty string, only the object name O is printed. +// +// Using a nil Qualifier is equivalent to using (*Package).Path: the +// object is qualified by the import path, e.g., "encoding/json.Marshal". +// +type Qualifier func(*Package) string + +// RelativeTo(pkg) returns a Qualifier that fully qualifies members of +// all packages other than pkg. +func RelativeTo(pkg *Package) Qualifier { + if pkg == nil { + return nil + } + return func(other *Package) string { + if pkg == other { + return "" // same package; unqualified + } + return other.Path() + } +} + +// If gcCompatibilityMode is set, printing of types is modified +// to match the representation of some types in the gc compiler: +// +// - byte and rune lose their alias name and simply stand for +// uint8 and int32 respectively +// - embedded interfaces get flattened (the embedding info is lost, +// and certain recursive interface types cannot be printed anymore) +// +// This makes it easier to compare packages computed with the type- +// checker vs packages imported from gc export data. +// +// Caution: This flag affects all uses of WriteType, globally. +// It is only provided for testing in conjunction with +// gc-generated data. +// +// This flag is exported in the x/tools/go/types package. We don't +// need it at the moment in the std repo and so we don't export it +// anymore. We should eventually try to remove it altogether. +var gcCompatibilityMode bool + +// TypeString returns the string representation of typ. +// The Qualifier controls the printing of +// package-level objects, and may be nil. +func TypeString(typ Type, qf Qualifier) string { + var buf bytes.Buffer + WriteType(&buf, typ, qf) + return buf.String() +} + +// WriteType writes the string representation of typ to buf. +// The Qualifier controls the printing of +// package-level objects, and may be nil. +func WriteType(buf *bytes.Buffer, typ Type, qf Qualifier) { + writeType(buf, typ, qf, make([]Type, 8)) +} + +func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) { + // Theoretically, this is a quadratic lookup algorithm, but in + // practice deeply nested composite types with unnamed component + // types are uncommon. This code is likely more efficient than + // using a map. + for _, t := range visited { + if t == typ { + fmt.Fprintf(buf, "○%T", typ) // cycle to typ + return + } + } + visited = append(visited, typ) + + switch t := typ.(type) { + case nil: + buf.WriteString("") + + case *Basic: + if t.kind == UnsafePointer { + buf.WriteString("unsafe.") + } + if gcCompatibilityMode { + // forget the alias names + switch t.kind { + case Byte: + t = Typ[Uint8] + case Rune: + t = Typ[Int32] + } + } + buf.WriteString(t.name) + + case *Array: + fmt.Fprintf(buf, "[%d]", t.len) + writeType(buf, t.elem, qf, visited) + + case *Slice: + buf.WriteString("[]") + writeType(buf, t.elem, qf, visited) + + case *Struct: + buf.WriteString("struct{") + for i, f := range t.fields { + if i > 0 { + buf.WriteString("; ") + } + if !f.anonymous { + buf.WriteString(f.name) + buf.WriteByte(' ') + } + writeType(buf, f.typ, qf, visited) + if tag := t.Tag(i); tag != "" { + fmt.Fprintf(buf, " %q", tag) + } + } + buf.WriteByte('}') + + case *Pointer: + buf.WriteByte('*') + writeType(buf, t.base, qf, visited) + + case *Tuple: + writeTuple(buf, t, false, qf, visited) + + case *Signature: + buf.WriteString("func") + writeSignature(buf, t, qf, visited) + + case *Interface: + // We write the source-level methods and embedded types rather + // than the actual method set since resolved method signatures + // may have non-printable cycles if parameters have anonymous + // interface types that (directly or indirectly) embed the + // current interface. For instance, consider the result type + // of m: + // + // type T interface{ + // m() interface{ T } + // } + // + buf.WriteString("interface{") + if gcCompatibilityMode { + // print flattened interface + // (useful to compare against gc-generated interfaces) + for i, m := range t.allMethods { + if i > 0 { + buf.WriteString("; ") + } + buf.WriteString(m.name) + writeSignature(buf, m.typ.(*Signature), qf, visited) + } + } else { + // print explicit interface methods and embedded types + for i, m := range t.methods { + if i > 0 { + buf.WriteString("; ") + } + buf.WriteString(m.name) + writeSignature(buf, m.typ.(*Signature), qf, visited) + } + for i, typ := range t.embeddeds { + if i > 0 || len(t.methods) > 0 { + buf.WriteString("; ") + } + writeType(buf, typ, qf, visited) + } + } + buf.WriteByte('}') + + case *Map: + buf.WriteString("map[") + writeType(buf, t.key, qf, visited) + buf.WriteByte(']') + writeType(buf, t.elem, qf, visited) + + case *Chan: + var s string + var parens bool + switch t.dir { + case SendRecv: + s = "chan " + // chan (<-chan T) requires parentheses + if c, _ := t.elem.(*Chan); c != nil && c.dir == RecvOnly { + parens = true + } + case SendOnly: + s = "chan<- " + case RecvOnly: + s = "<-chan " + default: + panic("unreachable") + } + buf.WriteString(s) + if parens { + buf.WriteByte('(') + } + writeType(buf, t.elem, qf, visited) + if parens { + buf.WriteByte(')') + } + + case *Named: + s := "" + if obj := t.obj; obj != nil { + if obj.pkg != nil { + writePackage(buf, obj.pkg, qf) + } + // TODO(gri): function-local named types should be displayed + // differently from named types at package level to avoid + // ambiguity. + s = obj.name + } + buf.WriteString(s) + + default: + // For externally defined implementations of Type. + buf.WriteString(t.String()) + } +} + +func writeTuple(buf *bytes.Buffer, tup *Tuple, variadic bool, qf Qualifier, visited []Type) { + buf.WriteByte('(') + if tup != nil { + for i, v := range tup.vars { + if i > 0 { + buf.WriteString(", ") + } + if v.name != "" { + buf.WriteString(v.name) + buf.WriteByte(' ') + } + typ := v.typ + if variadic && i == len(tup.vars)-1 { + if s, ok := typ.(*Slice); ok { + buf.WriteString("...") + typ = s.elem + } else { + // special case: + // append(s, "foo"...) leads to signature func([]byte, string...) + if t, ok := typ.Underlying().(*Basic); !ok || t.kind != String { + panic("internal error: string type expected") + } + writeType(buf, typ, qf, visited) + buf.WriteString("...") + continue + } + } + writeType(buf, typ, qf, visited) + } + } + buf.WriteByte(')') +} + +// WriteSignature writes the representation of the signature sig to buf, +// without a leading "func" keyword. +// The Qualifier controls the printing of +// package-level objects, and may be nil. +func WriteSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier) { + writeSignature(buf, sig, qf, make([]Type, 8)) +} + +func writeSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier, visited []Type) { + writeTuple(buf, sig.params, sig.variadic, qf, visited) + + n := sig.results.Len() + if n == 0 { + // no result + return + } + + buf.WriteByte(' ') + if n == 1 && sig.results.vars[0].name == "" { + // single unnamed result + writeType(buf, sig.results.vars[0].typ, qf, visited) + return + } + + // multiple or named result(s) + writeTuple(buf, sig.results, false, qf, visited) +} diff --git a/libgo/go/go/types/typestring_test.go b/libgo/go/go/types/typestring_test.go new file mode 100644 index 00000000000..913e6c735cc --- /dev/null +++ b/libgo/go/go/types/typestring_test.go @@ -0,0 +1,168 @@ +// 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 types_test + +import ( + "go/ast" + "go/importer" + "go/parser" + "go/token" + "internal/testenv" + "testing" + + . "go/types" +) + +const filename = "" + +func makePkg(t *testing.T, src string) (*Package, error) { + fset := token.NewFileSet() + file, err := parser.ParseFile(fset, filename, src, parser.DeclarationErrors) + if err != nil { + return nil, err + } + // use the package name as package path + conf := Config{Importer: importer.Default()} + return conf.Check(file.Name.Name, fset, []*ast.File{file}, nil) +} + +type testEntry struct { + src, str string +} + +// dup returns a testEntry where both src and str are the same. +func dup(s string) testEntry { + return testEntry{s, s} +} + +// types that don't depend on any other type declarations +var independentTestTypes = []testEntry{ + // basic types + dup("int"), + dup("float32"), + dup("string"), + + // arrays + dup("[10]int"), + + // slices + dup("[]int"), + dup("[][]int"), + + // structs + dup("struct{}"), + dup("struct{x int}"), + {`struct { + x, y int + z float32 "foo" + }`, `struct{x int; y int; z float32 "foo"}`}, + {`struct { + string + elems []complex128 + }`, `struct{string; elems []complex128}`}, + + // pointers + dup("*int"), + dup("***struct{}"), + dup("*struct{a int; b float32}"), + + // functions + dup("func()"), + dup("func(x int)"), + {"func(x, y int)", "func(x int, y int)"}, + {"func(x, y int, z string)", "func(x int, y int, z string)"}, + dup("func(int)"), + {"func(int, string, byte)", "func(int, string, byte)"}, + + dup("func() int"), + {"func() (string)", "func() string"}, + dup("func() (u int)"), + {"func() (u, v int, w string)", "func() (u int, v int, w string)"}, + + dup("func(int) string"), + dup("func(x int) string"), + dup("func(x int) (u string)"), + {"func(x, y int) (u string)", "func(x int, y int) (u string)"}, + + dup("func(...int) string"), + dup("func(x ...int) string"), + dup("func(x ...int) (u string)"), + {"func(x, y ...int) (u string)", "func(x int, y ...int) (u string)"}, + + // interfaces + dup("interface{}"), + dup("interface{m()}"), + dup(`interface{String() string; m(int) float32}`), + + // maps + dup("map[string]int"), + {"map[struct{x, y int}][]byte", "map[struct{x int; y int}][]byte"}, + + // channels + dup("chan<- chan int"), + dup("chan<- <-chan int"), + dup("<-chan <-chan int"), + dup("chan (<-chan int)"), + dup("chan<- func()"), + dup("<-chan []func() int"), +} + +// types that depend on other type declarations (src in TestTypes) +var dependentTestTypes = []testEntry{ + // interfaces + dup(`interface{io.Reader; io.Writer}`), + dup(`interface{m() int; io.Writer}`), + {`interface{m() interface{T}}`, `interface{m() interface{p.T}}`}, +} + +func TestTypeString(t *testing.T) { + testenv.MustHaveGoBuild(t) + + var tests []testEntry + tests = append(tests, independentTestTypes...) + tests = append(tests, dependentTestTypes...) + + for _, test := range tests { + src := `package p; import "io"; type _ io.Writer; type T ` + test.src + pkg, err := makePkg(t, src) + if err != nil { + t.Errorf("%s: %s", src, err) + continue + } + typ := pkg.Scope().Lookup("T").Type().Underlying() + if got := typ.String(); got != test.str { + t.Errorf("%s: got %s, want %s", test.src, got, test.str) + } + } +} + +func TestQualifiedTypeString(t *testing.T) { + p, _ := pkgFor("p.go", "package p; type T int", nil) + q, _ := pkgFor("q.go", "package q", nil) + + pT := p.Scope().Lookup("T").Type() + for _, test := range []struct { + typ Type + this *Package + want string + }{ + {pT, nil, "p.T"}, + {pT, p, "T"}, + {pT, q, "p.T"}, + {NewPointer(pT), p, "*T"}, + {NewPointer(pT), q, "*p.T"}, + } { + qualifier := func(pkg *Package) string { + if pkg != test.this { + return pkg.Name() + } + return "" + } + if got := TypeString(test.typ, qualifier); got != test.want { + t.Errorf("TypeString(%s, %s) = %s, want %s", + test.this, test.typ, got, test.want) + } + } +} diff --git a/libgo/go/go/types/typexpr.go b/libgo/go/go/types/typexpr.go new file mode 100644 index 00000000000..c744eeaa0c7 --- /dev/null +++ b/libgo/go/go/types/typexpr.go @@ -0,0 +1,712 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file implements type-checking of identifiers and type expressions. + +package types + +import ( + "go/ast" + "go/constant" + "go/token" + "sort" + "strconv" +) + +// ident type-checks identifier e and initializes x with the value or type of e. +// If an error occurred, x.mode is set to invalid. +// For the meaning of def and path, see check.typ, below. +// +func (check *Checker) ident(x *operand, e *ast.Ident, def *Named, path []*TypeName) { + x.mode = invalid + x.expr = e + + scope, obj := check.scope.LookupParent(e.Name, check.pos) + if obj == nil { + if e.Name == "_" { + check.errorf(e.Pos(), "cannot use _ as value or type") + } else { + check.errorf(e.Pos(), "undeclared name: %s", e.Name) + } + return + } + check.recordUse(e, obj) + + check.objDecl(obj, def, path) + typ := obj.Type() + assert(typ != nil) + + // The object may be dot-imported: If so, remove its package from + // the map of unused dot imports for the respective file scope. + // (This code is only needed for dot-imports. Without them, + // we only have to mark variables, see *Var case below). + if pkg := obj.Pkg(); pkg != check.pkg && pkg != nil { + delete(check.unusedDotImports[scope], pkg) + } + + switch obj := obj.(type) { + case *PkgName: + check.errorf(e.Pos(), "use of package %s not in selector", obj.name) + return + + case *Const: + check.addDeclDep(obj) + if typ == Typ[Invalid] { + return + } + if obj == universeIota { + if check.iota == nil { + check.errorf(e.Pos(), "cannot use iota outside constant declaration") + return + } + x.val = check.iota + } else { + x.val = obj.val + } + assert(x.val != nil) + x.mode = constant_ + + case *TypeName: + x.mode = typexpr + // check for cycle + // (it's ok to iterate forward because each named type appears at most once in path) + for i, prev := range path { + if prev == obj { + check.errorf(obj.pos, "illegal cycle in declaration of %s", obj.name) + // print cycle + for _, obj := range path[i:] { + check.errorf(obj.Pos(), "\t%s refers to", obj.Name()) // secondary error, \t indented + } + check.errorf(obj.Pos(), "\t%s", obj.Name()) + // maintain x.mode == typexpr despite error + typ = Typ[Invalid] + break + } + } + + case *Var: + if obj.pkg == check.pkg { + obj.used = true + } + check.addDeclDep(obj) + if typ == Typ[Invalid] { + return + } + x.mode = variable + + case *Func: + check.addDeclDep(obj) + x.mode = value + + case *Builtin: + x.id = obj.id + x.mode = builtin + + case *Nil: + x.mode = value + + default: + unreachable() + } + + x.typ = typ +} + +// typExpr type-checks the type expression e and returns its type, or Typ[Invalid]. +// If def != nil, e is the type specification for the named type def, declared +// in a type declaration, and def.underlying will be set to the type of e before +// any components of e are type-checked. Path contains the path of named types +// referring to this type. +// +func (check *Checker) typExpr(e ast.Expr, def *Named, path []*TypeName) (T Type) { + if trace { + check.trace(e.Pos(), "%s", e) + check.indent++ + defer func() { + check.indent-- + check.trace(e.Pos(), "=> %s", T) + }() + } + + T = check.typExprInternal(e, def, path) + assert(isTyped(T)) + check.recordTypeAndValue(e, typexpr, T, nil) + + return +} + +func (check *Checker) typ(e ast.Expr) Type { + return check.typExpr(e, nil, nil) +} + +// funcType type-checks a function or method type. +func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast.FuncType) { + scope := NewScope(check.scope, token.NoPos, token.NoPos, "function") + check.recordScope(ftyp, scope) + + recvList, _ := check.collectParams(scope, recvPar, false) + params, variadic := check.collectParams(scope, ftyp.Params, true) + results, _ := check.collectParams(scope, ftyp.Results, false) + + if recvPar != nil { + // recv parameter list present (may be empty) + // spec: "The receiver is specified via an extra parameter section preceding the + // method name. That parameter section must declare a single parameter, the receiver." + var recv *Var + switch len(recvList) { + case 0: + check.error(recvPar.Pos(), "method is missing receiver") + recv = NewParam(0, nil, "", Typ[Invalid]) // ignore recv below + default: + // more than one receiver + check.error(recvList[len(recvList)-1].Pos(), "method must have exactly one receiver") + fallthrough // continue with first receiver + case 1: + recv = recvList[0] + } + // spec: "The receiver type must be of the form T or *T where T is a type name." + // (ignore invalid types - error was reported before) + if t, _ := deref(recv.typ); t != Typ[Invalid] { + var err string + if T, _ := t.(*Named); T != nil { + // spec: "The type denoted by T is called the receiver base type; it must not + // be a pointer or interface type and it must be declared in the same package + // as the method." + if T.obj.pkg != check.pkg { + err = "type not defined in this package" + } else { + // TODO(gri) This is not correct if the underlying type is unknown yet. + switch u := T.underlying.(type) { + case *Basic: + // unsafe.Pointer is treated like a regular pointer + if u.kind == UnsafePointer { + err = "unsafe.Pointer" + } + case *Pointer, *Interface: + err = "pointer or interface type" + } + } + } else { + err = "basic or unnamed type" + } + if err != "" { + check.errorf(recv.pos, "invalid receiver %s (%s)", recv.typ, err) + // ok to continue + } + } + sig.recv = recv + } + + sig.scope = scope + sig.params = NewTuple(params...) + sig.results = NewTuple(results...) + sig.variadic = variadic +} + +// typExprInternal drives type checking of types. +// Must only be called by typExpr. +// +func (check *Checker) typExprInternal(e ast.Expr, def *Named, path []*TypeName) Type { + switch e := e.(type) { + case *ast.BadExpr: + // ignore - error reported before + + case *ast.Ident: + var x operand + check.ident(&x, e, def, path) + + switch x.mode { + case typexpr: + typ := x.typ + def.setUnderlying(typ) + return typ + case invalid: + // ignore - error reported before + case novalue: + check.errorf(x.pos(), "%s used as type", &x) + default: + check.errorf(x.pos(), "%s is not a type", &x) + } + + case *ast.SelectorExpr: + var x operand + check.selector(&x, e) + + switch x.mode { + case typexpr: + typ := x.typ + def.setUnderlying(typ) + return typ + case invalid: + // ignore - error reported before + case novalue: + check.errorf(x.pos(), "%s used as type", &x) + default: + check.errorf(x.pos(), "%s is not a type", &x) + } + + case *ast.ParenExpr: + return check.typExpr(e.X, def, path) + + case *ast.ArrayType: + if e.Len != nil { + typ := new(Array) + def.setUnderlying(typ) + typ.len = check.arrayLength(e.Len) + typ.elem = check.typExpr(e.Elt, nil, path) + return typ + + } else { + typ := new(Slice) + def.setUnderlying(typ) + typ.elem = check.typ(e.Elt) + return typ + } + + case *ast.StructType: + typ := new(Struct) + def.setUnderlying(typ) + check.structType(typ, e, path) + return typ + + case *ast.StarExpr: + typ := new(Pointer) + def.setUnderlying(typ) + typ.base = check.typ(e.X) + return typ + + case *ast.FuncType: + typ := new(Signature) + def.setUnderlying(typ) + check.funcType(typ, nil, e) + return typ + + case *ast.InterfaceType: + typ := new(Interface) + def.setUnderlying(typ) + check.interfaceType(typ, e, def, path) + return typ + + case *ast.MapType: + typ := new(Map) + def.setUnderlying(typ) + + typ.key = check.typ(e.Key) + typ.elem = check.typ(e.Value) + + // spec: "The comparison operators == and != must be fully defined + // for operands of the key type; thus the key type must not be a + // function, map, or slice." + // + // Delay this check because it requires fully setup types; + // it is safe to continue in any case (was issue 6667). + check.delay(func() { + if !Comparable(typ.key) { + check.errorf(e.Key.Pos(), "invalid map key type %s", typ.key) + } + }) + + return typ + + case *ast.ChanType: + typ := new(Chan) + def.setUnderlying(typ) + + dir := SendRecv + switch e.Dir { + case ast.SEND | ast.RECV: + // nothing to do + case ast.SEND: + dir = SendOnly + case ast.RECV: + dir = RecvOnly + default: + check.invalidAST(e.Pos(), "unknown channel direction %d", e.Dir) + // ok to continue + } + + typ.dir = dir + typ.elem = check.typ(e.Value) + return typ + + default: + check.errorf(e.Pos(), "%s is not a type", e) + } + + typ := Typ[Invalid] + def.setUnderlying(typ) + return typ +} + +// typeOrNil type-checks the type expression (or nil value) e +// and returns the typ of e, or nil. +// If e is neither a type nor nil, typOrNil returns Typ[Invalid]. +// +func (check *Checker) typOrNil(e ast.Expr) Type { + var x operand + check.rawExpr(&x, e, nil) + switch x.mode { + case invalid: + // ignore - error reported before + case novalue: + check.errorf(x.pos(), "%s used as type", &x) + case typexpr: + return x.typ + case value: + if x.isNil() { + return nil + } + fallthrough + default: + check.errorf(x.pos(), "%s is not a type", &x) + } + return Typ[Invalid] +} + +func (check *Checker) arrayLength(e ast.Expr) int64 { + var x operand + check.expr(&x, e) + if x.mode != constant_ { + if x.mode != invalid { + check.errorf(x.pos(), "array length %s must be constant", &x) + } + return 0 + } + if !x.isInteger() { + check.errorf(x.pos(), "array length %s must be integer", &x) + return 0 + } + n, ok := constant.Int64Val(x.val) + if !ok || n < 0 { + check.errorf(x.pos(), "invalid array length %s", &x) + return 0 + } + return n +} + +func (check *Checker) collectParams(scope *Scope, list *ast.FieldList, variadicOk bool) (params []*Var, variadic bool) { + if list == nil { + return + } + + var named, anonymous bool + for i, field := range list.List { + ftype := field.Type + if t, _ := ftype.(*ast.Ellipsis); t != nil { + ftype = t.Elt + if variadicOk && i == len(list.List)-1 { + variadic = true + } else { + check.invalidAST(field.Pos(), "... not permitted") + // ignore ... and continue + } + } + typ := check.typ(ftype) + // The parser ensures that f.Tag is nil and we don't + // care if a constructed AST contains a non-nil tag. + if len(field.Names) > 0 { + // named parameter + for _, name := range field.Names { + if name.Name == "" { + check.invalidAST(name.Pos(), "anonymous parameter") + // ok to continue + } + par := NewParam(name.Pos(), check.pkg, name.Name, typ) + check.declare(scope, name, par, scope.pos) + params = append(params, par) + } + named = true + } else { + // anonymous parameter + par := NewParam(ftype.Pos(), check.pkg, "", typ) + check.recordImplicit(field, par) + params = append(params, par) + anonymous = true + } + } + + if named && anonymous { + check.invalidAST(list.Pos(), "list contains both named and anonymous parameters") + // ok to continue + } + + // For a variadic function, change the last parameter's type from T to []T. + if variadic && len(params) > 0 { + last := params[len(params)-1] + last.typ = &Slice{elem: last.typ} + } + + return +} + +func (check *Checker) declareInSet(oset *objset, pos token.Pos, obj Object) bool { + if alt := oset.insert(obj); alt != nil { + check.errorf(pos, "%s redeclared", obj.Name()) + check.reportAltDecl(alt) + return false + } + return true +} + +func (check *Checker) interfaceType(iface *Interface, ityp *ast.InterfaceType, def *Named, path []*TypeName) { + // empty interface: common case + if ityp.Methods == nil { + return + } + + // The parser ensures that field tags are nil and we don't + // care if a constructed AST contains non-nil tags. + + // use named receiver type if available (for better error messages) + var recvTyp Type = iface + if def != nil { + recvTyp = def + } + + // Phase 1: Collect explicitly declared methods, the corresponding + // signature (AST) expressions, and the list of embedded + // type (AST) expressions. Do not resolve signatures or + // embedded types yet to avoid cycles referring to this + // interface. + + var ( + mset objset + signatures []ast.Expr // list of corresponding method signatures + embedded []ast.Expr // list of embedded types + ) + for _, f := range ityp.Methods.List { + if len(f.Names) > 0 { + // The parser ensures that there's only one method + // and we don't care if a constructed AST has more. + name := f.Names[0] + pos := name.Pos() + // spec: "As with all method sets, in an interface type, + // each method must have a unique non-blank name." + if name.Name == "_" { + check.errorf(pos, "invalid method name _") + continue + } + // Don't type-check signature yet - use an + // empty signature now and update it later. + // Since we know the receiver, set it up now + // (required to avoid crash in ptrRecv; see + // e.g. test case for issue 6638). + // TODO(gri) Consider marking methods signatures + // as incomplete, for better error messages. See + // also the T4 and T5 tests in testdata/cycles2.src. + sig := new(Signature) + sig.recv = NewVar(pos, check.pkg, "", recvTyp) + m := NewFunc(pos, check.pkg, name.Name, sig) + if check.declareInSet(&mset, pos, m) { + iface.methods = append(iface.methods, m) + iface.allMethods = append(iface.allMethods, m) + signatures = append(signatures, f.Type) + check.recordDef(name, m) + } + } else { + // embedded type + embedded = append(embedded, f.Type) + } + } + + // Phase 2: Resolve embedded interfaces. Because an interface must not + // embed itself (directly or indirectly), each embedded interface + // can be fully resolved without depending on any method of this + // interface (if there is a cycle or another error, the embedded + // type resolves to an invalid type and is ignored). + // In particular, the list of methods for each embedded interface + // must be complete (it cannot depend on this interface), and so + // those methods can be added to the list of all methods of this + // interface. + + for _, e := range embedded { + pos := e.Pos() + typ := check.typExpr(e, nil, path) + // Determine underlying embedded (possibly incomplete) type + // by following its forward chain. + named, _ := typ.(*Named) + under := underlying(named) + embed, _ := under.(*Interface) + if embed == nil { + if typ != Typ[Invalid] { + check.errorf(pos, "%s is not an interface", typ) + } + continue + } + iface.embeddeds = append(iface.embeddeds, named) + // collect embedded methods + for _, m := range embed.allMethods { + if check.declareInSet(&mset, pos, m) { + iface.allMethods = append(iface.allMethods, m) + } + } + } + + // Phase 3: At this point all methods have been collected for this interface. + // It is now safe to type-check the signatures of all explicitly + // declared methods, even if they refer to this interface via a cycle + // and embed the methods of this interface in a parameter of interface + // type. + + for i, m := range iface.methods { + expr := signatures[i] + typ := check.typ(expr) + sig, _ := typ.(*Signature) + if sig == nil { + if typ != Typ[Invalid] { + check.invalidAST(expr.Pos(), "%s is not a method signature", typ) + } + continue // keep method with empty method signature + } + // update signature, but keep recv that was set up before + old := m.typ.(*Signature) + sig.recv = old.recv + *old = *sig // update signature (don't replace it!) + } + + // TODO(gri) The list of explicit methods is only sorted for now to + // produce the same Interface as NewInterface. We may be able to + // claim source order in the future. Revisit. + sort.Sort(byUniqueMethodName(iface.methods)) + + // TODO(gri) The list of embedded types is only sorted for now to + // produce the same Interface as NewInterface. We may be able to + // claim source order in the future. Revisit. + sort.Sort(byUniqueTypeName(iface.embeddeds)) + + sort.Sort(byUniqueMethodName(iface.allMethods)) +} + +// byUniqueTypeName named type lists can be sorted by their unique type names. +type byUniqueTypeName []*Named + +func (a byUniqueTypeName) Len() int { return len(a) } +func (a byUniqueTypeName) Less(i, j int) bool { return a[i].obj.Id() < a[j].obj.Id() } +func (a byUniqueTypeName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } + +// byUniqueMethodName method lists can be sorted by their unique method names. +type byUniqueMethodName []*Func + +func (a byUniqueMethodName) Len() int { return len(a) } +func (a byUniqueMethodName) Less(i, j int) bool { return a[i].Id() < a[j].Id() } +func (a byUniqueMethodName) Swap(i, j int) { a[i], a[j] = a[j], a[i] } + +func (check *Checker) tag(t *ast.BasicLit) string { + if t != nil { + if t.Kind == token.STRING { + if val, err := strconv.Unquote(t.Value); err == nil { + return val + } + } + check.invalidAST(t.Pos(), "incorrect tag syntax: %q", t.Value) + } + return "" +} + +func (check *Checker) structType(styp *Struct, e *ast.StructType, path []*TypeName) { + list := e.Fields + if list == nil { + return + } + + // struct fields and tags + var fields []*Var + var tags []string + + // for double-declaration checks + var fset objset + + // current field typ and tag + var typ Type + var tag string + // anonymous != nil indicates an anonymous field. + add := func(field *ast.Field, ident *ast.Ident, anonymous *TypeName, pos token.Pos) { + if tag != "" && tags == nil { + tags = make([]string, len(fields)) + } + if tags != nil { + tags = append(tags, tag) + } + + name := ident.Name + fld := NewField(pos, check.pkg, name, typ, anonymous != nil) + // spec: "Within a struct, non-blank field names must be unique." + if name == "_" || check.declareInSet(&fset, pos, fld) { + fields = append(fields, fld) + check.recordDef(ident, fld) + } + if anonymous != nil { + check.recordUse(ident, anonymous) + } + } + + for _, f := range list.List { + typ = check.typExpr(f.Type, nil, path) + tag = check.tag(f.Tag) + if len(f.Names) > 0 { + // named fields + for _, name := range f.Names { + add(f, name, nil, name.Pos()) + } + } else { + // anonymous field + name := anonymousFieldIdent(f.Type) + pos := f.Type.Pos() + t, isPtr := deref(typ) + switch t := t.(type) { + case *Basic: + if t == Typ[Invalid] { + // error was reported before + continue + } + // unsafe.Pointer is treated like a regular pointer + if t.kind == UnsafePointer { + check.errorf(pos, "anonymous field type cannot be unsafe.Pointer") + continue + } + add(f, name, Universe.Lookup(t.name).(*TypeName), pos) + + case *Named: + // spec: "An embedded type must be specified as a type name + // T or as a pointer to a non-interface type name *T, and T + // itself may not be a pointer type." + switch u := t.underlying.(type) { + case *Basic: + // unsafe.Pointer is treated like a regular pointer + if u.kind == UnsafePointer { + check.errorf(pos, "anonymous field type cannot be unsafe.Pointer") + continue + } + case *Pointer: + check.errorf(pos, "anonymous field type cannot be a pointer") + continue + case *Interface: + if isPtr { + check.errorf(pos, "anonymous field type cannot be a pointer to an interface") + continue + } + } + add(f, name, t.obj, pos) + + default: + check.invalidAST(pos, "anonymous field type %s must be named", typ) + } + } + } + + styp.fields = fields + styp.tags = tags +} + +func anonymousFieldIdent(e ast.Expr) *ast.Ident { + switch e := e.(type) { + case *ast.Ident: + return e + case *ast.StarExpr: + return anonymousFieldIdent(e.X) + case *ast.SelectorExpr: + return e.Sel + } + return nil // invalid anonymous field +} diff --git a/libgo/go/go/types/universe.go b/libgo/go/go/types/universe.go new file mode 100644 index 00000000000..40185c1ad42 --- /dev/null +++ b/libgo/go/go/types/universe.go @@ -0,0 +1,223 @@ +// 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 sets up the universe scope and the unsafe package. + +package types + +import ( + "go/constant" + "go/token" + "strings" +) + +var ( + Universe *Scope + Unsafe *Package + universeIota *Const + universeByte *Basic // uint8 alias, but has name "byte" + universeRune *Basic // int32 alias, but has name "rune" +) + +var Typ = []*Basic{ + Invalid: {Invalid, 0, "invalid type"}, + + Bool: {Bool, IsBoolean, "bool"}, + Int: {Int, IsInteger, "int"}, + Int8: {Int8, IsInteger, "int8"}, + Int16: {Int16, IsInteger, "int16"}, + Int32: {Int32, IsInteger, "int32"}, + Int64: {Int64, IsInteger, "int64"}, + Uint: {Uint, IsInteger | IsUnsigned, "uint"}, + Uint8: {Uint8, IsInteger | IsUnsigned, "uint8"}, + Uint16: {Uint16, IsInteger | IsUnsigned, "uint16"}, + Uint32: {Uint32, IsInteger | IsUnsigned, "uint32"}, + Uint64: {Uint64, IsInteger | IsUnsigned, "uint64"}, + Uintptr: {Uintptr, IsInteger | IsUnsigned, "uintptr"}, + Float32: {Float32, IsFloat, "float32"}, + Float64: {Float64, IsFloat, "float64"}, + Complex64: {Complex64, IsComplex, "complex64"}, + Complex128: {Complex128, IsComplex, "complex128"}, + String: {String, IsString, "string"}, + UnsafePointer: {UnsafePointer, 0, "Pointer"}, + + UntypedBool: {UntypedBool, IsBoolean | IsUntyped, "untyped bool"}, + UntypedInt: {UntypedInt, IsInteger | IsUntyped, "untyped int"}, + UntypedRune: {UntypedRune, IsInteger | IsUntyped, "untyped rune"}, + UntypedFloat: {UntypedFloat, IsFloat | IsUntyped, "untyped float"}, + UntypedComplex: {UntypedComplex, IsComplex | IsUntyped, "untyped complex"}, + UntypedString: {UntypedString, IsString | IsUntyped, "untyped string"}, + UntypedNil: {UntypedNil, IsUntyped, "untyped nil"}, +} + +var aliases = [...]*Basic{ + {Byte, IsInteger | IsUnsigned, "byte"}, + {Rune, IsInteger, "rune"}, +} + +func defPredeclaredTypes() { + for _, t := range Typ { + def(NewTypeName(token.NoPos, nil, t.name, t)) + } + for _, t := range aliases { + def(NewTypeName(token.NoPos, nil, t.name, t)) + } + + // Error has a nil package in its qualified name since it is in no package + res := NewVar(token.NoPos, nil, "", Typ[String]) + sig := &Signature{results: NewTuple(res)} + err := NewFunc(token.NoPos, nil, "Error", sig) + typ := &Named{underlying: NewInterface([]*Func{err}, nil).Complete()} + sig.recv = NewVar(token.NoPos, nil, "", typ) + def(NewTypeName(token.NoPos, nil, "error", typ)) +} + +var predeclaredConsts = [...]struct { + name string + kind BasicKind + val constant.Value +}{ + {"true", UntypedBool, constant.MakeBool(true)}, + {"false", UntypedBool, constant.MakeBool(false)}, + {"iota", UntypedInt, constant.MakeInt64(0)}, +} + +func defPredeclaredConsts() { + for _, c := range predeclaredConsts { + def(NewConst(token.NoPos, nil, c.name, Typ[c.kind], c.val)) + } +} + +func defPredeclaredNil() { + def(&Nil{object{name: "nil", typ: Typ[UntypedNil]}}) +} + +// A builtinId is the id of a builtin function. +type builtinId int + +const ( + // universe scope + _Append builtinId = iota + _Cap + _Close + _Complex + _Copy + _Delete + _Imag + _Len + _Make + _New + _Panic + _Print + _Println + _Real + _Recover + + // package unsafe + _Alignof + _Offsetof + _Sizeof + + // testing support + _Assert + _Trace +) + +var predeclaredFuncs = [...]struct { + name string + nargs int + variadic bool + kind exprKind +}{ + _Append: {"append", 1, true, expression}, + _Cap: {"cap", 1, false, expression}, + _Close: {"close", 1, false, statement}, + _Complex: {"complex", 2, false, expression}, + _Copy: {"copy", 2, false, statement}, + _Delete: {"delete", 2, false, statement}, + _Imag: {"imag", 1, false, expression}, + _Len: {"len", 1, false, expression}, + _Make: {"make", 1, true, expression}, + _New: {"new", 1, false, expression}, + _Panic: {"panic", 1, false, statement}, + _Print: {"print", 0, true, statement}, + _Println: {"println", 0, true, statement}, + _Real: {"real", 1, false, expression}, + _Recover: {"recover", 0, false, statement}, + + _Alignof: {"Alignof", 1, false, expression}, + _Offsetof: {"Offsetof", 1, false, expression}, + _Sizeof: {"Sizeof", 1, false, expression}, + + _Assert: {"assert", 1, false, statement}, + _Trace: {"trace", 0, true, statement}, +} + +func defPredeclaredFuncs() { + for i := range predeclaredFuncs { + id := builtinId(i) + if id == _Assert || id == _Trace { + continue // only define these in testing environment + } + def(newBuiltin(id)) + } +} + +// DefPredeclaredTestFuncs defines the assert and trace built-ins. +// These built-ins are intended for debugging and testing of this +// package only. +func DefPredeclaredTestFuncs() { + if Universe.Lookup("assert") != nil { + return // already defined + } + def(newBuiltin(_Assert)) + def(newBuiltin(_Trace)) +} + +func init() { + Universe = NewScope(nil, token.NoPos, token.NoPos, "universe") + Unsafe = NewPackage("unsafe", "unsafe") + Unsafe.complete = true + + defPredeclaredTypes() + defPredeclaredConsts() + defPredeclaredNil() + defPredeclaredFuncs() + + universeIota = Universe.Lookup("iota").(*Const) + universeByte = Universe.Lookup("byte").(*TypeName).typ.(*Basic) + universeRune = Universe.Lookup("rune").(*TypeName).typ.(*Basic) +} + +// Objects with names containing blanks are internal and not entered into +// a scope. Objects with exported names are inserted in the unsafe package +// scope; other objects are inserted in the universe scope. +// +func def(obj Object) { + name := obj.Name() + if strings.Index(name, " ") >= 0 { + return // nothing to do + } + // fix Obj link for named types + if typ, ok := obj.Type().(*Named); ok { + typ.obj = obj.(*TypeName) + } + // exported identifiers go into package unsafe + scope := Universe + if obj.Exported() { + scope = Unsafe.scope + // set Pkg field + switch obj := obj.(type) { + case *TypeName: + obj.pkg = Unsafe + case *Builtin: + obj.pkg = Unsafe + default: + unreachable() + } + } + if scope.Insert(obj) != nil { + panic("internal error: double declaration") + } +} diff --git a/libgo/go/hash/crc32/crc32.go b/libgo/go/hash/crc32/crc32.go index 6a6b9473bea..234d9296890 100644 --- a/libgo/go/hash/crc32/crc32.go +++ b/libgo/go/hash/crc32/crc32.go @@ -5,6 +5,11 @@ // Package crc32 implements the 32-bit cyclic redundancy check, or CRC-32, // checksum. See http://en.wikipedia.org/wiki/Cyclic_redundancy_check for // information. +// +// Polynomials are represented in LSB-first form also known as reversed representation. +// +// See http://en.wikipedia.org/wiki/Mathematics_of_cyclic_redundancy_checks#Reversed_representations_and_reciprocal_polynomials +// for information. package crc32 import ( @@ -49,6 +54,13 @@ func castagnoliInit() { // IEEETable is the table for the IEEE polynomial. var IEEETable = makeTable(IEEE) +// slicing8Table is array of 8 Tables +type slicing8Table [8]Table + +// iEEETable8 is the slicing8Table for IEEE +var iEEETable8 *slicing8Table +var iEEETable8Once sync.Once + // MakeTable returns the Table constructed from the specified polynomial. func MakeTable(poly uint32) *Table { switch poly { @@ -78,6 +90,20 @@ func makeTable(poly uint32) *Table { return t } +// makeTable8 returns slicing8Table constructed from the specified polynomial. +func makeTable8(poly uint32) *slicing8Table { + t := new(slicing8Table) + t[0] = *makeTable(poly) + for i := 0; i < 256; i++ { + crc := t[0][i] + for j := 1; j < 8; j++ { + crc = t[0][crc&0xFF] ^ (crc >> 8) + t[j][i] = crc + } + } + return t +} + // digest represents the partial evaluation of a checksum. type digest struct { crc uint32 @@ -106,11 +132,32 @@ func update(crc uint32, tab *Table, p []byte) uint32 { return ^crc } +// updateSlicingBy8 updates CRC using Slicing-by-8 +func updateSlicingBy8(crc uint32, tab *slicing8Table, p []byte) uint32 { + crc = ^crc + for len(p) > 8 { + crc ^= uint32(p[0]) | uint32(p[1])<<8 | uint32(p[2])<<16 | uint32(p[3])<<24 + crc = tab[0][p[7]] ^ tab[1][p[6]] ^ tab[2][p[5]] ^ tab[3][p[4]] ^ + tab[4][crc>>24] ^ tab[5][(crc>>16)&0xFF] ^ + tab[6][(crc>>8)&0xFF] ^ tab[7][crc&0xFF] + p = p[8:] + } + crc = ^crc + return update(crc, &tab[0], p) +} + // Update returns the result of adding the bytes in p to the crc. func Update(crc uint32, tab *Table, p []byte) uint32 { if tab == castagnoliTable { return updateCastagnoli(crc, p) } + // only use slicing-by-8 when input is larger than 4KB + if tab == IEEETable && len(p) >= 4096 { + iEEETable8Once.Do(func() { + iEEETable8 = makeTable8(IEEE) + }) + return updateSlicingBy8(crc, iEEETable8, p) + } return update(crc, tab, p) } @@ -132,4 +179,4 @@ func Checksum(data []byte, tab *Table) uint32 { return Update(0, tab, data) } // ChecksumIEEE returns the CRC-32 checksum of data // using the IEEE polynomial. -func ChecksumIEEE(data []byte) uint32 { return update(0, IEEETable, data) } +func ChecksumIEEE(data []byte) uint32 { return Update(0, IEEETable, data) } diff --git a/libgo/go/hash/crc32/crc32_generic.go b/libgo/go/hash/crc32/crc32_generic.go index c3fdcd685c5..416c1b7c556 100644 --- a/libgo/go/hash/crc32/crc32_generic.go +++ b/libgo/go/hash/crc32/crc32_generic.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 386 arm +// +build 386 arm arm64 ppc64 ppc64le package crc32 diff --git a/libgo/go/hash/crc32/crc32_test.go b/libgo/go/hash/crc32/crc32_test.go index 75dc26e7cc2..1ca3ac2a270 100644 --- a/libgo/go/hash/crc32/crc32_test.go +++ b/libgo/go/hash/crc32/crc32_test.go @@ -81,7 +81,7 @@ func TestGolden(t *testing.T) { } } -func BenchmarkCrc32KB(b *testing.B) { +func BenchmarkIEEECrc1KB(b *testing.B) { b.SetBytes(1024) data := make([]byte, 1024) for i := range data { @@ -97,3 +97,37 @@ func BenchmarkCrc32KB(b *testing.B) { h.Sum(in) } } + +func BenchmarkIEEECrc4KB(b *testing.B) { + b.SetBytes(4096) + data := make([]byte, 4096) + for i := range data { + data[i] = byte(i) + } + h := NewIEEE() + in := make([]byte, 0, h.Size()) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + h.Reset() + h.Write(data) + h.Sum(in) + } +} + +func BenchmarkCastagnoliCrc1KB(b *testing.B) { + b.SetBytes(1024) + data := make([]byte, 1024) + for i := range data { + data[i] = byte(i) + } + h := New(MakeTable(Castagnoli)) + in := make([]byte, 0, h.Size()) + + b.ResetTimer() + for i := 0; i < b.N; i++ { + h.Reset() + h.Write(data) + h.Sum(in) + } +} diff --git a/libgo/go/hash/crc32/example_test.go b/libgo/go/hash/crc32/example_test.go new file mode 100644 index 00000000000..a1d9e165280 --- /dev/null +++ b/libgo/go/hash/crc32/example_test.go @@ -0,0 +1,30 @@ +// Copyright 2015 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 + +package crc32_test + +import ( + "fmt" + "hash/crc32" +) + +func ExampleMakeTable() { + // In this package, the CRC polynomial is represented in reversed notation, + // or LSB-first representation. + // + // LSB-first representation is a hexadecimal number with n bits, in which the + // most significant bit represents the coefficient of x⁰ and the least significant + // bit represents the coefficient of xⁿ⁻¹ (the coefficient for xⁿ is implicit). + // + // For example, CRC32-Q, as defined by the following polynomial, + // x³²+ x³¹+ x²⁴+ x²²+ x¹⁶+ x¹⁴+ x⁸+ x⁷+ x⁵+ x³+ x¹+ x⁰ + // has the reversed notation 0b11010101100000101000001010000001, so the value + // that should be passed to MakeTable is 0xD5828281. + crc32q := crc32.MakeTable(0xD5828281) + fmt.Printf("%08x\n", crc32.Checksum([]byte("Hello world"), crc32q)) + // Output: + // 2964d064 +} diff --git a/libgo/go/html/escape.go b/libgo/go/html/escape.go index dd5dfa7cd75..f50a4b937a7 100644 --- a/libgo/go/html/escape.go +++ b/libgo/go/html/escape.go @@ -6,7 +6,6 @@ package html import ( - "bytes" "strings" "unicode/utf8" ) @@ -187,52 +186,20 @@ func unescape(b []byte) []byte { return b } -const escapedChars = `&'<>"` - -func escape(w writer, s string) error { - i := strings.IndexAny(s, escapedChars) - for i != -1 { - if _, err := w.WriteString(s[:i]); err != nil { - return err - } - var esc string - switch s[i] { - case '&': - esc = "&" - case '\'': - // "'" is shorter than "'" and apos was not in HTML until HTML5. - esc = "'" - case '<': - esc = "<" - case '>': - esc = ">" - case '"': - // """ is shorter than """. - esc = """ - default: - panic("unrecognized escape character") - } - s = s[i+1:] - if _, err := w.WriteString(esc); err != nil { - return err - } - i = strings.IndexAny(s, escapedChars) - } - _, err := w.WriteString(s) - return err -} +var htmlEscaper = strings.NewReplacer( + `&`, "&", + `'`, "'", // "'" is shorter than "'" and apos was not in HTML until HTML5. + `<`, "<", + `>`, ">", + `"`, """, // """ is shorter than """. +) // EscapeString escapes special characters like "<" to become "<". It // escapes only five such characters: <, >, &, ' and ". // UnescapeString(EscapeString(s)) == s always holds, but the converse isn't // always true. func EscapeString(s string) string { - if strings.IndexAny(s, escapedChars) == -1 { - return s - } - var buf bytes.Buffer - escape(&buf, s) - return buf.String() + return htmlEscaper.Replace(s) } // UnescapeString unescapes entities like "<" to become "<". It unescapes a @@ -241,10 +208,8 @@ func EscapeString(s string) string { // UnescapeString(EscapeString(s)) == s always holds, but the converse isn't // always true. func UnescapeString(s string) string { - for _, c := range s { - if c == '&' { - return string(unescape([]byte(s))) - } + if !strings.Contains(s, "&") { + return s } - return s + return string(unescape([]byte(s))) } diff --git a/libgo/go/html/escape_test.go b/libgo/go/html/escape_test.go index 2d7ad8ac266..3702626a3dc 100644 --- a/libgo/go/html/escape_test.go +++ b/libgo/go/html/escape_test.go @@ -4,7 +4,10 @@ package html -import "testing" +import ( + "strings" + "testing" +) type unescapeTest struct { // A short description of the test case. @@ -113,3 +116,38 @@ func TestUnescapeEscape(t *testing.T) { } } } + +var ( + benchEscapeData = strings.Repeat("AAAAA < BBBBB > CCCCC & DDDDD ' EEEEE \" ", 100) + benchEscapeNone = strings.Repeat("AAAAA x BBBBB x CCCCC x DDDDD x EEEEE x ", 100) +) + +func BenchmarkEscape(b *testing.B) { + n := 0 + for i := 0; i < b.N; i++ { + n += len(EscapeString(benchEscapeData)) + } +} + +func BenchmarkEscapeNone(b *testing.B) { + n := 0 + for i := 0; i < b.N; i++ { + n += len(EscapeString(benchEscapeNone)) + } +} + +func BenchmarkUnescape(b *testing.B) { + s := EscapeString(benchEscapeData) + n := 0 + for i := 0; i < b.N; i++ { + n += len(UnescapeString(s)) + } +} + +func BenchmarkUnescapeNone(b *testing.B) { + s := EscapeString(benchEscapeNone) + n := 0 + for i := 0; i < b.N; i++ { + n += len(UnescapeString(s)) + } +} diff --git a/libgo/go/html/example_test.go b/libgo/go/html/example_test.go new file mode 100644 index 00000000000..d0f0a9bd850 --- /dev/null +++ b/libgo/go/html/example_test.go @@ -0,0 +1,24 @@ +// Copyright 2015 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 + +package html_test + +import ( + "fmt" + "html" +) + +func ExampleEscapeString() { + const s = `"Fran & Freddie's Diner" ` + fmt.Println(html.EscapeString(s)) + // Output: "Fran & Freddie's Diner" <tasty@example.com> +} + +func ExampleUnescapeString() { + const s = `"Fran & Freddie's Diner" <tasty@example.com>` + fmt.Println(html.UnescapeString(s)) + // Output: "Fran & Freddie's Diner" +} diff --git a/libgo/go/html/template/clone_test.go b/libgo/go/html/template/clone_test.go index e11bff2c5df..c89d22a6f90 100644 --- a/libgo/go/html/template/clone_test.go +++ b/libgo/go/html/template/clone_test.go @@ -142,7 +142,7 @@ func TestTemplates(t *testing.T) { } } -// This used to crash; http://golang.org/issue/3281 +// This used to crash; https://golang.org/issue/3281 func TestCloneCrash(t *testing.T) { t1 := New("all") Must(t1.New("t1").Parse(`{{define "foo"}}foo{{end}}`)) @@ -166,7 +166,7 @@ func TestCloneThenParse(t *testing.T) { } } -// https://code.google.com/p/go/issues/detail?id=5980 +// https://golang.org/issue/5980 func TestFuncMapWorksAfterClone(t *testing.T) { funcs := FuncMap{"customFunc": func() (string, error) { return "", errors.New("issue5980") diff --git a/libgo/go/html/template/content_test.go b/libgo/go/html/template/content_test.go index 5f3ffe2d325..e698328693e 100644 --- a/libgo/go/html/template/content_test.go +++ b/libgo/go/html/template/content_test.go @@ -260,7 +260,7 @@ func TestStringer(t *testing.T) { } } -// https://code.google.com/p/go/issues/detail?id=5982 +// https://golang.org/issue/5982 func TestEscapingNilNonemptyInterfaces(t *testing.T) { tmpl := Must(New("x").Parse("{{.E}}")) diff --git a/libgo/go/html/template/css.go b/libgo/go/html/template/css.go index 634f183f796..318464835fa 100644 --- a/libgo/go/html/template/css.go +++ b/libgo/go/html/template/css.go @@ -157,56 +157,20 @@ func isCSSSpace(b byte) bool { func cssEscaper(args ...interface{}) string { s, _ := stringify(args...) var b bytes.Buffer - written := 0 - for i, r := range s { + r, w, written := rune(0), 0, 0 + for i := 0; i < len(s); i += w { + // See comment in htmlEscaper. + r, w = utf8.DecodeRuneInString(s[i:]) var repl string - switch r { - case 0: - repl = `\0` - case '\t': - repl = `\9` - case '\n': - repl = `\a` - case '\f': - repl = `\c` - case '\r': - repl = `\d` - // Encode HTML specials as hex so the output can be embedded - // in HTML attributes without further encoding. - case '"': - repl = `\22` - case '&': - repl = `\26` - case '\'': - repl = `\27` - case '(': - repl = `\28` - case ')': - repl = `\29` - case '+': - repl = `\2b` - case '/': - repl = `\2f` - case ':': - repl = `\3a` - case ';': - repl = `\3b` - case '<': - repl = `\3c` - case '>': - repl = `\3e` - case '\\': - repl = `\\` - case '{': - repl = `\7b` - case '}': - repl = `\7d` + switch { + case int(r) < len(cssReplacementTable) && cssReplacementTable[r] != "": + repl = cssReplacementTable[r] default: continue } b.WriteString(s[written:i]) b.WriteString(repl) - written = i + utf8.RuneLen(r) + written = i + w if repl != `\\` && (written == len(s) || isHex(s[written]) || isCSSSpace(s[written])) { b.WriteByte(' ') } @@ -218,6 +182,30 @@ func cssEscaper(args ...interface{}) string { return b.String() } +var cssReplacementTable = []string{ + 0: `\0`, + '\t': `\9`, + '\n': `\a`, + '\f': `\c`, + '\r': `\d`, + // Encode HTML specials as hex so the output can be embedded + // in HTML attributes without further encoding. + '"': `\22`, + '&': `\26`, + '\'': `\27`, + '(': `\28`, + ')': `\29`, + '+': `\2b`, + '/': `\2f`, + ':': `\3a`, + ';': `\3b`, + '<': `\3c`, + '>': `\3e`, + '\\': `\\`, + '{': `\7b`, + '}': `\7d`, +} + var expressionBytes = []byte("expression") var mozBindingBytes = []byte("mozbinding") diff --git a/libgo/go/html/template/doc.go b/libgo/go/html/template/doc.go index d422ada37a7..1827403aa38 100644 --- a/libgo/go/html/template/doc.go +++ b/libgo/go/html/template/doc.go @@ -151,7 +151,7 @@ The template can be invoked with - tmpl.Execute(out, HTML(`World`)) + tmpl.Execute(out, template.HTML(`World`)) to produce diff --git a/libgo/go/html/template/escape.go b/libgo/go/html/template/escape.go index ee01fb12ab8..3c183405478 100644 --- a/libgo/go/html/template/escape.go +++ b/libgo/go/html/template/escape.go @@ -205,15 +205,17 @@ func (e *escaper) escapeAction(c context, n *parse.ActionNode) context { } // allIdents returns the names of the identifiers under the Ident field of the node, -// which might be a singleton (Identifier) or a slice (Field). +// which might be a singleton (Identifier) or a slice (Field or Chain). func allIdents(node parse.Node) []string { switch node := node.(type) { case *parse.IdentifierNode: return []string{node.Ident} case *parse.FieldNode: return node.Ident + case *parse.ChainNode: + return node.Field } - panic("unidentified node type in allIdents") + return nil } // ensurePipelineContains ensures that the pipeline has commands with @@ -297,9 +299,9 @@ var redundantFuncs = map[string]map[string]bool{ // unless it is redundant with the last command. func appendCmd(cmds []*parse.CommandNode, cmd *parse.CommandNode) []*parse.CommandNode { if n := len(cmds); n != 0 { - last, ok := cmds[n-1].Args[0].(*parse.IdentifierNode) - next, _ := cmd.Args[0].(*parse.IdentifierNode) - if ok && redundantFuncs[last.Ident][next.Ident] { + last, okLast := cmds[n-1].Args[0].(*parse.IdentifierNode) + next, okNext := cmd.Args[0].(*parse.IdentifierNode) + if okLast && okNext && redundantFuncs[last.Ident][next.Ident] { return cmds } } diff --git a/libgo/go/html/template/escape_test.go b/libgo/go/html/template/escape_test.go index ef7b8774845..bea2d133c33 100644 --- a/libgo/go/html/template/escape_test.go +++ b/libgo/go/html/template/escape_test.go @@ -1547,6 +1547,28 @@ func TestEnsurePipelineContains(t *testing.T) { "($).X | urlquery | html | print", []string{"urlquery", "html"}, }, + { + "{{.X | print 2 | .f 3}}", + ".X | print 2 | .f 3 | urlquery | html", + []string{"urlquery", "html"}, + }, + { + "{{.X | html | print 2 | .f 3}}", + ".X | urlquery | html | print 2 | .f 3", + []string{"urlquery", "html"}, + }, + { + // covering issue 10801 + "{{.X | js.x }}", + ".X | js.x | urlquery | html", + []string{"urlquery", "html"}, + }, + { + // covering issue 10801 + "{{.X | (print 12 | js).x }}", + ".X | (print 12 | js).x | urlquery | html", + []string{"urlquery", "html"}, + }, } for i, test := range tests { tmpl := template.Must(template.New("test").Parse(test.input)) @@ -1564,6 +1586,28 @@ func TestEnsurePipelineContains(t *testing.T) { } } +func TestEscapeMalformedPipelines(t *testing.T) { + tests := []string{ + "{{ 0 | $ }}", + "{{ 0 | $ | urlquery }}", + "{{ 0 | $ | urlquery | html }}", + "{{ 0 | (nil) }}", + "{{ 0 | (nil) | html }}", + "{{ 0 | (nil) | html | urlquery }}", + } + for _, test := range tests { + var b bytes.Buffer + tmpl, err := New("test").Parse(test) + if err != nil { + t.Errorf("failed to parse set: %q", err) + } + err = tmpl.Execute(&b, nil) + if err == nil { + t.Errorf("Expected error for %q", test) + } + } +} + func TestEscapeErrorsNotIgnorable(t *testing.T) { var b bytes.Buffer tmpl, _ := New("dangerous").Parse("{{.}}`)) var buf bytes.Buffer diff --git a/libgo/go/html/template/example_test.go b/libgo/go/html/template/example_test.go new file mode 100644 index 00000000000..3ea3dca304c --- /dev/null +++ b/libgo/go/html/template/example_test.go @@ -0,0 +1,124 @@ +// Copyright 2015 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 + +package template_test + +import ( + "fmt" + "html/template" + "log" + "os" +) + +func Example() { + const tpl = ` + + + + + {{.Title}} + + + {{range .Items}}
{{ . }}
{{else}}
no rows
{{end}} + +` + + check := func(err error) { + if err != nil { + log.Fatal(err) + } + } + t, err := template.New("webpage").Parse(tpl) + + data := struct { + Title string + Items []string + }{ + Title: "My page", + Items: []string{ + "My photos", + "My blog", + }, + } + + err = t.Execute(os.Stdout, data) + check(err) + + noItems := struct { + Title string + Items []string + }{ + Title: "My another page", + Items: []string{}, + } + + err = t.Execute(os.Stdout, noItems) + check(err) + + // Output: + // + // + // + // + // My page + // + // + //
My photos
My blog
+ // + // + // + // + // + // + // My another page + // + // + //
no rows
+ // + // + +} + +func Example_autoescaping() { + check := func(err error) { + if err != nil { + log.Fatal(err) + } + } + t, err := template.New("foo").Parse(`{{define "T"}}Hello, {{.}}!{{end}}`) + check(err) + err = t.ExecuteTemplate(os.Stdout, "T", "") + check(err) + // Output: + // Hello, <script>alert('you have been pwned')</script>! +} + +func Example_escape() { + const s = `"Fran & Freddie's Diner" ` + v := []interface{}{`"Fran & Freddie's Diner"`, ' ', ``} + + fmt.Println(template.HTMLEscapeString(s)) + template.HTMLEscape(os.Stdout, []byte(s)) + fmt.Fprintln(os.Stdout, "") + fmt.Println(template.HTMLEscaper(v...)) + + fmt.Println(template.JSEscapeString(s)) + template.JSEscape(os.Stdout, []byte(s)) + fmt.Fprintln(os.Stdout, "") + fmt.Println(template.JSEscaper(v...)) + + fmt.Println(template.URLQueryEscaper(v...)) + + // Output: + // "Fran & Freddie's Diner" <tasty@example.com> + // "Fran & Freddie's Diner" <tasty@example.com> + // "Fran & Freddie's Diner"32<tasty@example.com> + // \"Fran & Freddie\'s Diner\" \x3Ctasty@example.com\x3E + // \"Fran & Freddie\'s Diner\" \x3Ctasty@example.com\x3E + // \"Fran & Freddie\'s Diner\"32\x3Ctasty@example.com\x3E + // %22Fran+%26+Freddie%27s+Diner%2232%3Ctasty%40example.com%3E + +} diff --git a/libgo/go/html/template/html.go b/libgo/go/html/template/html.go index 9c069efd1d9..de4aa4abb26 100644 --- a/libgo/go/html/template/html.go +++ b/libgo/go/html/template/html.go @@ -138,21 +138,24 @@ var htmlNospaceNormReplacementTable = []string{ // and when badRunes is true, certain bad runes are allowed through unescaped. func htmlReplacer(s string, replacementTable []string, badRunes bool) string { written, b := 0, new(bytes.Buffer) - for i, r := range s { + r, w := rune(0), 0 + for i := 0; i < len(s); i += w { + // Cannot use 'for range s' because we need to preserve the width + // of the runes in the input. If we see a decoding error, the input + // width will not be utf8.Runelen(r) and we will overrun the buffer. + r, w = utf8.DecodeRuneInString(s[i:]) if int(r) < len(replacementTable) { if repl := replacementTable[r]; len(repl) != 0 { b.WriteString(s[written:i]) b.WriteString(repl) - // Valid as long as replacementTable doesn't - // include anything above 0x7f. - written = i + utf8.RuneLen(r) + written = i + w } } else if badRunes { // No-op. // IE does not allow these ranges in unquoted attrs. } else if 0xfdd0 <= r && r <= 0xfdef || 0xfff0 <= r && r <= 0xffff { fmt.Fprintf(b, "%s&#x%x;", s[written:i], r) - written = i + utf8.RuneLen(r) + written = i + w } } if written == 0 { diff --git a/libgo/go/html/template/html_test.go b/libgo/go/html/template/html_test.go index b9b97038757..f04ee04c27a 100644 --- a/libgo/go/html/template/html_test.go +++ b/libgo/go/html/template/html_test.go @@ -19,7 +19,8 @@ func TestHTMLNospaceEscaper(t *testing.T) { `PQRSTUVWXYZ[\]^_` + "`abcdefghijklmno" + "pqrstuvwxyz{|}~\x7f" + - "\u00A0\u0100\u2028\u2029\ufeff\ufdec\U0001D11E") + "\u00A0\u0100\u2028\u2029\ufeff\ufdec\U0001D11E" + + "erroneous\x960") // keep at the end want := ("�\x01\x02\x03\x04\x05\x06\x07" + "\x08 \x0E\x0F" + @@ -31,14 +32,16 @@ func TestHTMLNospaceEscaper(t *testing.T) { `PQRSTUVWXYZ[\]^_` + ``abcdefghijklmno` + `pqrstuvwxyz{|}~` + "\u007f" + - "\u00A0\u0100\u2028\u2029\ufeff﷬\U0001D11E") + "\u00A0\u0100\u2028\u2029\ufeff﷬\U0001D11E" + + "erroneous�0") // keep at the end got := htmlNospaceEscaper(input) if got != want { t.Errorf("encode: want\n\t%q\nbut got\n\t%q", want, got) } - got, want = html.UnescapeString(got), strings.Replace(input, "\x00", "\ufffd", 1) + r := strings.NewReplacer("\x00", "\ufffd", "\x96", "\ufffd") + got, want = html.UnescapeString(got), r.Replace(input) if want != got { t.Errorf("decode: want\n\t%q\nbut got\n\t%q", want, got) } diff --git a/libgo/go/html/template/js.go b/libgo/go/html/template/js.go index 999a61ed078..f6d166b3113 100644 --- a/libgo/go/html/template/js.go +++ b/libgo/go/html/template/js.go @@ -246,8 +246,10 @@ func jsRegexpEscaper(args ...interface{}) string { // `\u2029`. func replace(s string, replacementTable []string) string { var b bytes.Buffer - written := 0 - for i, r := range s { + r, w, written := rune(0), 0, 0 + for i := 0; i < len(s); i += w { + // See comment in htmlEscaper. + r, w = utf8.DecodeRuneInString(s[i:]) var repl string switch { case int(r) < len(replacementTable) && replacementTable[r] != "": @@ -261,7 +263,7 @@ func replace(s string, replacementTable []string) string { } b.WriteString(s[written:i]) b.WriteString(repl) - written = i + utf8.RuneLen(r) + written = i + w } if written == 0 { return s diff --git a/libgo/go/html/template/template.go b/libgo/go/html/template/template.go index ce6170105cc..bb9140a4daf 100644 --- a/libgo/go/html/template/template.go +++ b/libgo/go/html/template/template.go @@ -51,11 +51,37 @@ func (t *Template) Templates() []*Template { return m } +// Option sets options for the template. Options are described by +// strings, either a simple string or "key=value". There can be at +// most one equals sign in an option string. If the option string +// is unrecognized or otherwise invalid, Option panics. +// +// Known options: +// +// missingkey: Control the behavior during execution if a map is +// indexed with a key that is not present in the map. +// "missingkey=default" or "missingkey=invalid" +// The default behavior: Do nothing and continue execution. +// If printed, the result of the index operation is the string +// "". +// "missingkey=zero" +// The operation returns the zero value for the map type's element. +// "missingkey=error" +// Execution stops immediately with an error. +// +func (t *Template) Option(opt ...string) *Template { + t.text.Option(opt...) + return t +} + // escape escapes all associated templates. func (t *Template) escape() error { t.nameSpace.mu.Lock() defer t.nameSpace.mu.Unlock() if t.escapeErr == nil { + if t.Tree == nil { + return fmt.Errorf("template: %q is an incomplete or empty template%s", t.Name(), t.text.DefinedTemplates()) + } if err := escapeTemplate(t, t.text.Root, t.Name()); err != nil { return err } diff --git a/libgo/go/html/template/transition.go b/libgo/go/html/template/transition.go index b486fcd2854..d2e028741a1 100644 --- a/libgo/go/html/template/transition.go +++ b/libgo/go/html/template/transition.go @@ -183,24 +183,54 @@ func tHTMLCmt(c context, s []byte) (context, int) { // specialTagEndMarkers maps element types to the character sequence that // case-insensitively signals the end of the special tag body. -var specialTagEndMarkers = [...]string{ - elementScript: " \t\n\f/") +) + // tSpecialTagEnd is the context transition function for raw text and RCDATA // element states. func tSpecialTagEnd(c context, s []byte) (context, int) { if c.element != elementNone { - if i := strings.Index(strings.ToLower(string(s)), specialTagEndMarkers[c.element]); i != -1 { + if i := indexTagEnd(s, specialTagEndMarkers[c.element]); i != -1 { return context{}, i } } return c, len(s) } +// indexTagEnd finds the index of a special tag end in a case insensitive way, or returns -1 +func indexTagEnd(s []byte, tag []byte) int { + res := 0 + plen := len(specialTagEndPrefix) + for len(s) > 0 { + // Try to find the tag end prefix first + i := bytes.Index(s, specialTagEndPrefix) + if i == -1 { + return i + } + s = s[i+plen:] + // Try to match the actual tag if there is still space for it + if len(tag) <= len(s) && bytes.EqualFold(tag, s[:len(tag)]) { + s = s[len(tag):] + // Check the tag is followed by a proper separator + if len(s) > 0 && bytes.IndexByte(tagEndSeparators, s[0]) != -1 { + return res + i + } + res += len(tag) + } + res += i + plen + } + return -1 +} + // tAttr is the context transition function for the attribute state. func tAttr(c context, s []byte) (context, int) { return c, len(s) diff --git a/libgo/go/html/template/transition_test.go b/libgo/go/html/template/transition_test.go new file mode 100644 index 00000000000..412a4c71b75 --- /dev/null +++ b/libgo/go/html/template/transition_test.go @@ -0,0 +1,60 @@ +// 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 template + +import ( + "bytes" + "strings" + "testing" +) + +func TestFindEndTag(t *testing.T) { + tests := []struct { + s, tag string + want int + }{ + {"", "tag", -1}, + {"hello hello", "textarea", 6}, + {"hello hello", "textarea", 6}, + {"hello ", "textarea", 6}, + {"hello ", "tag", -1}, + {"hello tag ", "textarea", 22}, + {" ", "textarea", 0}, + {"
", "textarea", 13}, + {"
", "textarea", 13}, + {"
", "textarea", 13}, + {"
", "textarea", 14}, + {"<", "script", 1}, + {"", "textarea", -1}, + } + for _, test := range tests { + if got := indexTagEnd([]byte(test.s), []byte(test.tag)); test.want != got { + t.Errorf("%q/%q: want\n\t%d\nbut got\n\t%d", test.s, test.tag, test.want, got) + } + } +} + +func BenchmarkTemplateSpecialTags(b *testing.B) { + + r := struct { + Name, Gift string + }{"Aunt Mildred", "bone china tea set"} + + h1 := " " + h2 := "" + html := strings.Repeat(h1, 100) + h2 + strings.Repeat(h1, 100) + h2 + + var buf bytes.Buffer + for i := 0; i < b.N; i++ { + tmpl := Must(New("foo").Parse(html)) + if err := tmpl.Execute(&buf, r); err != nil { + b.Fatal(err) + } + buf.Reset() + } +} diff --git a/libgo/go/image/color/color.go b/libgo/go/image/color/color.go index ff596a76a36..cae059b6daa 100644 --- a/libgo/go/image/color/color.go +++ b/libgo/go/image/color/color.go @@ -9,14 +9,20 @@ package color // The conversion may be lossy. type Color interface { // RGBA returns the alpha-premultiplied red, green, blue and alpha values - // for the color. Each value ranges within [0, 0xFFFF], but is represented - // by a uint32 so that multiplying by a blend factor up to 0xFFFF will not + // for the color. Each value ranges within [0, 0xffff], but is represented + // by a uint32 so that multiplying by a blend factor up to 0xffff will not // overflow. + // + // An alpha-premultiplied color component c has been scaled by alpha (a), + // so has valid values 0 <= c <= a. RGBA() (r, g, b, a uint32) } -// RGBA represents a traditional 32-bit alpha-premultiplied color, -// having 8 bits for each of red, green, blue and alpha. +// RGBA represents a traditional 32-bit alpha-premultiplied color, having 8 +// bits for each of red, green, blue and alpha. +// +// An alpha-premultiplied color component C has been scaled by alpha (A), so +// has valid values 0 <= C <= A. type RGBA struct { R, G, B, A uint8 } @@ -33,8 +39,11 @@ func (c RGBA) RGBA() (r, g, b, a uint32) { return } -// RGBA64 represents a 64-bit alpha-premultiplied color, -// having 16 bits for each of red, green, blue and alpha. +// RGBA64 represents a 64-bit alpha-premultiplied color, having 16 bits for +// each of red, green, blue and alpha. +// +// An alpha-premultiplied color component C has been scaled by alpha (A), so +// has valid values 0 <= C <= A. type RGBA64 struct { R, G, B, A uint16 } @@ -262,32 +271,39 @@ func (p Palette) Convert(c Color) Color { } // Index returns the index of the palette color closest to c in Euclidean -// R,G,B space. +// R,G,B,A space. func (p Palette) Index(c Color) int { // A batch version of this computation is in image/draw/draw.go. - cr, cg, cb, _ := c.RGBA() - ret, bestSSD := 0, uint32(1<<32-1) + cr, cg, cb, ca := c.RGBA() + ret, bestSum := 0, uint32(1<<32-1) for i, v := range p { - vr, vg, vb, _ := v.RGBA() - // We shift by 1 bit to avoid potential uint32 overflow in - // sum-squared-difference. - delta := (int32(cr) - int32(vr)) >> 1 - ssd := uint32(delta * delta) - delta = (int32(cg) - int32(vg)) >> 1 - ssd += uint32(delta * delta) - delta = (int32(cb) - int32(vb)) >> 1 - ssd += uint32(delta * delta) - if ssd < bestSSD { - if ssd == 0 { + vr, vg, vb, va := v.RGBA() + sum := sqDiff(cr, vr) + sqDiff(cg, vg) + sqDiff(cb, vb) + sqDiff(ca, va) + if sum < bestSum { + if sum == 0 { return i } - ret, bestSSD = i, ssd + ret, bestSum = i, sum } } return ret } +// sqDiff returns the squared-difference of x and y, shifted by 2 so that +// adding four of those won't overflow a uint32. +// +// x and y are both assumed to be in the range [0, 0xffff]. +func sqDiff(x, y uint32) uint32 { + var d uint32 + if x > y { + d = x - y + } else { + d = y - x + } + return (d * d) >> 2 +} + // Standard colors. var ( Black = Gray16{0} diff --git a/libgo/go/image/color/ycbcr.go b/libgo/go/image/color/ycbcr.go index 4c2f29ea021..4bcb07dce22 100644 --- a/libgo/go/image/color/ycbcr.go +++ b/libgo/go/image/color/ycbcr.go @@ -11,26 +11,27 @@ func RGBToYCbCr(r, g, b uint8) (uint8, uint8, uint8) { // Cb = -0.1687*R - 0.3313*G + 0.5000*B + 128 // Cr = 0.5000*R - 0.4187*G - 0.0813*B + 128 // http://www.w3.org/Graphics/JPEG/jfif3.pdf says Y but means Y'. - r1 := int(r) - g1 := int(g) - b1 := int(b) + + r1 := int32(r) + g1 := int32(g) + b1 := int32(b) yy := (19595*r1 + 38470*g1 + 7471*b1 + 1<<15) >> 16 cb := (-11056*r1 - 21712*g1 + 32768*b1 + 257<<15) >> 16 cr := (32768*r1 - 27440*g1 - 5328*b1 + 257<<15) >> 16 if yy < 0 { yy = 0 - } else if yy > 255 { - yy = 255 + } else if yy > 0xff { + yy = 0xff } if cb < 0 { cb = 0 - } else if cb > 255 { - cb = 255 + } else if cb > 0xff { + cb = 0xff } if cr < 0 { cr = 0 - } else if cr > 255 { - cr = 255 + } else if cr > 0xff { + cr = 0xff } return uint8(yy), uint8(cb), uint8(cr) } @@ -42,26 +43,27 @@ func YCbCrToRGB(y, cb, cr uint8) (uint8, uint8, uint8) { // G = Y' - 0.34414*(Cb-128) - 0.71414*(Cr-128) // B = Y' + 1.77200*(Cb-128) // http://www.w3.org/Graphics/JPEG/jfif3.pdf says Y but means Y'. - yy1 := int(y)<<16 + 1<<15 - cb1 := int(cb) - 128 - cr1 := int(cr) - 128 + + yy1 := int32(y) * 0x10100 // Convert 0x12 to 0x121200. + cb1 := int32(cb) - 128 + cr1 := int32(cr) - 128 r := (yy1 + 91881*cr1) >> 16 g := (yy1 - 22554*cb1 - 46802*cr1) >> 16 b := (yy1 + 116130*cb1) >> 16 if r < 0 { r = 0 - } else if r > 255 { - r = 255 + } else if r > 0xff { + r = 0xff } if g < 0 { g = 0 - } else if g > 255 { - g = 255 + } else if g > 0xff { + g = 0xff } if b < 0 { b = 0 - } else if b > 255 { - b = 255 + } else if b > 0xff { + b = 0xff } return uint8(r), uint8(g), uint8(b) } @@ -82,8 +84,45 @@ type YCbCr struct { } func (c YCbCr) RGBA() (uint32, uint32, uint32, uint32) { - r, g, b := YCbCrToRGB(c.Y, c.Cb, c.Cr) - return uint32(r) * 0x101, uint32(g) * 0x101, uint32(b) * 0x101, 0xffff + // This code is a copy of the YCbCrToRGB function above, except that it + // returns values in the range [0, 0xffff] instead of [0, 0xff]. There is a + // subtle difference between doing this and having YCbCr satisfy the Color + // interface by first converting to an RGBA. The latter loses some + // information by going to and from 8 bits per channel. + // + // For example, this code: + // const y, cb, cr = 0x7f, 0x7f, 0x7f + // r, g, b := color.YCbCrToRGB(y, cb, cr) + // r0, g0, b0, _ := color.YCbCr{y, cb, cr}.RGBA() + // r1, g1, b1, _ := color.RGBA{r, g, b, 0xff}.RGBA() + // fmt.Printf("0x%04x 0x%04x 0x%04x\n", r0, g0, b0) + // fmt.Printf("0x%04x 0x%04x 0x%04x\n", r1, g1, b1) + // prints: + // 0x7e18 0x808e 0x7db9 + // 0x7e7e 0x8080 0x7d7d + + yy1 := int32(c.Y) * 0x10100 // Convert 0x12 to 0x121200. + cb1 := int32(c.Cb) - 128 + cr1 := int32(c.Cr) - 128 + r := (yy1 + 91881*cr1) >> 8 + g := (yy1 - 22554*cb1 - 46802*cr1) >> 8 + b := (yy1 + 116130*cb1) >> 8 + if r < 0 { + r = 0 + } else if r > 0xffff { + r = 0xffff + } + if g < 0 { + g = 0 + } else if g > 0xffff { + g = 0xffff + } + if b < 0 { + b = 0 + } else if b > 0xffff { + b = 0xffff + } + return uint32(r), uint32(g), uint32(b), 0xffff } // YCbCrModel is the Model for Y'CbCr colors. @@ -97,3 +136,64 @@ func yCbCrModel(c Color) Color { y, u, v := RGBToYCbCr(uint8(r>>8), uint8(g>>8), uint8(b>>8)) return YCbCr{y, u, v} } + +// RGBToCMYK converts an RGB triple to a CMYK quadruple. +func RGBToCMYK(r, g, b uint8) (uint8, uint8, uint8, uint8) { + rr := uint32(r) + gg := uint32(g) + bb := uint32(b) + w := rr + if w < gg { + w = gg + } + if w < bb { + w = bb + } + if w == 0 { + return 0, 0, 0, 0xff + } + c := (w - rr) * 0xff / w + m := (w - gg) * 0xff / w + y := (w - bb) * 0xff / w + return uint8(c), uint8(m), uint8(y), uint8(0xff - w) +} + +// CMYKToRGB converts a CMYK quadruple to an RGB triple. +func CMYKToRGB(c, m, y, k uint8) (uint8, uint8, uint8) { + w := uint32(0xffff - uint32(k)*0x101) + r := uint32(0xffff-uint32(c)*0x101) * w / 0xffff + g := uint32(0xffff-uint32(m)*0x101) * w / 0xffff + b := uint32(0xffff-uint32(y)*0x101) * w / 0xffff + return uint8(r >> 8), uint8(g >> 8), uint8(b >> 8) +} + +// CMYK represents a fully opaque CMYK color, having 8 bits for each of cyan, +// magenta, yellow and black. +// +// It is not associated with any particular color profile. +type CMYK struct { + C, M, Y, K uint8 +} + +func (c CMYK) RGBA() (uint32, uint32, uint32, uint32) { + // This code is a copy of the CMYKToRGB function above, except that it + // returns values in the range [0, 0xffff] instead of [0, 0xff]. + + w := uint32(0xffff - uint32(c.K)*0x101) + r := uint32(0xffff-uint32(c.C)*0x101) * w / 0xffff + g := uint32(0xffff-uint32(c.M)*0x101) * w / 0xffff + b := uint32(0xffff-uint32(c.Y)*0x101) * w / 0xffff + return uint32(r), uint32(g), uint32(b), 0xffff +} + +// CMYKModel is the Model for CMYK colors. +var CMYKModel Model = ModelFunc(cmykModel) + +func cmykModel(c Color) Color { + if _, ok := c.(CMYK); ok { + return c + } + r, g, b, _ := c.RGBA() + cc, mm, yy, kk := RGBToCMYK(uint8(r>>8), uint8(g>>8), uint8(b>>8)) + return CMYK{cc, mm, yy, kk} +} diff --git a/libgo/go/image/color/ycbcr_test.go b/libgo/go/image/color/ycbcr_test.go index 92a0e6ff1e7..5da49d379aa 100644 --- a/libgo/go/image/color/ycbcr_test.go +++ b/libgo/go/image/color/ycbcr_test.go @@ -5,6 +5,7 @@ package color import ( + "fmt" "testing" ) @@ -15,19 +16,134 @@ func delta(x, y uint8) uint8 { return y - x } -// Test that a subset of RGB space can be converted to YCbCr and back to within -// 1/256 tolerance. -func TestRoundtrip(t *testing.T) { - for r := 0; r < 255; r += 7 { - for g := 0; g < 255; g += 5 { - for b := 0; b < 255; b += 3 { +func eq(c0, c1 Color) error { + r0, g0, b0, a0 := c0.RGBA() + r1, g1, b1, a1 := c1.RGBA() + if r0 != r1 || g0 != g1 || b0 != b1 || a0 != a1 { + return fmt.Errorf("got 0x%04x 0x%04x 0x%04x 0x%04x\nwant 0x%04x 0x%04x 0x%04x 0x%04x", + r0, g0, b0, a0, r1, g1, b1, a1) + } + return nil +} + +// TestYCbCrRoundtrip tests that a subset of RGB space can be converted to YCbCr +// and back to within 2/256 tolerance. +func TestYCbCrRoundtrip(t *testing.T) { + for r := 0; r < 256; r += 7 { + for g := 0; g < 256; g += 5 { + for b := 0; b < 256; b += 3 { r0, g0, b0 := uint8(r), uint8(g), uint8(b) y, cb, cr := RGBToYCbCr(r0, g0, b0) r1, g1, b1 := YCbCrToRGB(y, cb, cr) + if delta(r0, r1) > 2 || delta(g0, g1) > 2 || delta(b0, b1) > 2 { + t.Fatalf("\nr0, g0, b0 = %d, %d, %d\ny, cb, cr = %d, %d, %d\nr1, g1, b1 = %d, %d, %d", + r0, g0, b0, y, cb, cr, r1, g1, b1) + } + } + } + } +} + +// TestYCbCrToRGBConsistency tests that calling the RGBA method (16 bit color) +// then truncating to 8 bits is equivalent to calling the YCbCrToRGB function (8 +// bit color). +func TestYCbCrToRGBConsistency(t *testing.T) { + for y := 0; y < 256; y += 7 { + for cb := 0; cb < 256; cb += 5 { + for cr := 0; cr < 256; cr += 3 { + x := YCbCr{uint8(y), uint8(cb), uint8(cr)} + r0, g0, b0, _ := x.RGBA() + r1, g1, b1 := uint8(r0>>8), uint8(g0>>8), uint8(b0>>8) + r2, g2, b2 := YCbCrToRGB(x.Y, x.Cb, x.Cr) + if r1 != r2 || g1 != g2 || b1 != b2 { + t.Fatalf("y, cb, cr = %d, %d, %d\nr1, g1, b1 = %d, %d, %d\nr2, g2, b2 = %d, %d, %d", + y, cb, cr, r1, g1, b1, r2, g2, b2) + } + } + } + } +} + +// TestYCbCrGray tests that YCbCr colors are a superset of Gray colors. +func TestYCbCrGray(t *testing.T) { + for i := 0; i < 256; i++ { + if err := eq(YCbCr{uint8(i), 0x80, 0x80}, Gray{uint8(i)}); err != nil { + t.Errorf("i=0x%02x:\n%v", i, err) + } + } +} + +// TestCMYKRoundtrip tests that a subset of RGB space can be converted to CMYK +// and back to within 1/256 tolerance. +func TestCMYKRoundtrip(t *testing.T) { + for r := 0; r < 256; r += 7 { + for g := 0; g < 256; g += 5 { + for b := 0; b < 256; b += 3 { + r0, g0, b0 := uint8(r), uint8(g), uint8(b) + c, m, y, k := RGBToCMYK(r0, g0, b0) + r1, g1, b1 := CMYKToRGB(c, m, y, k) if delta(r0, r1) > 1 || delta(g0, g1) > 1 || delta(b0, b1) > 1 { - t.Fatalf("r0, g0, b0 = %d, %d, %d r1, g1, b1 = %d, %d, %d", r0, g0, b0, r1, g1, b1) + t.Fatalf("\nr0, g0, b0 = %d, %d, %d\nc, m, y, k = %d, %d, %d, %d\nr1, g1, b1 = %d, %d, %d", + r0, g0, b0, c, m, y, k, r1, g1, b1) } } } } } + +// TestCMYKToRGBConsistency tests that calling the RGBA method (16 bit color) +// then truncating to 8 bits is equivalent to calling the CMYKToRGB function (8 +// bit color). +func TestCMYKToRGBConsistency(t *testing.T) { + for c := 0; c < 256; c += 7 { + for m := 0; m < 256; m += 5 { + for y := 0; y < 256; y += 3 { + for k := 0; k < 256; k += 11 { + x := CMYK{uint8(c), uint8(m), uint8(y), uint8(k)} + r0, g0, b0, _ := x.RGBA() + r1, g1, b1 := uint8(r0>>8), uint8(g0>>8), uint8(b0>>8) + r2, g2, b2 := CMYKToRGB(x.C, x.M, x.Y, x.K) + if r1 != r2 || g1 != g2 || b1 != b2 { + t.Fatalf("c, m, y, k = %d, %d, %d, %d\nr1, g1, b1 = %d, %d, %d\nr2, g2, b2 = %d, %d, %d", + c, m, y, k, r1, g1, b1, r2, g2, b2) + } + } + } + } + } +} + +// TestCMYKGray tests that CMYK colors are a superset of Gray colors. +func TestCMYKGray(t *testing.T) { + for i := 0; i < 256; i++ { + if err := eq(CMYK{0x00, 0x00, 0x00, uint8(255 - i)}, Gray{uint8(i)}); err != nil { + t.Errorf("i=0x%02x:\n%v", i, err) + } + } +} + +func TestPalette(t *testing.T) { + p := Palette{ + RGBA{0xff, 0xff, 0xff, 0xff}, + RGBA{0x80, 0x00, 0x00, 0xff}, + RGBA{0x7f, 0x00, 0x00, 0x7f}, + RGBA{0x00, 0x00, 0x00, 0x7f}, + RGBA{0x00, 0x00, 0x00, 0x00}, + RGBA{0x40, 0x40, 0x40, 0x40}, + } + // Check that, for a Palette with no repeated colors, the closest color to + // each element is itself. + for i, c := range p { + j := p.Index(c) + if i != j { + t.Errorf("Index(%v): got %d (color = %v), want %d", c, j, p[j], i) + } + } + // Check that finding the closest color considers alpha, not just red, + // green and blue. + got := p.Convert(RGBA{0x80, 0x00, 0x00, 0x80}) + want := RGBA{0x7f, 0x00, 0x00, 0x7f} + if got != want { + t.Errorf("got %v, want %v", got, want) + } +} diff --git a/libgo/go/image/decode_example_test.go b/libgo/go/image/decode_example_test.go index 21e90fea4f8..81fa0378e17 100644 --- a/libgo/go/image/decode_example_test.go +++ b/libgo/go/image/decode_example_test.go @@ -61,22 +61,22 @@ func Example() { } // Output: // bin red green blue alpha - // 0x0000-0x0fff: 353 759 7228 0 - // 0x1000-0x1fff: 629 2944 1036 0 - // 0x2000-0x2fff: 1075 2319 984 0 - // 0x3000-0x3fff: 838 2291 988 0 - // 0x4000-0x4fff: 540 1302 542 0 - // 0x5000-0x5fff: 319 971 263 0 - // 0x6000-0x6fff: 316 377 178 0 - // 0x7000-0x7fff: 581 280 216 0 - // 0x8000-0x8fff: 3457 228 274 0 - // 0x9000-0x9fff: 2294 237 334 0 - // 0xa000-0xafff: 938 283 370 0 - // 0xb000-0xbfff: 322 338 401 0 - // 0xc000-0xcfff: 229 386 295 0 - // 0xd000-0xdfff: 263 416 281 0 - // 0xe000-0xefff: 538 433 312 0 - // 0xf000-0xffff: 2758 1886 1748 15450 + // 0x0000-0x0fff: 364 790 7242 0 + // 0x1000-0x1fff: 645 2967 1039 0 + // 0x2000-0x2fff: 1072 2299 979 0 + // 0x3000-0x3fff: 820 2266 980 0 + // 0x4000-0x4fff: 537 1305 541 0 + // 0x5000-0x5fff: 319 962 261 0 + // 0x6000-0x6fff: 322 375 177 0 + // 0x7000-0x7fff: 601 279 214 0 + // 0x8000-0x8fff: 3478 227 273 0 + // 0x9000-0x9fff: 2260 234 329 0 + // 0xa000-0xafff: 921 282 373 0 + // 0xb000-0xbfff: 321 335 397 0 + // 0xc000-0xcfff: 229 388 298 0 + // 0xd000-0xdfff: 260 414 277 0 + // 0xe000-0xefff: 516 428 298 0 + // 0xf000-0xffff: 2785 1899 1772 15450 } const data = ` diff --git a/libgo/go/image/decode_test.go b/libgo/go/image/decode_test.go index 8dee57ee467..d16ef8a1a4d 100644 --- a/libgo/go/image/decode_test.go +++ b/libgo/go/image/decode_test.go @@ -6,6 +6,7 @@ package image_test import ( "bufio" + "fmt" "image" "image/color" "os" @@ -32,6 +33,9 @@ var imageTests = []imageTest{ // JPEG is a lossy format and hence needs a non-zero tolerance. {"testdata/video-001.png", "testdata/video-001.jpeg", 8 << 8}, {"testdata/video-001.png", "testdata/video-001.progressive.jpeg", 8 << 8}, + {"testdata/video-001.221212.png", "testdata/video-001.221212.jpeg", 8 << 8}, + {"testdata/video-001.cmyk.png", "testdata/video-001.cmyk.jpeg", 8 << 8}, + {"testdata/video-001.rgb.png", "testdata/video-001.rgb.jpeg", 8 << 8}, // Grayscale images. {"testdata/video-005.gray.png", "testdata/video-005.gray.jpeg", 8 << 8}, {"testdata/video-005.gray.png", "testdata/video-005.gray.png", 0}, @@ -74,6 +78,11 @@ func withinTolerance(c0, c1 color.Color, tolerance int) bool { } func TestDecode(t *testing.T) { + rgba := func(c color.Color) string { + r, g, b, a := c.RGBA() + return fmt.Sprintf("rgba = 0x%04x, 0x%04x, 0x%04x, 0x%04x for %T%v", r, g, b, a, c, c) + } + golden := make(map[string]image.Image) loop: for _, it := range imageTests { @@ -94,13 +103,14 @@ loop: } b := g.Bounds() if !b.Eq(m.Bounds()) { - t.Errorf("%s: want bounds %v got %v", it.filename, b, m.Bounds()) + t.Errorf("%s: got bounds %v want %v", it.filename, m.Bounds(), b) continue loop } for y := b.Min.Y; y < b.Max.Y; y++ { for x := b.Min.X; x < b.Max.X; x++ { if !withinTolerance(g.At(x, y), m.At(x, y), it.tolerance) { - t.Errorf("%s: at (%d, %d), want %v got %v", it.filename, x, y, g.At(x, y), m.At(x, y)) + t.Errorf("%s: at (%d, %d):\ngot %v\nwant %v", + it.filename, x, y, rgba(m.At(x, y)), rgba(g.At(x, y))) continue loop } } diff --git a/libgo/go/image/draw/bench_test.go b/libgo/go/image/draw/bench_test.go index cc62e25f1bb..7b89f95d118 100644 --- a/libgo/go/image/draw/bench_test.go +++ b/libgo/go/image/draw/bench_test.go @@ -7,6 +7,7 @@ package draw import ( "image" "image/color" + "reflect" "testing" ) @@ -15,6 +16,11 @@ const ( srcw, srch = 400, 300 ) +var palette = color.Palette{ + color.Black, + color.White, +} + // bench benchmarks drawing src and mask images onto a dst image with the // given op and the color models to create those images from. // The created images' pixels are initialized to non-zero values. @@ -50,13 +56,48 @@ func bench(b *testing.B, dcm, scm, mcm color.Model, op Op) { } dst = dst1 default: - b.Fatal("unknown destination color model", dcm) + // The == operator isn't defined on a color.Palette (a slice), so we + // use reflection. + if reflect.DeepEqual(dcm, palette) { + dst1 := image.NewPaletted(image.Rect(0, 0, dstw, dsth), palette) + for y := 0; y < dsth; y++ { + for x := 0; x < dstw; x++ { + dst1.SetColorIndex(x, y, uint8(x^y)&1) + } + } + dst = dst1 + } else { + b.Fatal("unknown destination color model", dcm) + } } var src image.Image switch scm { case nil: src = &image.Uniform{C: color.RGBA{0x11, 0x22, 0x33, 0xff}} + case color.CMYKModel: + src1 := image.NewCMYK(image.Rect(0, 0, srcw, srch)) + for y := 0; y < srch; y++ { + for x := 0; x < srcw; x++ { + src1.SetCMYK(x, y, color.CMYK{ + uint8(13 * x % 0x100), + uint8(11 * y % 0x100), + uint8((11*x + 13*y) % 0x100), + uint8((31*x + 37*y) % 0x100), + }) + } + } + src = src1 + case color.GrayModel: + src1 := image.NewGray(image.Rect(0, 0, srcw, srch)) + for y := 0; y < srch; y++ { + for x := 0; x < srcw; x++ { + src1.SetGray(x, y, color.Gray{ + uint8((11*x + 13*y) % 0x100), + }) + } + } + src = src1 case color.RGBAModel: src1 := image.NewRGBA(image.Rect(0, 0, srcw, srch)) for y := 0; y < srch; y++ { @@ -179,6 +220,14 @@ func BenchmarkYCbCr(b *testing.B) { bench(b, color.RGBAModel, color.YCbCrModel, nil, Over) } +func BenchmarkGray(b *testing.B) { + bench(b, color.RGBAModel, color.GrayModel, nil, Over) +} + +func BenchmarkCMYK(b *testing.B) { + bench(b, color.RGBAModel, color.CMYKModel, nil, Over) +} + func BenchmarkGlyphOver(b *testing.B) { bench(b, color.RGBAModel, nil, color.AlphaModel, Over) } @@ -187,6 +236,10 @@ func BenchmarkRGBA(b *testing.B) { bench(b, color.RGBAModel, color.RGBA64Model, nil, Src) } +func BenchmarkPaletted(b *testing.B) { + bench(b, palette, color.RGBAModel, nil, Src) +} + // The BenchmarkGenericFoo functions exercise the generic, slow-path code. func BenchmarkGenericOver(b *testing.B) { diff --git a/libgo/go/image/draw/clip_test.go b/libgo/go/image/draw/clip_test.go index 65381f72f65..0abf53e5c78 100644 --- a/libgo/go/image/draw/clip_test.go +++ b/libgo/go/image/draw/clip_test.go @@ -139,7 +139,19 @@ var clipTests = []clipTest{ image.Pt(20, 0), image.Pt(20, 0), }, - // TODO(nigeltao): write more tests. + { + "clip sr and mr", + image.Rect(0, 0, 100, 100), + image.Rect(0, 0, 100, 100), + image.Rect(23, 23, 55, 86), + image.Rect(44, 44, 87, 58), + image.Pt(10, 10), + image.Pt(11, 11), + false, + image.Rect(33, 33, 45, 47), + image.Pt(43, 43), + image.Pt(44, 44), + }, } func TestClip(t *testing.T) { @@ -149,12 +161,12 @@ func TestClip(t *testing.T) { for _, c := range clipTests { dst := dst0.SubImage(c.dr).(*image.RGBA) src := src0.SubImage(c.sr).(*image.RGBA) - var mask image.Image - if !c.nilMask { - mask = mask0.SubImage(c.mr) - } r, sp, mp := c.r, c.sp, c.mp - clip(dst, &r, src, &sp, mask, &mp) + if c.nilMask { + clip(dst, &r, src, &sp, nil, nil) + } else { + clip(dst, &r, src, &sp, mask0.SubImage(c.mr), &mp) + } // Check that the actual results equal the expected results. if !c.r0.Eq(r) { @@ -173,17 +185,17 @@ func TestClip(t *testing.T) { } // Check that the clipped rectangle is contained by the dst / src / mask - // rectangles, in their respective co-ordinate spaces. + // rectangles, in their respective coordinate spaces. if !r.In(c.dr) { t.Errorf("%s: c.dr %v does not contain r %v", c.desc, c.dr, r) } - // sr is r translated into src's co-ordinate space. + // sr is r translated into src's coordinate space. sr := r.Add(c.sp.Sub(c.dr.Min)) if !sr.In(c.sr) { t.Errorf("%s: c.sr %v does not contain sr %v", c.desc, c.sr, sr) } if !c.nilMask { - // mr is r translated into mask's co-ordinate space. + // mr is r translated into mask's coordinate space. mr := r.Add(c.mp.Sub(c.dr.Min)) if !mr.In(c.mr) { t.Errorf("%s: c.mr %v does not contain mr %v", c.desc, c.mr, mr) diff --git a/libgo/go/image/draw/draw.go b/libgo/go/image/draw/draw.go index 661230e7c59..9419d5e72a7 100644 --- a/libgo/go/image/draw/draw.go +++ b/libgo/go/image/draw/draw.go @@ -5,12 +5,13 @@ // Package draw provides image composition functions. // // See "The Go image/draw package" for an introduction to this package: -// http://golang.org/doc/articles/image_draw.html +// https://golang.org/doc/articles/image_draw.html package draw import ( "image" "image/color" + "image/internal/imageutil" ) // m is the maximum color value returned by image.Color.RGBA. @@ -67,7 +68,7 @@ func (floydSteinberg) Draw(dst Image, r image.Rectangle, src image.Image, sp ima } // clip clips r against each image's bounds (after translating into the -// destination image's co-ordinate space) and shifts the points sp and mp by +// destination image's coordinate space) and shifts the points sp and mp by // the same amount as the change in r.Min. func clip(dst Image, r *image.Rectangle, src image.Image, sp *image.Point, mask image.Image, mp *image.Point) { orig := r.Min @@ -81,10 +82,12 @@ func clip(dst Image, r *image.Rectangle, src image.Image, sp *image.Point, mask if dx == 0 && dy == 0 { return } - (*sp).X += dx - (*sp).Y += dy - (*mp).X += dx - (*mp).Y += dy + sp.X += dx + sp.Y += dy + if mp != nil { + mp.X += dx + mp.Y += dy + } } func processBackward(dst Image, r image.Rectangle, src image.Image, sp image.Point) bool { @@ -122,9 +125,19 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas drawNRGBAOver(dst0, r, src0, sp) return case *image.YCbCr: - if drawYCbCr(dst0, r, src0, sp) { + // An image.YCbCr is always fully opaque, and so if the + // mask is nil (i.e. fully opaque) then the op is + // effectively always Src. Similarly for image.Gray and + // image.CMYK. + if imageutil.DrawYCbCr(dst0, r, src0, sp) { return } + case *image.Gray: + drawGray(dst0, r, src0, sp) + return + case *image.CMYK: + drawCMYK(dst0, r, src0, sp) + return } } else if mask0, ok := mask.(*image.Alpha); ok { switch src0 := src.(type) { @@ -146,9 +159,15 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas drawNRGBASrc(dst0, r, src0, sp) return case *image.YCbCr: - if drawYCbCr(dst0, r, src0, sp) { + if imageutil.DrawYCbCr(dst0, r, src0, sp) { return } + case *image.Gray: + drawGray(dst0, r, src0, sp) + return + case *image.CMYK: + drawCMYK(dst0, r, src0, sp) + return } } } @@ -157,6 +176,7 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas case *image.Paletted: if op == Src && mask == nil && !processBackward(dst, r, src, sp) { drawPaletted(dst0, r, src, sp, false) + return } } @@ -237,16 +257,20 @@ func drawFillOver(dst *image.RGBA, r image.Rectangle, src *image.Uniform) { func drawFillSrc(dst *image.RGBA, r image.Rectangle, src *image.Uniform) { sr, sg, sb, sa := src.RGBA() + sr8 := uint8(sr >> 8) + sg8 := uint8(sg >> 8) + sb8 := uint8(sb >> 8) + sa8 := uint8(sa >> 8) // The built-in copy function is faster than a straightforward for loop to fill the destination with // the color, but copy requires a slice source. We therefore use a for loop to fill the first row, and // then use the first row as the slice source for the remaining rows. i0 := dst.PixOffset(r.Min.X, r.Min.Y) i1 := i0 + r.Dx()*4 for i := i0; i < i1; i += 4 { - dst.Pix[i+0] = uint8(sr >> 8) - dst.Pix[i+1] = uint8(sg >> 8) - dst.Pix[i+2] = uint8(sb >> 8) - dst.Pix[i+3] = uint8(sa >> 8) + dst.Pix[i+0] = sr8 + dst.Pix[i+1] = sg8 + dst.Pix[i+2] = sb8 + dst.Pix[i+3] = sa8 } firstRow := dst.Pix[i0:i1] for y := r.Min.Y + 1; y < r.Max.Y; y++ { @@ -313,9 +337,11 @@ func drawCopySrc(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.P ddelta = dst.Stride sdelta = src.Stride } else { - // If the source start point is higher than the destination start point, then we compose the rows - // in bottom-up order instead of top-down. Unlike the drawCopyOver function, we don't have to - // check the x co-ordinates because the built-in copy function can handle overlapping slices. + // If the source start point is higher than the destination start + // point, then we compose the rows in bottom-up order instead of + // top-down. Unlike the drawCopyOver function, we don't have to check + // the x coordinates because the built-in copy function can handle + // overlapping slices. d0 += (dy - 1) * dst.Stride s0 += (dy - 1) * src.Stride ddelta = -dst.Stride @@ -390,72 +416,46 @@ func drawNRGBASrc(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp image } } -func drawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Point) (ok bool) { - // An image.YCbCr is always fully opaque, and so if the mask is implicitly nil - // (i.e. fully opaque) then the op is effectively always Src. - x0 := (r.Min.X - dst.Rect.Min.X) * 4 - x1 := (r.Max.X - dst.Rect.Min.X) * 4 - y0 := r.Min.Y - dst.Rect.Min.Y - y1 := r.Max.Y - dst.Rect.Min.Y - switch src.SubsampleRatio { - case image.YCbCrSubsampleRatio444: - for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 { - dpix := dst.Pix[y*dst.Stride:] - yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X) - ci := (sy-src.Rect.Min.Y)*src.CStride + (sp.X - src.Rect.Min.X) - for x := x0; x != x1; x, yi, ci = x+4, yi+1, ci+1 { - rr, gg, bb := color.YCbCrToRGB(src.Y[yi], src.Cb[ci], src.Cr[ci]) - dpix[x+0] = rr - dpix[x+1] = gg - dpix[x+2] = bb - dpix[x+3] = 255 - } - } - case image.YCbCrSubsampleRatio422: - for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 { - dpix := dst.Pix[y*dst.Stride:] - yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X) - ciBase := (sy-src.Rect.Min.Y)*src.CStride - src.Rect.Min.X/2 - for x, sx := x0, sp.X; x != x1; x, sx, yi = x+4, sx+1, yi+1 { - ci := ciBase + sx/2 - rr, gg, bb := color.YCbCrToRGB(src.Y[yi], src.Cb[ci], src.Cr[ci]) - dpix[x+0] = rr - dpix[x+1] = gg - dpix[x+2] = bb - dpix[x+3] = 255 - } - } - case image.YCbCrSubsampleRatio420: - for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 { - dpix := dst.Pix[y*dst.Stride:] - yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X) - ciBase := (sy/2-src.Rect.Min.Y/2)*src.CStride - src.Rect.Min.X/2 - for x, sx := x0, sp.X; x != x1; x, sx, yi = x+4, sx+1, yi+1 { - ci := ciBase + sx/2 - rr, gg, bb := color.YCbCrToRGB(src.Y[yi], src.Cb[ci], src.Cr[ci]) - dpix[x+0] = rr - dpix[x+1] = gg - dpix[x+2] = bb - dpix[x+3] = 255 - } +func drawGray(dst *image.RGBA, r image.Rectangle, src *image.Gray, sp image.Point) { + i0 := (r.Min.X - dst.Rect.Min.X) * 4 + i1 := (r.Max.X - dst.Rect.Min.X) * 4 + si0 := (sp.X - src.Rect.Min.X) * 1 + yMax := r.Max.Y - dst.Rect.Min.Y + + y := r.Min.Y - dst.Rect.Min.Y + sy := sp.Y - src.Rect.Min.Y + for ; y != yMax; y, sy = y+1, sy+1 { + dpix := dst.Pix[y*dst.Stride:] + spix := src.Pix[sy*src.Stride:] + + for i, si := i0, si0; i < i1; i, si = i+4, si+1 { + p := spix[si] + dpix[i+0] = p + dpix[i+1] = p + dpix[i+2] = p + dpix[i+3] = 255 } - case image.YCbCrSubsampleRatio440: - for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 { - dpix := dst.Pix[y*dst.Stride:] - yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X) - ci := (sy/2-src.Rect.Min.Y/2)*src.CStride + (sp.X - src.Rect.Min.X) - for x := x0; x != x1; x, yi, ci = x+4, yi+1, ci+1 { - rr, gg, bb := color.YCbCrToRGB(src.Y[yi], src.Cb[ci], src.Cr[ci]) - dpix[x+0] = rr - dpix[x+1] = gg - dpix[x+2] = bb - dpix[x+3] = 255 - } + } +} + +func drawCMYK(dst *image.RGBA, r image.Rectangle, src *image.CMYK, sp image.Point) { + i0 := (r.Min.X - dst.Rect.Min.X) * 4 + i1 := (r.Max.X - dst.Rect.Min.X) * 4 + si0 := (sp.X - src.Rect.Min.X) * 4 + yMax := r.Max.Y - dst.Rect.Min.Y + + y := r.Min.Y - dst.Rect.Min.Y + sy := sp.Y - src.Rect.Min.Y + for ; y != yMax; y, sy = y+1, sy+1 { + dpix := dst.Pix[y*dst.Stride:] + spix := src.Pix[sy*src.Stride:] + + for i, si := i0, si0; i < i1; i, si = i+4, si+4 { + dpix[i+0], dpix[i+1], dpix[i+2] = + color.CMYKToRGB(spix[si+0], spix[si+1], spix[si+2], spix[si+3]) + dpix[i+3] = 255 } - default: - return false } - return true } func drawGlyphOver(dst *image.RGBA, r image.Rectangle, src *image.Uniform, mask *image.Alpha, mp image.Point) { @@ -555,6 +555,20 @@ func clamp(i int32) int32 { return i } +// sqDiff returns the squared-difference of x and y, shifted by 2 so that +// adding four of those won't overflow a uint32. +// +// x and y are both assumed to be in the range [0, 0xffff]. +func sqDiff(x, y int32) uint32 { + var d uint32 + if x > y { + d = uint32(x - y) + } else { + d = uint32(y - x) + } + return (d * d) >> 2 +} + func drawPaletted(dst Image, r image.Rectangle, src image.Image, sp image.Point, floydSteinberg bool) { // TODO(nigeltao): handle the case where the dst and src overlap. // Does it even make sense to try and do Floyd-Steinberg whilst @@ -564,14 +578,15 @@ func drawPaletted(dst Image, r image.Rectangle, src image.Image, sp image.Point, // dst.At. The dst.Set equivalent is a batch version of the algorithm // used by color.Palette's Index method in image/color/color.go, plus // optional Floyd-Steinberg error diffusion. - palette, pix, stride := [][3]int32(nil), []byte(nil), 0 + palette, pix, stride := [][4]int32(nil), []byte(nil), 0 if p, ok := dst.(*image.Paletted); ok { - palette = make([][3]int32, len(p.Palette)) + palette = make([][4]int32, len(p.Palette)) for i, col := range p.Palette { - r, g, b, _ := col.RGBA() + r, g, b, a := col.RGBA() palette[i][0] = int32(r) palette[i][1] = int32(g) palette[i][2] = int32(b) + palette[i][3] = int32(a) } pix, stride = p.Pix[p.PixOffset(r.Min.X, r.Min.Y):], p.Stride } @@ -579,10 +594,10 @@ func drawPaletted(dst Image, r image.Rectangle, src image.Image, sp image.Point, // quantErrorCurr and quantErrorNext are the Floyd-Steinberg quantization // errors that have been propagated to the pixels in the current and next // rows. The +2 simplifies calculation near the edges. - var quantErrorCurr, quantErrorNext [][3]int32 + var quantErrorCurr, quantErrorNext [][4]int32 if floydSteinberg { - quantErrorCurr = make([][3]int32, r.Dx()+2) - quantErrorNext = make([][3]int32, r.Dx()+2) + quantErrorCurr = make([][4]int32, r.Dx()+2) + quantErrorNext = make([][4]int32, r.Dx()+2) } // Loop over each source pixel. @@ -591,30 +606,25 @@ func drawPaletted(dst Image, r image.Rectangle, src image.Image, sp image.Point, for x := 0; x != r.Dx(); x++ { // er, eg and eb are the pixel's R,G,B values plus the // optional Floyd-Steinberg error. - sr, sg, sb, _ := src.At(sp.X+x, sp.Y+y).RGBA() - er, eg, eb := int32(sr), int32(sg), int32(sb) + sr, sg, sb, sa := src.At(sp.X+x, sp.Y+y).RGBA() + er, eg, eb, ea := int32(sr), int32(sg), int32(sb), int32(sa) if floydSteinberg { er = clamp(er + quantErrorCurr[x+1][0]/16) eg = clamp(eg + quantErrorCurr[x+1][1]/16) eb = clamp(eb + quantErrorCurr[x+1][2]/16) + ea = clamp(ea + quantErrorCurr[x+1][3]/16) } if palette != nil { - // Find the closest palette color in Euclidean R,G,B space: the - // one that minimizes sum-squared-difference. We shift by 1 bit - // to avoid potential uint32 overflow in sum-squared-difference. + // Find the closest palette color in Euclidean R,G,B,A space: + // the one that minimizes sum-squared-difference. // TODO(nigeltao): consider smarter algorithms. - bestIndex, bestSSD := 0, uint32(1<<32-1) + bestIndex, bestSum := 0, uint32(1<<32-1) for index, p := range palette { - delta := (er - p[0]) >> 1 - ssd := uint32(delta * delta) - delta = (eg - p[1]) >> 1 - ssd += uint32(delta * delta) - delta = (eb - p[2]) >> 1 - ssd += uint32(delta * delta) - if ssd < bestSSD { - bestIndex, bestSSD = index, ssd - if ssd == 0 { + sum := sqDiff(er, p[0]) + sqDiff(eg, p[1]) + sqDiff(eb, p[2]) + sqDiff(ea, p[3]) + if sum < bestSum { + bestIndex, bestSum = index, sum + if sum == 0 { break } } @@ -627,11 +637,13 @@ func drawPaletted(dst Image, r image.Rectangle, src image.Image, sp image.Point, er -= int32(palette[bestIndex][0]) eg -= int32(palette[bestIndex][1]) eb -= int32(palette[bestIndex][2]) + ea -= int32(palette[bestIndex][3]) } else { out.R = uint16(er) out.G = uint16(eg) out.B = uint16(eb) + out.A = uint16(ea) // The third argument is &out instead of out (and out is // declared outside of the inner loop) to avoid the implicit // conversion to color.Color here allocating memory in the @@ -641,32 +653,37 @@ func drawPaletted(dst Image, r image.Rectangle, src image.Image, sp image.Point, if !floydSteinberg { continue } - sr, sg, sb, _ = dst.At(r.Min.X+x, r.Min.Y+y).RGBA() + sr, sg, sb, sa = dst.At(r.Min.X+x, r.Min.Y+y).RGBA() er -= int32(sr) eg -= int32(sg) eb -= int32(sb) + ea -= int32(sa) } // Propagate the Floyd-Steinberg quantization error. quantErrorNext[x+0][0] += er * 3 quantErrorNext[x+0][1] += eg * 3 quantErrorNext[x+0][2] += eb * 3 + quantErrorNext[x+0][3] += ea * 3 quantErrorNext[x+1][0] += er * 5 quantErrorNext[x+1][1] += eg * 5 quantErrorNext[x+1][2] += eb * 5 + quantErrorNext[x+1][3] += ea * 5 quantErrorNext[x+2][0] += er * 1 quantErrorNext[x+2][1] += eg * 1 quantErrorNext[x+2][2] += eb * 1 + quantErrorNext[x+2][3] += ea * 1 quantErrorCurr[x+2][0] += er * 7 quantErrorCurr[x+2][1] += eg * 7 quantErrorCurr[x+2][2] += eb * 7 + quantErrorCurr[x+2][3] += ea * 7 } // Recycle the quantization error buffers. if floydSteinberg { quantErrorCurr, quantErrorNext = quantErrorNext, quantErrorCurr for i := range quantErrorNext { - quantErrorNext[i] = [3]int32{} + quantErrorNext[i] = [4]int32{} } } } diff --git a/libgo/go/image/draw/draw_test.go b/libgo/go/image/draw/draw_test.go index 0dd7fbd479a..a58f0f49849 100644 --- a/libgo/go/image/draw/draw_test.go +++ b/libgo/go/image/draw/draw_test.go @@ -74,6 +74,26 @@ func vgradCr() image.Image { return m } +func vgradGray() image.Image { + m := image.NewGray(image.Rect(0, 0, 16, 16)) + for y := 0; y < 16; y++ { + for x := 0; x < 16; x++ { + m.Set(x, y, color.Gray{uint8(y * 0x11)}) + } + } + return m +} + +func vgradMagenta() image.Image { + m := image.NewCMYK(image.Rect(0, 0, 16, 16)) + for y := 0; y < 16; y++ { + for x := 0; x < 16; x++ { + m.Set(x, y, color.CMYK{0, uint8(y * 0x11), 0, 0x3f}) + } + } + return m +} + func hgradRed(alpha int) Image { m := image.NewRGBA(image.Rect(0, 0, 16, 16)) for y := 0; y < 16; y++ { @@ -147,6 +167,26 @@ var drawTests = []drawTest{ {"ycbcrAlphaSrc", vgradCr(), fillAlpha(192), Src, color.RGBA{8, 28, 0, 192}}, {"ycbcrNil", vgradCr(), nil, Over, color.RGBA{11, 38, 0, 255}}, {"ycbcrNilSrc", vgradCr(), nil, Src, color.RGBA{11, 38, 0, 255}}, + // Uniform mask (100%, 75%, nil) and variable Gray source. + // At (x, y) == (8, 8): + // The destination pixel is {136, 0, 0, 255}. + // The source pixel is {136} in Gray-space, which is {136, 136, 136, 255} in RGBA-space. + {"gray", vgradGray(), fillAlpha(255), Over, color.RGBA{136, 136, 136, 255}}, + {"graySrc", vgradGray(), fillAlpha(255), Src, color.RGBA{136, 136, 136, 255}}, + {"grayAlpha", vgradGray(), fillAlpha(192), Over, color.RGBA{136, 102, 102, 255}}, + {"grayAlphaSrc", vgradGray(), fillAlpha(192), Src, color.RGBA{102, 102, 102, 192}}, + {"grayNil", vgradGray(), nil, Over, color.RGBA{136, 136, 136, 255}}, + {"grayNilSrc", vgradGray(), nil, Src, color.RGBA{136, 136, 136, 255}}, + // Uniform mask (100%, 75%, nil) and variable CMYK source. + // At (x, y) == (8, 8): + // The destination pixel is {136, 0, 0, 255}. + // The source pixel is {0, 136, 0, 63} in CMYK-space, which is {192, 89, 192} in RGB-space. + {"cmyk", vgradMagenta(), fillAlpha(255), Over, color.RGBA{192, 89, 192, 255}}, + {"cmykSrc", vgradMagenta(), fillAlpha(255), Src, color.RGBA{192, 89, 192, 255}}, + {"cmykAlpha", vgradMagenta(), fillAlpha(192), Over, color.RGBA{178, 67, 145, 255}}, + {"cmykAlphaSrc", vgradMagenta(), fillAlpha(192), Src, color.RGBA{145, 67, 145, 192}}, + {"cmykNil", vgradMagenta(), nil, Over, color.RGBA{192, 89, 192, 255}}, + {"cmykNilSrc", vgradMagenta(), nil, Src, color.RGBA{192, 89, 192, 255}}, // Variable mask and variable source. // At (x, y) == (8, 8): // The destination pixel is {136, 0, 0, 255}. diff --git a/libgo/go/image/geom.go b/libgo/go/image/geom.go index 6ebaf67da84..e1cd4dc1e3e 100644 --- a/libgo/go/image/geom.go +++ b/libgo/go/image/geom.go @@ -5,6 +5,7 @@ package image import ( + "image/color" "strconv" ) @@ -62,7 +63,7 @@ func (p Point) Mod(r Rectangle) Point { // Eq reports whether p and q are equal. func (p Point) Eq(q Point) bool { - return p.X == q.X && p.Y == q.Y + return p == q } // ZP is the zero Point. @@ -77,6 +78,10 @@ func Pt(X, Y int) Point { // It is well-formed if Min.X <= Max.X and likewise for Y. Points are always // well-formed. A rectangle's methods always return well-formed outputs for // well-formed inputs. +// +// A Rectangle is also an Image whose bounds are the rectangle itself. At +// returns color.Opaque for points in the rectangle and color.Transparent +// otherwise. type Rectangle struct { Min, Max Point } @@ -164,6 +169,12 @@ func (r Rectangle) Intersect(s Rectangle) Rectangle { // Union returns the smallest rectangle that contains both r and s. func (r Rectangle) Union(s Rectangle) Rectangle { + if r.Empty() { + return s + } + if s.Empty() { + return r + } if r.Min.X > s.Min.X { r.Min.X = s.Min.X } @@ -184,15 +195,16 @@ func (r Rectangle) Empty() bool { return r.Min.X >= r.Max.X || r.Min.Y >= r.Max.Y } -// Eq reports whether r and s are equal. +// Eq reports whether r and s contain the same set of points. All empty +// rectangles are considered equal. func (r Rectangle) Eq(s Rectangle) bool { - return r.Min.X == s.Min.X && r.Min.Y == s.Min.Y && - r.Max.X == s.Max.X && r.Max.Y == s.Max.Y + return r == s || r.Empty() && s.Empty() } // Overlaps reports whether r and s have a non-empty intersection. func (r Rectangle) Overlaps(s Rectangle) bool { - return r.Min.X < s.Max.X && s.Min.X < r.Max.X && + return !r.Empty() && !s.Empty() && + r.Min.X < s.Max.X && s.Min.X < r.Max.X && r.Min.Y < s.Max.Y && s.Min.Y < r.Max.Y } @@ -219,10 +231,30 @@ func (r Rectangle) Canon() Rectangle { return r } +// At implements the Image interface. +func (r Rectangle) At(x, y int) color.Color { + if (Point{x, y}).In(r) { + return color.Opaque + } + return color.Transparent +} + +// Bounds implements the Image interface. +func (r Rectangle) Bounds() Rectangle { + return r +} + +// ColorModel implements the Image interface. +func (r Rectangle) ColorModel() color.Model { + return color.Alpha16Model +} + // ZR is the zero Rectangle. var ZR Rectangle -// Rect is shorthand for Rectangle{Pt(x0, y0), Pt(x1, y1)}. +// Rect is shorthand for Rectangle{Pt(x0, y0), Pt(x1, y1)}. The returned +// rectangle has minimum and maximum coordinates swapped if necessary so that +// it is well-formed. func Rect(x0, y0, x1, y1 int) Rectangle { if x0 > x1 { x0, x1 = x1, x0 diff --git a/libgo/go/image/geom_test.go b/libgo/go/image/geom_test.go new file mode 100644 index 00000000000..6e9c6a13c2c --- /dev/null +++ b/libgo/go/image/geom_test.go @@ -0,0 +1,115 @@ +// Copyright 2015 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 image + +import ( + "fmt" + "testing" +) + +func TestRectangle(t *testing.T) { + // in checks that every point in f is in g. + in := func(f, g Rectangle) error { + if !f.In(g) { + return fmt.Errorf("f=%s, f.In(%s): got false, want true", f, g) + } + for y := f.Min.Y; y < f.Max.Y; y++ { + for x := f.Min.X; x < f.Max.X; x++ { + p := Point{x, y} + if !p.In(g) { + return fmt.Errorf("p=%s, p.In(%s): got false, want true", p, g) + } + } + } + return nil + } + + rects := []Rectangle{ + Rect(0, 0, 10, 10), + Rect(1, 2, 3, 4), + Rect(4, 6, 10, 10), + Rect(2, 3, 12, 5), + Rect(-1, -2, 0, 0), + Rect(-1, -2, 4, 6), + Rect(-10, -20, 30, 40), + Rect(8, 8, 8, 8), + Rect(88, 88, 88, 88), + Rect(6, 5, 4, 3), + } + + // r.Eq(s) should be equivalent to every point in r being in s, and every + // point in s being in r. + for _, r := range rects { + for _, s := range rects { + got := r.Eq(s) + want := in(r, s) == nil && in(s, r) == nil + if got != want { + t.Errorf("Eq: r=%s, s=%s: got %t, want %t", r, s, got, want) + } + } + } + + // The intersection should be the largest rectangle a such that every point + // in a is both in r and in s. + for _, r := range rects { + for _, s := range rects { + a := r.Intersect(s) + if err := in(a, r); err != nil { + t.Errorf("Intersect: r=%s, s=%s, a=%s, a not in r: %v", r, s, a, err) + } + if err := in(a, s); err != nil { + t.Errorf("Intersect: r=%s, s=%s, a=%s, a not in s: %v", r, s, a, err) + } + if a.Empty() == r.Overlaps(s) { + t.Errorf("Intersect: r=%s, s=%s, a=%s: empty=%t same as overlaps=%t", + r, s, a, a.Empty(), r.Overlaps(s)) + } + largerThanA := [4]Rectangle{a, a, a, a} + largerThanA[0].Min.X-- + largerThanA[1].Min.Y-- + largerThanA[2].Max.X++ + largerThanA[3].Max.Y++ + for i, b := range largerThanA { + if b.Empty() { + // b isn't actually larger than a. + continue + } + if in(b, r) == nil && in(b, s) == nil { + t.Errorf("Intersect: r=%s, s=%s, a=%s, b=%s, i=%d: intersection could be larger", + r, s, a, b, i) + } + } + } + } + + // The union should be the smallest rectangle a such that every point in r + // is in a and every point in s is in a. + for _, r := range rects { + for _, s := range rects { + a := r.Union(s) + if err := in(r, a); err != nil { + t.Errorf("Union: r=%s, s=%s, a=%s, r not in a: %v", r, s, a, err) + } + if err := in(s, a); err != nil { + t.Errorf("Union: r=%s, s=%s, a=%s, s not in a: %v", r, s, a, err) + } + if a.Empty() { + // You can't get any smaller than a. + continue + } + smallerThanA := [4]Rectangle{a, a, a, a} + smallerThanA[0].Min.X++ + smallerThanA[1].Min.Y++ + smallerThanA[2].Max.X-- + smallerThanA[3].Max.Y-- + for i, b := range smallerThanA { + if in(r, b) == nil && in(s, b) == nil { + t.Errorf("Union: r=%s, s=%s, a=%s, b=%s, i=%d: union could be smaller", + r, s, a, b, i) + } + } + } + } +} diff --git a/libgo/go/image/gif/reader.go b/libgo/go/image/gif/reader.go index 5a863e204f3..6a133124ad5 100644 --- a/libgo/go/image/gif/reader.go +++ b/libgo/go/image/gif/reader.go @@ -32,15 +32,20 @@ type reader interface { // Masks etc. const ( // Fields. - fColorMapFollows = 1 << 7 - - // Image fields. - ifLocalColorTable = 1 << 7 - ifInterlace = 1 << 6 - ifPixelSizeMask = 7 + fColorTable = 1 << 7 + fInterlace = 1 << 6 + fColorTableBitsMask = 7 // Graphic control flags. gcTransparentColorSet = 1 << 0 + gcDisposalMethodMask = 7 << 2 +) + +// Disposal Methods. +const ( + DisposalNone = 0x01 + DisposalBackground = 0x02 + DisposalPrevious = 0x03 ) // Section indicators. @@ -66,14 +71,10 @@ type decoder struct { vers string width int height int - flags byte - headerFields byte - backgroundIndex byte loopCount int delayTime int - - // Unused from header. - aspect byte + backgroundIndex byte + disposalMethod byte // From image descriptor. imageFields byte @@ -83,13 +84,13 @@ type decoder struct { hasTransparentIndex bool // Computed. - pixelSize uint - globalColorMap color.Palette + globalColorTable color.Palette // Used when decoding. - delay []int - image []*image.Paletted - tmp [1024]byte // must be at least 768 so we can read color map + delay []int + disposal []byte + image []*image.Paletted + tmp [1024]byte // must be at least 768 so we can read color table } // blockReader parses the block structure of GIF image data, which @@ -122,7 +123,7 @@ func (b *blockReader) Read(p []byte) (int, error) { b.err = io.EOF return 0, b.err } - b.slice = b.tmp[0:blockLen] + b.slice = b.tmp[:blockLen] if _, b.err = io.ReadFull(b.r, b.slice); b.err != nil { return 0, b.err } @@ -149,12 +150,6 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error { return nil } - if d.headerFields&fColorMapFollows != 0 { - if d.globalColorMap, err = d.readColorMap(); err != nil { - return err - } - } - for { c, err := d.r.ReadByte() if err != nil { @@ -171,19 +166,22 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error { if err != nil { return err } - useLocalColorMap := d.imageFields&fColorMapFollows != 0 - if useLocalColorMap { - m.Palette, err = d.readColorMap() + useLocalColorTable := d.imageFields&fColorTable != 0 + if useLocalColorTable { + m.Palette, err = d.readColorTable(d.imageFields) if err != nil { return err } } else { - m.Palette = d.globalColorMap + if d.globalColorTable == nil { + return errors.New("gif: no color table") + } + m.Palette = d.globalColorTable } if d.hasTransparentIndex && int(d.transparentIndex) < len(m.Palette) { - if !useLocalColorMap { - // Clone the global color map. - m.Palette = append(color.Palette(nil), d.globalColorMap...) + if !useLocalColorTable { + // Clone the global color table. + m.Palette = append(color.Palette(nil), d.globalColorTable...) } m.Palette[d.transparentIndex] = color.RGBA{} } @@ -204,9 +202,18 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error { } return errNotEnough } - // Both lzwr and br should be exhausted. Reading from them - // should yield (0, io.EOF). - if n, err := lzwr.Read(d.tmp[:1]); n != 0 || err != io.EOF { + // Both lzwr and br should be exhausted. Reading from them should + // yield (0, io.EOF). + // + // The spec (Appendix F - Compression), says that "An End of + // Information code... must be the last code output by the encoder + // for an image". In practice, though, giflib (a widely used C + // library) does not enforce this, so we also accept lzwr returning + // io.ErrUnexpectedEOF (meaning that the encoded stream hit io.EOF + // before the LZW decoder saw an explict end code), provided that + // the io.ReadFull call above successfully read len(m.Pix) bytes. + // See https://golang.org/issue/9856 for an example GIF. + if n, err := lzwr.Read(d.tmp[:1]); n != 0 || (err != io.EOF && err != io.ErrUnexpectedEOF) { if err != nil { return err } @@ -229,12 +236,13 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error { } // Undo the interlacing if necessary. - if d.imageFields&ifInterlace != 0 { + if d.imageFields&fInterlace != 0 { uninterlace(m) } d.image = append(d.image, m) d.delay = append(d.delay, d.delayTime) + d.disposal = append(d.disposal, d.disposalMethod) // The GIF89a spec, Section 23 (Graphic Control Extension) says: // "The scope of this extension is the first graphic rendering block // to follow." We therefore reset the GCE fields to zero. @@ -254,44 +262,39 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error { } func (d *decoder) readHeaderAndScreenDescriptor() error { - _, err := io.ReadFull(d.r, d.tmp[0:13]) + _, err := io.ReadFull(d.r, d.tmp[:13]) if err != nil { return err } - d.vers = string(d.tmp[0:6]) + d.vers = string(d.tmp[:6]) if d.vers != "GIF87a" && d.vers != "GIF89a" { return fmt.Errorf("gif: can't recognize format %s", d.vers) } d.width = int(d.tmp[6]) + int(d.tmp[7])<<8 d.height = int(d.tmp[8]) + int(d.tmp[9])<<8 - d.headerFields = d.tmp[10] - d.backgroundIndex = d.tmp[11] - d.aspect = d.tmp[12] - d.loopCount = -1 - d.pixelSize = uint(d.headerFields&7) + 1 + if fields := d.tmp[10]; fields&fColorTable != 0 { + d.backgroundIndex = d.tmp[11] + // readColorTable overwrites the contents of d.tmp, but that's OK. + if d.globalColorTable, err = d.readColorTable(fields); err != nil { + return err + } + } + // d.tmp[12] is the Pixel Aspect Ratio, which is ignored. return nil } -func (d *decoder) readColorMap() (color.Palette, error) { - if d.pixelSize > 8 { - return nil, fmt.Errorf("gif: can't handle %d bits per pixel", d.pixelSize) - } - numColors := 1 << d.pixelSize - if d.imageFields&ifLocalColorTable != 0 { - numColors = 1 << ((d.imageFields & ifPixelSizeMask) + 1) - } - numValues := 3 * numColors - _, err := io.ReadFull(d.r, d.tmp[0:numValues]) +func (d *decoder) readColorTable(fields byte) (color.Palette, error) { + n := 1 << (1 + uint(fields&fColorTableBitsMask)) + _, err := io.ReadFull(d.r, d.tmp[:3*n]) if err != nil { - return nil, fmt.Errorf("gif: short read on color map: %s", err) + return nil, fmt.Errorf("gif: short read on color table: %s", err) } - colorMap := make(color.Palette, numColors) - j := 0 - for i := range colorMap { - colorMap[i] = color.RGBA{d.tmp[j+0], d.tmp[j+1], d.tmp[j+2], 0xFF} + j, p := 0, make(color.Palette, n) + for i := range p { + p[i] = color.RGBA{d.tmp[j+0], d.tmp[j+1], d.tmp[j+2], 0xFF} j += 3 } - return colorMap, nil + return p, nil } func (d *decoder) readExtension() error { @@ -318,7 +321,7 @@ func (d *decoder) readExtension() error { return fmt.Errorf("gif: unknown extension 0x%.2x", extension) } if size > 0 { - if _, err := io.ReadFull(d.r, d.tmp[0:size]); err != nil { + if _, err := io.ReadFull(d.r, d.tmp[:size]); err != nil { return err } } @@ -343,12 +346,13 @@ func (d *decoder) readExtension() error { } func (d *decoder) readGraphicControl() error { - if _, err := io.ReadFull(d.r, d.tmp[0:6]); err != nil { + if _, err := io.ReadFull(d.r, d.tmp[:6]); err != nil { return fmt.Errorf("gif: can't read graphic control: %s", err) } - d.flags = d.tmp[1] + flags := d.tmp[1] + d.disposalMethod = (flags & gcDisposalMethodMask) >> 2 d.delayTime = int(d.tmp[2]) | int(d.tmp[3])<<8 - if d.flags&gcTransparentColorSet != 0 { + if flags&gcTransparentColorSet != 0 { d.transparentIndex = d.tmp[4] d.hasTransparentIndex = true } @@ -356,7 +360,7 @@ func (d *decoder) readGraphicControl() error { } func (d *decoder) newImageFromDescriptor() (*image.Paletted, error) { - if _, err := io.ReadFull(d.r, d.tmp[0:9]); err != nil { + if _, err := io.ReadFull(d.r, d.tmp[:9]); err != nil { return nil, fmt.Errorf("gif: can't read image descriptor: %s", err) } left := int(d.tmp[0]) + int(d.tmp[1])<<8 @@ -380,7 +384,7 @@ func (d *decoder) readBlock() (int, error) { if n == 0 || err != nil { return 0, err } - return io.ReadFull(d.r, d.tmp[0:n]) + return io.ReadFull(d.r, d.tmp[:n]) } // interlaceScan defines the ordering for a pass of the interlace algorithm. @@ -429,6 +433,24 @@ type GIF struct { Image []*image.Paletted // The successive images. Delay []int // The successive delay times, one per frame, in 100ths of a second. LoopCount int // The loop count. + // Disposal is the successive disposal methods, one per frame. For + // backwards compatibility, a nil Disposal is valid to pass to EncodeAll, + // and implies that each frame's disposal method is 0 (no disposal + // specified). + Disposal []byte + // Config is the global color table (palette), width and height. A nil or + // empty-color.Palette Config.ColorModel means that each frame has its own + // color table and there is no global color table. Each frame's bounds must + // be within the rectangle defined by the two points (0, 0) and + // (Config.Width, Config.Height). + // + // For backwards compatibility, a zero-valued Config is valid to pass to + // EncodeAll, and implies that the overall GIF's width and height equals + // the first frame's bounds' Rectangle.Max point. + Config image.Config + // BackgroundIndex is the background index in the global color table, for + // use with the DisposalBackground disposal method. + BackgroundIndex byte } // DecodeAll reads a GIF image from r and returns the sequential frames @@ -442,6 +464,13 @@ func DecodeAll(r io.Reader) (*GIF, error) { Image: d.image, LoopCount: d.loopCount, Delay: d.delay, + Disposal: d.disposal, + Config: image.Config{ + ColorModel: d.globalColorTable, + Width: d.width, + Height: d.height, + }, + BackgroundIndex: d.backgroundIndex, } return gif, nil } @@ -454,7 +483,7 @@ func DecodeConfig(r io.Reader) (image.Config, error) { return image.Config{}, err } return image.Config{ - ColorModel: d.globalColorMap, + ColorModel: d.globalColorTable, Width: d.width, Height: d.height, }, nil diff --git a/libgo/go/image/gif/reader_test.go b/libgo/go/image/gif/reader_test.go index 7b6f504367c..c294195b6f7 100644 --- a/libgo/go/image/gif/reader_test.go +++ b/libgo/go/image/gif/reader_test.go @@ -17,8 +17,8 @@ import ( const ( headerStr = "GIF89a" + "\x02\x00\x01\x00" + // width=2, height=1 - "\x80\x00\x00" // headerFields=(a color map of 2 pixels), backgroundIndex, aspect - paletteStr = "\x10\x20\x30\x40\x50\x60" // the color map, also known as a palette + "\x80\x00\x00" // headerFields=(a color table of 2 pixels), backgroundIndex, aspect + paletteStr = "\x10\x20\x30\x40\x50\x60" // the color table, also known as a palette trailerStr = "\x3b" ) @@ -141,7 +141,7 @@ var testGIF = []byte{ 'G', 'I', 'F', '8', '9', 'a', 1, 0, 1, 0, // w=1, h=1 (6) 128, 0, 0, // headerFields, bg, aspect (10) - 0, 0, 0, 1, 1, 1, // color map and graphics control (13) + 0, 0, 0, 1, 1, 1, // color table and graphics control (13) 0x21, 0xf9, 0x04, 0x00, 0x00, 0x00, 0xff, 0x00, // (19) // frame 1 (0,0 - 1,1) 0x2c, @@ -200,22 +200,26 @@ func TestNoPalette(t *testing.T) { b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02") // Encode the pixels: neither is in range, because there is no palette. - pix := []byte{0, 128} + pix := []byte{0, 3} enc := &bytes.Buffer{} w := lzw.NewWriter(enc, lzw.LSB, 2) - w.Write(pix) - w.Close() + if _, err := w.Write(pix); err != nil { + t.Fatalf("Write: %v", err) + } + if err := w.Close(); err != nil { + t.Fatalf("Close: %v", err) + } b.WriteByte(byte(len(enc.Bytes()))) b.Write(enc.Bytes()) b.WriteByte(0x00) // An empty block signifies the end of the image data. b.WriteString(trailerStr) - try(t, b.Bytes(), "gif: invalid pixel value") + try(t, b.Bytes(), "gif: no color table") } func TestPixelOutsidePaletteRange(t *testing.T) { - for _, pval := range []byte{0, 1, 2, 3, 255} { + for _, pval := range []byte{0, 1, 2, 3} { b := &bytes.Buffer{} // Manufacture a GIF with a 2 color palette. @@ -229,8 +233,12 @@ func TestPixelOutsidePaletteRange(t *testing.T) { pix := []byte{pval, pval} enc := &bytes.Buffer{} w := lzw.NewWriter(enc, lzw.LSB, 2) - w.Write(pix) - w.Close() + if _, err := w.Write(pix); err != nil { + t.Fatalf("Write: %v", err) + } + if err := w.Close(); err != nil { + t.Fatalf("Close: %v", err) + } b.WriteByte(byte(len(enc.Bytes()))) b.Write(enc.Bytes()) b.WriteByte(0x00) // An empty block signifies the end of the image data. @@ -245,3 +253,24 @@ func TestPixelOutsidePaletteRange(t *testing.T) { try(t, b.Bytes(), want) } } + +func TestLoopCount(t *testing.T) { + data := []byte("GIF89a000\x00000,0\x00\x00\x00\n\x00" + + "\n\x00\x80000000\x02\b\xf01u\xb9\xfdal\x05\x00;") + img, err := DecodeAll(bytes.NewReader(data)) + if err != nil { + t.Fatal("DecodeAll:", err) + } + w := new(bytes.Buffer) + err = EncodeAll(w, img) + if err != nil { + t.Fatal("EncodeAll:", err) + } + img1, err := DecodeAll(w) + if err != nil { + t.Fatal("DecodeAll:", err) + } + if img.LoopCount != img1.LoopCount { + t.Errorf("loop count mismatch: %d vs %d", img.LoopCount, img1.LoopCount) + } +} diff --git a/libgo/go/image/gif/writer.go b/libgo/go/image/gif/writer.go index 49abde704c8..dd317901d48 100644 --- a/libgo/go/image/gif/writer.go +++ b/libgo/go/image/gif/writer.go @@ -6,6 +6,7 @@ package gif import ( "bufio" + "bytes" "compress/lzw" "errors" "image" @@ -52,9 +53,13 @@ type encoder struct { w writer err error // g is a reference to the data that is being encoded. - g *GIF - // buf is a scratch buffer. It must be at least 768 so we can write the color map. - buf [1024]byte + g GIF + // globalCT is the size in bytes of the global color table. + globalCT int + // buf is a scratch buffer. It must be at least 256 for the blockWriter. + buf [256]byte + globalColorTable [3 * 256]byte + localColorTable [3 * 256]byte } // blockWriter writes the block structure of GIF image data, which @@ -116,18 +121,27 @@ func (e *encoder) writeHeader() { return } - pm := e.g.Image[0] // Logical screen width and height. - writeUint16(e.buf[0:2], uint16(pm.Bounds().Dx())) - writeUint16(e.buf[2:4], uint16(pm.Bounds().Dy())) + writeUint16(e.buf[0:2], uint16(e.g.Config.Width)) + writeUint16(e.buf[2:4], uint16(e.g.Config.Height)) e.write(e.buf[:4]) - // All frames have a local color table, so a global color table - // is not needed. - e.buf[0] = 0x00 - e.buf[1] = 0x00 // Background Color Index. - e.buf[2] = 0x00 // Pixel Aspect Ratio. - e.write(e.buf[:3]) + if p, ok := e.g.Config.ColorModel.(color.Palette); ok && len(p) > 0 { + paddedSize := log2(len(p)) // Size of Global Color Table: 2^(1+n). + e.buf[0] = fColorTable | uint8(paddedSize) + e.buf[1] = e.g.BackgroundIndex + e.buf[2] = 0x00 // Pixel Aspect Ratio. + e.write(e.buf[:3]) + e.globalCT = encodeColorTable(e.globalColorTable[:], p, paddedSize) + e.write(e.globalColorTable[:e.globalCT]) + } else { + // All frames have a local color table, so a global color table + // is not needed. + e.buf[0] = 0x00 + e.buf[1] = 0x00 // Background Color Index. + e.buf[2] = 0x00 // Pixel Aspect Ratio. + e.write(e.buf[:3]) + } // Add animation info if necessary. if len(e.g.Image) > 1 { @@ -147,28 +161,25 @@ func (e *encoder) writeHeader() { } } -func (e *encoder) writeColorTable(p color.Palette, size int) { - if e.err != nil { - return - } - - for i := 0; i < log2Lookup[size]; i++ { +func encodeColorTable(dst []byte, p color.Palette, size int) int { + n := log2Lookup[size] + for i := 0; i < n; i++ { if i < len(p) { r, g, b, _ := p[i].RGBA() - e.buf[3*i+0] = uint8(r >> 8) - e.buf[3*i+1] = uint8(g >> 8) - e.buf[3*i+2] = uint8(b >> 8) + dst[3*i+0] = uint8(r >> 8) + dst[3*i+1] = uint8(g >> 8) + dst[3*i+2] = uint8(b >> 8) } else { // Pad with black. - e.buf[3*i+0] = 0x00 - e.buf[3*i+1] = 0x00 - e.buf[3*i+2] = 0x00 + dst[3*i+0] = 0x00 + dst[3*i+1] = 0x00 + dst[3*i+2] = 0x00 } } - e.write(e.buf[:3*log2Lookup[size]]) + return 3 * n } -func (e *encoder) writeImageBlock(pm *image.Paletted, delay int) { +func (e *encoder) writeImageBlock(pm *image.Paletted, delay int, disposal byte) { if e.err != nil { return } @@ -179,10 +190,14 @@ func (e *encoder) writeImageBlock(pm *image.Paletted, delay int) { } b := pm.Bounds() - if b.Dx() >= 1<<16 || b.Dy() >= 1<<16 || b.Min.X < 0 || b.Min.X >= 1<<16 || b.Min.Y < 0 || b.Min.Y >= 1<<16 { + if b.Min.X < 0 || b.Max.X >= 1<<16 || b.Min.Y < 0 || b.Max.Y >= 1<<16 { e.err = errors.New("gif: image block is too large to encode") return } + if !b.In(image.Rectangle{Max: image.Point{e.g.Config.Width, e.g.Config.Height}}) { + e.err = errors.New("gif: image block is out of bounds") + return + } transparentIndex := -1 for i, c := range pm.Palette { @@ -192,14 +207,14 @@ func (e *encoder) writeImageBlock(pm *image.Paletted, delay int) { } } - if delay > 0 || transparentIndex != -1 { + if delay > 0 || disposal != 0 || transparentIndex != -1 { e.buf[0] = sExtension // Extension Introducer. e.buf[1] = gcLabel // Graphic Control Label. e.buf[2] = gcBlockSize // Block Size. if transparentIndex != -1 { - e.buf[3] = 0x01 + e.buf[3] = 0x01 | disposal<<2 } else { - e.buf[3] = 0x00 + e.buf[3] = 0x00 | disposal<<2 } writeUint16(e.buf[4:6], uint16(delay)) // Delay Time (1/100ths of a second) @@ -220,11 +235,15 @@ func (e *encoder) writeImageBlock(pm *image.Paletted, delay int) { e.write(e.buf[:9]) paddedSize := log2(len(pm.Palette)) // Size of Local Color Table: 2^(1+n). - // Interlacing is not supported. - e.writeByte(0x80 | uint8(paddedSize)) - - // Local Color Table. - e.writeColorTable(pm.Palette, paddedSize) + ct := encodeColorTable(e.localColorTable[:], pm.Palette, paddedSize) + if ct != e.globalCT || !bytes.Equal(e.globalColorTable[:ct], e.localColorTable[:ct]) { + // Use a local color table. + e.writeByte(fColorTable | uint8(paddedSize)) + e.write(e.localColorTable[:ct]) + } else { + // Use the global color table. + e.writeByte(0) + } litWidth := paddedSize + 1 if litWidth < 2 { @@ -281,7 +300,23 @@ func EncodeAll(w io.Writer, g *GIF) error { g.LoopCount = 0 } - e := encoder{g: g} + e := encoder{g: *g} + // The GIF.Disposal, GIF.Config and GIF.BackgroundIndex fields were added + // in Go 1.5. Valid Go 1.4 code, such as when the Disposal field is omitted + // in a GIF struct literal, should still produce valid GIFs. + if e.g.Disposal != nil && len(e.g.Image) != len(e.g.Disposal) { + return errors.New("gif: mismatched image and disposal lengths") + } + if e.g.Config == (image.Config{}) { + p := g.Image[0].Bounds().Max + e.g.Config.Width = p.X + e.g.Config.Height = p.Y + } else if e.g.Config.ColorModel != nil { + if _, ok := e.g.Config.ColorModel.(color.Palette); !ok { + return errors.New("gif: GIF color model must be a color.Palette") + } + } + if ww, ok := w.(writer); ok { e.w = ww } else { @@ -290,7 +325,11 @@ func EncodeAll(w io.Writer, g *GIF) error { e.writeHeader() for i, pm := range g.Image { - e.writeImageBlock(pm, g.Delay[i]) + disposal := uint8(0) + if g.Disposal != nil { + disposal = g.Disposal[i] + } + e.writeImageBlock(pm, g.Delay[i], disposal) } e.writeByte(sTrailer) e.flush() @@ -326,8 +365,22 @@ func Encode(w io.Writer, m image.Image, o *Options) error { opts.Drawer.Draw(pm, b, m, image.ZP) } + // When calling Encode instead of EncodeAll, the single-frame image is + // translated such that its top-left corner is (0, 0), so that the single + // frame completely fills the overall GIF's bounds. + if pm.Rect.Min != (image.Point{}) { + dup := *pm + dup.Rect = dup.Rect.Sub(dup.Rect.Min) + pm = &dup + } + return EncodeAll(w, &GIF{ Image: []*image.Paletted{pm}, Delay: []int{0}, + Config: image.Config{ + ColorModel: pm.Palette, + Width: b.Dx(), + Height: b.Dy(), + }, }) } diff --git a/libgo/go/image/gif/writer_test.go b/libgo/go/image/gif/writer_test.go index 93306ffdb34..db61a5c3c2e 100644 --- a/libgo/go/image/gif/writer_test.go +++ b/libgo/go/image/gif/writer_test.go @@ -8,10 +8,12 @@ import ( "bytes" "image" "image/color" + "image/color/palette" _ "image/png" "io/ioutil" "math/rand" "os" + "reflect" "testing" ) @@ -125,55 +127,317 @@ func TestSubImage(t *testing.T) { } } +// palettesEqual reports whether two color.Palette values are equal, ignoring +// any trailing opaque-black palette entries. +func palettesEqual(p, q color.Palette) bool { + n := len(p) + if n > len(q) { + n = len(q) + } + for i := 0; i < n; i++ { + if p[i] != q[i] { + return false + } + } + for i := n; i < len(p); i++ { + r, g, b, a := p[i].RGBA() + if r != 0 || g != 0 || b != 0 || a != 0xffff { + return false + } + } + for i := n; i < len(q); i++ { + r, g, b, a := q[i].RGBA() + if r != 0 || g != 0 || b != 0 || a != 0xffff { + return false + } + } + return true +} + var frames = []string{ "../testdata/video-001.gif", "../testdata/video-005.gray.gif", } -func TestEncodeAll(t *testing.T) { +func testEncodeAll(t *testing.T, go1Dot5Fields bool, useGlobalColorModel bool) { + const width, height = 150, 103 + g0 := &GIF{ Image: make([]*image.Paletted, len(frames)), Delay: make([]int, len(frames)), LoopCount: 5, } for i, f := range frames { - m, err := readGIF(f) + g, err := readGIF(f) if err != nil { t.Fatal(f, err) } - g0.Image[i] = m.Image[0] + m := g.Image[0] + if m.Bounds().Dx() != width || m.Bounds().Dy() != height { + t.Fatalf("frame %d had unexpected bounds: got %v, want width/height = %d/%d", + i, m.Bounds(), width, height) + } + g0.Image[i] = m } + // The GIF.Disposal, GIF.Config and GIF.BackgroundIndex fields were added + // in Go 1.5. Valid Go 1.4 or earlier code should still produce valid GIFs. + // + // On the following line, color.Model is an interface type, and + // color.Palette is a concrete (slice) type. + globalColorModel, backgroundIndex := color.Model(color.Palette(nil)), uint8(0) + if useGlobalColorModel { + globalColorModel, backgroundIndex = color.Palette(palette.WebSafe), uint8(1) + } + if go1Dot5Fields { + g0.Disposal = make([]byte, len(g0.Image)) + for i := range g0.Disposal { + g0.Disposal[i] = DisposalNone + } + g0.Config = image.Config{ + ColorModel: globalColorModel, + Width: width, + Height: height, + } + g0.BackgroundIndex = backgroundIndex + } + var buf bytes.Buffer if err := EncodeAll(&buf, g0); err != nil { t.Fatal("EncodeAll:", err) } - g1, err := DecodeAll(&buf) + encoded := buf.Bytes() + config, err := DecodeConfig(bytes.NewReader(encoded)) + if err != nil { + t.Fatal("DecodeConfig:", err) + } + g1, err := DecodeAll(bytes.NewReader(encoded)) if err != nil { t.Fatal("DecodeAll:", err) } + + if !reflect.DeepEqual(config, g1.Config) { + t.Errorf("DecodeConfig inconsistent with DecodeAll") + } + if !palettesEqual(g1.Config.ColorModel.(color.Palette), globalColorModel.(color.Palette)) { + t.Errorf("unexpected global color model") + } + if w, h := g1.Config.Width, g1.Config.Height; w != width || h != height { + t.Errorf("got config width * height = %d * %d, want %d * %d", w, h, width, height) + } + if g0.LoopCount != g1.LoopCount { t.Errorf("loop counts differ: %d and %d", g0.LoopCount, g1.LoopCount) } + if backgroundIndex != g1.BackgroundIndex { + t.Errorf("background indexes differ: %d and %d", backgroundIndex, g1.BackgroundIndex) + } + if len(g0.Image) != len(g1.Image) { + t.Fatalf("image lengths differ: %d and %d", len(g0.Image), len(g1.Image)) + } + if len(g1.Image) != len(g1.Delay) { + t.Fatalf("image and delay lengths differ: %d and %d", len(g1.Image), len(g1.Delay)) + } + if len(g1.Image) != len(g1.Disposal) { + t.Fatalf("image and disposal lengths differ: %d and %d", len(g1.Image), len(g1.Disposal)) + } + for i := range g0.Image { m0, m1 := g0.Image[i], g1.Image[i] if m0.Bounds() != m1.Bounds() { - t.Errorf("%s, bounds differ: %v and %v", frames[i], m0.Bounds(), m1.Bounds()) + t.Errorf("frame %d: bounds differ: %v and %v", i, m0.Bounds(), m1.Bounds()) } d0, d1 := g0.Delay[i], g1.Delay[i] if d0 != d1 { - t.Errorf("%s: delay values differ: %d and %d", frames[i], d0, d1) + t.Errorf("frame %d: delay values differ: %d and %d", i, d0, d1) + } + p0, p1 := uint8(0), g1.Disposal[i] + if go1Dot5Fields { + p0 = DisposalNone + } + if p0 != p1 { + t.Errorf("frame %d: disposal values differ: %d and %d", i, p0, p1) } } +} - g1.Delay = make([]int, 1) - if err := EncodeAll(ioutil.Discard, g1); err == nil { +func TestEncodeAllGo1Dot4(t *testing.T) { testEncodeAll(t, false, false) } +func TestEncodeAllGo1Dot5(t *testing.T) { testEncodeAll(t, true, false) } +func TestEncodeAllGo1Dot5GlobalColorModel(t *testing.T) { testEncodeAll(t, true, true) } + +func TestEncodeMismatchDelay(t *testing.T) { + images := make([]*image.Paletted, 2) + for i := range images { + images[i] = image.NewPaletted(image.Rect(0, 0, 5, 5), palette.Plan9) + } + + g0 := &GIF{ + Image: images, + Delay: make([]int, 1), + } + if err := EncodeAll(ioutil.Discard, g0); err == nil { t.Error("expected error from mismatched delay and image slice lengths") } + + g1 := &GIF{ + Image: images, + Delay: make([]int, len(images)), + Disposal: make([]byte, 1), + } + for i := range g1.Disposal { + g1.Disposal[i] = DisposalNone + } + if err := EncodeAll(ioutil.Discard, g1); err == nil { + t.Error("expected error from mismatched disposal and image slice lengths") + } +} + +func TestEncodeZeroGIF(t *testing.T) { if err := EncodeAll(ioutil.Discard, &GIF{}); err == nil { t.Error("expected error from providing empty gif") } } +func TestEncodeAllFramesOutOfBounds(t *testing.T) { + images := []*image.Paletted{ + image.NewPaletted(image.Rect(0, 0, 5, 5), palette.Plan9), + image.NewPaletted(image.Rect(2, 2, 8, 8), palette.Plan9), + image.NewPaletted(image.Rect(3, 3, 4, 4), palette.Plan9), + } + for _, upperBound := range []int{6, 10} { + g := &GIF{ + Image: images, + Delay: make([]int, len(images)), + Disposal: make([]byte, len(images)), + Config: image.Config{ + Width: upperBound, + Height: upperBound, + }, + } + err := EncodeAll(ioutil.Discard, g) + if upperBound >= 8 { + if err != nil { + t.Errorf("upperBound=%d: %v", upperBound, err) + } + } else { + if err == nil { + t.Errorf("upperBound=%d: got nil error, want non-nil", upperBound) + } + } + } +} + +func TestEncodeNonZeroMinPoint(t *testing.T) { + points := []image.Point{ + image.Point{-8, -9}, + image.Point{-4, -4}, + image.Point{-3, +3}, + image.Point{+0, +0}, + image.Point{+2, +2}, + } + for _, p := range points { + src := image.NewPaletted(image.Rectangle{Min: p, Max: p.Add(image.Point{6, 6})}, palette.Plan9) + var buf bytes.Buffer + if err := Encode(&buf, src, nil); err != nil { + t.Errorf("p=%v: Encode: %v", p, err) + continue + } + m, err := Decode(&buf) + if err != nil { + t.Errorf("p=%v: Decode: %v", p, err) + continue + } + if got, want := m.Bounds(), image.Rect(0, 0, 6, 6); got != want { + t.Errorf("p=%v: got %v, want %v", p, got, want) + } + } +} + +func TestEncodeImplicitConfigSize(t *testing.T) { + // For backwards compatibility for Go 1.4 and earlier code, the Config + // field is optional, and if zero, the width and height is implied by the + // first (and in this case only) frame's width and height. + // + // A Config only specifies a width and height (two integers) while an + // image.Image's Bounds method returns an image.Rectangle (four integers). + // For a gif.GIF, the overall bounds' top-left point is always implicitly + // (0, 0), and any frame whose bounds have a negative X or Y will be + // outside those overall bounds, so encoding should fail. + for _, lowerBound := range []int{-1, 0, 1} { + images := []*image.Paletted{ + image.NewPaletted(image.Rect(lowerBound, lowerBound, 4, 4), palette.Plan9), + } + g := &GIF{ + Image: images, + Delay: make([]int, len(images)), + } + err := EncodeAll(ioutil.Discard, g) + if lowerBound >= 0 { + if err != nil { + t.Errorf("lowerBound=%d: %v", lowerBound, err) + } + } else { + if err == nil { + t.Errorf("lowerBound=%d: got nil error, want non-nil", lowerBound) + } + } + } +} + +func TestEncodePalettes(t *testing.T) { + const w, h = 5, 5 + pals := []color.Palette{{ + color.RGBA{0x00, 0x00, 0x00, 0xff}, + color.RGBA{0x01, 0x00, 0x00, 0xff}, + color.RGBA{0x02, 0x00, 0x00, 0xff}, + }, { + color.RGBA{0x00, 0x00, 0x00, 0xff}, + color.RGBA{0x00, 0x01, 0x00, 0xff}, + }, { + color.RGBA{0x00, 0x00, 0x03, 0xff}, + color.RGBA{0x00, 0x00, 0x02, 0xff}, + color.RGBA{0x00, 0x00, 0x01, 0xff}, + color.RGBA{0x00, 0x00, 0x00, 0xff}, + }, { + color.RGBA{0x10, 0x07, 0xf0, 0xff}, + color.RGBA{0x20, 0x07, 0xf0, 0xff}, + color.RGBA{0x30, 0x07, 0xf0, 0xff}, + color.RGBA{0x40, 0x07, 0xf0, 0xff}, + color.RGBA{0x50, 0x07, 0xf0, 0xff}, + }} + g0 := &GIF{ + Image: []*image.Paletted{ + image.NewPaletted(image.Rect(0, 0, w, h), pals[0]), + image.NewPaletted(image.Rect(0, 0, w, h), pals[1]), + image.NewPaletted(image.Rect(0, 0, w, h), pals[2]), + image.NewPaletted(image.Rect(0, 0, w, h), pals[3]), + }, + Delay: make([]int, len(pals)), + Disposal: make([]byte, len(pals)), + Config: image.Config{ + ColorModel: pals[2], + Width: w, + Height: h, + }, + } + + var buf bytes.Buffer + if err := EncodeAll(&buf, g0); err != nil { + t.Fatalf("EncodeAll: %v", err) + } + g1, err := DecodeAll(&buf) + if err != nil { + t.Fatalf("DecodeAll: %v", err) + } + if len(g0.Image) != len(g1.Image) { + t.Fatalf("image lengths differ: %d and %d", len(g0.Image), len(g1.Image)) + } + for i, m := range g1.Image { + if got, want := m.Palette, pals[i]; !palettesEqual(got, want) { + t.Errorf("frame %d:\ngot %v\nwant %v", i, got, want) + } + } +} + func BenchmarkEncode(b *testing.B) { b.StopTimer() diff --git a/libgo/go/image/image.go b/libgo/go/image/image.go index 6b8e5c4877e..20b64d78e1a 100644 --- a/libgo/go/image/image.go +++ b/libgo/go/image/image.go @@ -18,7 +18,7 @@ // initialization side effects. // // See "The Go image package" for more details: -// http://golang.org/doc/articles/image_package.html +// https://golang.org/doc/articles/image_package.html package image import ( @@ -46,9 +46,9 @@ type Image interface { } // PalettedImage is an image whose colors may come from a limited palette. -// If m is a PalettedImage and m.ColorModel() returns a PalettedColorModel p, +// If m is a PalettedImage and m.ColorModel() returns a color.Palette p, // then m.At(x, y) should be equivalent to p[m.ColorIndexAt(x, y)]. If m's -// color model is not a PalettedColorModel, then ColorIndexAt's behavior is +// color model is not a color.Palette, then ColorIndexAt's behavior is // undefined. type PalettedImage interface { // ColorIndexAt returns the palette index of the pixel at (x, y). @@ -570,7 +570,7 @@ func NewAlpha(r Rectangle) *Alpha { return &Alpha{pix, 1 * w, r} } -// Alpha16 is an in-memory image whose At method returns color.Alpha64 values. +// Alpha16 is an in-memory image whose At method returns color.Alpha16 values. type Alpha16 struct { // Pix holds the image's pixels, as alpha values in big-endian format. The pixel at // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*2]. @@ -826,6 +826,92 @@ func NewGray16(r Rectangle) *Gray16 { return &Gray16{pix, 2 * w, r} } +// CMYK is an in-memory image whose At method returns color.CMYK values. +type CMYK struct { + // Pix holds the image's pixels, in C, M, Y, K order. The pixel at + // (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*4]. + Pix []uint8 + // Stride is the Pix stride (in bytes) between vertically adjacent pixels. + Stride int + // Rect is the image's bounds. + Rect Rectangle +} + +func (p *CMYK) ColorModel() color.Model { return color.CMYKModel } + +func (p *CMYK) Bounds() Rectangle { return p.Rect } + +func (p *CMYK) At(x, y int) color.Color { + return p.CMYKAt(x, y) +} + +func (p *CMYK) CMYKAt(x, y int) color.CMYK { + if !(Point{x, y}.In(p.Rect)) { + return color.CMYK{} + } + i := p.PixOffset(x, y) + return color.CMYK{p.Pix[i+0], p.Pix[i+1], p.Pix[i+2], p.Pix[i+3]} +} + +// PixOffset returns the index of the first element of Pix that corresponds to +// the pixel at (x, y). +func (p *CMYK) PixOffset(x, y int) int { + return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4 +} + +func (p *CMYK) Set(x, y int, c color.Color) { + if !(Point{x, y}.In(p.Rect)) { + return + } + i := p.PixOffset(x, y) + c1 := color.CMYKModel.Convert(c).(color.CMYK) + p.Pix[i+0] = c1.C + p.Pix[i+1] = c1.M + p.Pix[i+2] = c1.Y + p.Pix[i+3] = c1.K +} + +func (p *CMYK) SetCMYK(x, y int, c color.CMYK) { + if !(Point{x, y}.In(p.Rect)) { + return + } + i := p.PixOffset(x, y) + p.Pix[i+0] = c.C + p.Pix[i+1] = c.M + p.Pix[i+2] = c.Y + p.Pix[i+3] = c.K +} + +// SubImage returns an image representing the portion of the image p visible +// through r. The returned value shares pixels with the original image. +func (p *CMYK) SubImage(r Rectangle) Image { + r = r.Intersect(p.Rect) + // If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside + // either r1 or r2 if the intersection is empty. Without explicitly checking for + // this, the Pix[i:] expression below can panic. + if r.Empty() { + return &CMYK{} + } + i := p.PixOffset(r.Min.X, r.Min.Y) + return &CMYK{ + Pix: p.Pix[i:], + Stride: p.Stride, + Rect: r, + } +} + +// Opaque scans the entire image and reports whether it is fully opaque. +func (p *CMYK) Opaque() bool { + return true +} + +// NewCMYK returns a new CMYK with the given bounds. +func NewCMYK(r Rectangle) *CMYK { + w, h := r.Dx(), r.Dy() + buf := make([]uint8, 4*w*h) + return &CMYK{buf, 4 * w, r} +} + // Paletted is an in-memory image of uint8 indices into a given palette. type Paletted struct { // Pix holds the image's pixels, as palette indices. The pixel at diff --git a/libgo/go/image/internal/imageutil/gen.go b/libgo/go/image/internal/imageutil/gen.go new file mode 100644 index 00000000000..fc1e707f0fd --- /dev/null +++ b/libgo/go/image/internal/imageutil/gen.go @@ -0,0 +1,154 @@ +// Copyright 2015 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 + +package main + +import ( + "bytes" + "flag" + "fmt" + "go/format" + "io/ioutil" + "log" + "os" +) + +var debug = flag.Bool("debug", false, "") + +func main() { + flag.Parse() + + w := new(bytes.Buffer) + w.WriteString(pre) + for _, sratio := range subsampleRatios { + fmt.Fprintf(w, sratioCase, sratio, sratioLines[sratio]) + } + w.WriteString(post) + + if *debug { + os.Stdout.Write(w.Bytes()) + return + } + out, err := format.Source(w.Bytes()) + if err != nil { + log.Fatal(err) + } + if err := ioutil.WriteFile("impl.go", out, 0660); err != nil { + log.Fatal(err) + } +} + +const pre = `// generated by "go run gen.go". DO NOT EDIT. + +package imageutil + +import ( + "image" +) + +// DrawYCbCr draws the YCbCr source image on the RGBA destination image with +// r.Min in dst aligned with sp in src. It reports whether the draw was +// successful. If it returns false, no dst pixels were changed. +// +// This function assumes that r is entirely within dst's bounds and the +// translation of r from dst coordinate space to src coordinate space is +// entirely within src's bounds. +func DrawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Point) (ok bool) { + // This function exists in the image/internal/imageutil package because it + // is needed by both the image/draw and image/jpeg packages, but it doesn't + // seem right for one of those two to depend on the other. + // + // Another option is to have this code be exported in the image package, + // but we'd need to make sure we're totally happy with the API (for the + // rest of Go 1 compatibility), and decide if we want to have a more + // general purpose DrawToRGBA method for other image types. One possibility + // is: + // + // func (src *YCbCr) CopyToRGBA(dst *RGBA, dr, sr Rectangle) (effectiveDr, effectiveSr Rectangle) + // + // in the spirit of the built-in copy function for 1-dimensional slices, + // that also allowed a CopyFromRGBA method if needed. + + x0 := (r.Min.X - dst.Rect.Min.X) * 4 + x1 := (r.Max.X - dst.Rect.Min.X) * 4 + y0 := r.Min.Y - dst.Rect.Min.Y + y1 := r.Max.Y - dst.Rect.Min.Y + switch src.SubsampleRatio { +` + +const post = ` + default: + return false + } + return true +} +` + +const sratioCase = ` + case image.YCbCrSubsampleRatio%s: + for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 { + dpix := dst.Pix[y*dst.Stride:] + yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X) + %s + + // This is an inline version of image/color/ycbcr.go's func YCbCrToRGB. + yy1 := int32(src.Y[yi]) * 0x10100 // Convert 0x12 to 0x121200. + cb1 := int32(src.Cb[ci]) - 128 + cr1 := int32(src.Cr[ci]) - 128 + r := (yy1 + 91881*cr1) >> 16 + g := (yy1 - 22554*cb1 - 46802*cr1) >> 16 + b := (yy1 + 116130*cb1) >> 16 + if r < 0 { + r = 0 + } else if r > 255 { + r = 255 + } + if g < 0 { + g = 0 + } else if g > 255 { + g = 255 + } + if b < 0 { + b = 0 + } else if b > 255 { + b = 255 + } + + dpix[x+0] = uint8(r) + dpix[x+1] = uint8(g) + dpix[x+2] = uint8(b) + dpix[x+3] = 255 + } + } +` + +var subsampleRatios = []string{ + "444", + "422", + "420", + "440", +} + +var sratioLines = map[string]string{ + "444": ` + ci := (sy-src.Rect.Min.Y)*src.CStride + (sp.X - src.Rect.Min.X) + for x := x0; x != x1; x, yi, ci = x+4, yi+1, ci+1 { + `, + "422": ` + ciBase := (sy-src.Rect.Min.Y)*src.CStride - src.Rect.Min.X/2 + for x, sx := x0, sp.X; x != x1; x, sx, yi = x+4, sx+1, yi+1 { + ci := ciBase + sx/2 + `, + "420": ` + ciBase := (sy/2-src.Rect.Min.Y/2)*src.CStride - src.Rect.Min.X/2 + for x, sx := x0, sp.X; x != x1; x, sx, yi = x+4, sx+1, yi+1 { + ci := ciBase + sx/2 + `, + "440": ` + ci := (sy/2-src.Rect.Min.Y/2)*src.CStride + (sp.X - src.Rect.Min.X) + for x := x0; x != x1; x, yi, ci = x+4, yi+1, ci+1 { + `, +} diff --git a/libgo/go/image/internal/imageutil/imageutil.go b/libgo/go/image/internal/imageutil/imageutil.go new file mode 100644 index 00000000000..10cef0c6650 --- /dev/null +++ b/libgo/go/image/internal/imageutil/imageutil.go @@ -0,0 +1,8 @@ +// Copyright 2015 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. + +//go:generate go run gen.go + +// Package imageutil contains code shared by image-related packages. +package imageutil diff --git a/libgo/go/image/internal/imageutil/impl.go b/libgo/go/image/internal/imageutil/impl.go new file mode 100644 index 00000000000..fd7826d4a97 --- /dev/null +++ b/libgo/go/image/internal/imageutil/impl.go @@ -0,0 +1,196 @@ +// generated by "go run gen.go". DO NOT EDIT. + +package imageutil + +import ( + "image" +) + +// DrawYCbCr draws the YCbCr source image on the RGBA destination image with +// r.Min in dst aligned with sp in src. It reports whether the draw was +// successful. If it returns false, no dst pixels were changed. +// +// This function assumes that r is entirely within dst's bounds and the +// translation of r from dst coordinate space to src coordinate space is +// entirely within src's bounds. +func DrawYCbCr(dst *image.RGBA, r image.Rectangle, src *image.YCbCr, sp image.Point) (ok bool) { + // This function exists in the image/internal/imageutil package because it + // is needed by both the image/draw and image/jpeg packages, but it doesn't + // seem right for one of those two to depend on the other. + // + // Another option is to have this code be exported in the image package, + // but we'd need to make sure we're totally happy with the API (for the + // rest of Go 1 compatibility), and decide if we want to have a more + // general purpose DrawToRGBA method for other image types. One possibility + // is: + // + // func (src *YCbCr) CopyToRGBA(dst *RGBA, dr, sr Rectangle) (effectiveDr, effectiveSr Rectangle) + // + // in the spirit of the built-in copy function for 1-dimensional slices, + // that also allowed a CopyFromRGBA method if needed. + + x0 := (r.Min.X - dst.Rect.Min.X) * 4 + x1 := (r.Max.X - dst.Rect.Min.X) * 4 + y0 := r.Min.Y - dst.Rect.Min.Y + y1 := r.Max.Y - dst.Rect.Min.Y + switch src.SubsampleRatio { + + case image.YCbCrSubsampleRatio444: + for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 { + dpix := dst.Pix[y*dst.Stride:] + yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X) + + ci := (sy-src.Rect.Min.Y)*src.CStride + (sp.X - src.Rect.Min.X) + for x := x0; x != x1; x, yi, ci = x+4, yi+1, ci+1 { + + // This is an inline version of image/color/ycbcr.go's func YCbCrToRGB. + yy1 := int32(src.Y[yi]) * 0x10100 // Convert 0x12 to 0x121200. + cb1 := int32(src.Cb[ci]) - 128 + cr1 := int32(src.Cr[ci]) - 128 + r := (yy1 + 91881*cr1) >> 16 + g := (yy1 - 22554*cb1 - 46802*cr1) >> 16 + b := (yy1 + 116130*cb1) >> 16 + if r < 0 { + r = 0 + } else if r > 255 { + r = 255 + } + if g < 0 { + g = 0 + } else if g > 255 { + g = 255 + } + if b < 0 { + b = 0 + } else if b > 255 { + b = 255 + } + + dpix[x+0] = uint8(r) + dpix[x+1] = uint8(g) + dpix[x+2] = uint8(b) + dpix[x+3] = 255 + } + } + + case image.YCbCrSubsampleRatio422: + for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 { + dpix := dst.Pix[y*dst.Stride:] + yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X) + + ciBase := (sy-src.Rect.Min.Y)*src.CStride - src.Rect.Min.X/2 + for x, sx := x0, sp.X; x != x1; x, sx, yi = x+4, sx+1, yi+1 { + ci := ciBase + sx/2 + + // This is an inline version of image/color/ycbcr.go's func YCbCrToRGB. + yy1 := int32(src.Y[yi]) * 0x10100 // Convert 0x12 to 0x121200. + cb1 := int32(src.Cb[ci]) - 128 + cr1 := int32(src.Cr[ci]) - 128 + r := (yy1 + 91881*cr1) >> 16 + g := (yy1 - 22554*cb1 - 46802*cr1) >> 16 + b := (yy1 + 116130*cb1) >> 16 + if r < 0 { + r = 0 + } else if r > 255 { + r = 255 + } + if g < 0 { + g = 0 + } else if g > 255 { + g = 255 + } + if b < 0 { + b = 0 + } else if b > 255 { + b = 255 + } + + dpix[x+0] = uint8(r) + dpix[x+1] = uint8(g) + dpix[x+2] = uint8(b) + dpix[x+3] = 255 + } + } + + case image.YCbCrSubsampleRatio420: + for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 { + dpix := dst.Pix[y*dst.Stride:] + yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X) + + ciBase := (sy/2-src.Rect.Min.Y/2)*src.CStride - src.Rect.Min.X/2 + for x, sx := x0, sp.X; x != x1; x, sx, yi = x+4, sx+1, yi+1 { + ci := ciBase + sx/2 + + // This is an inline version of image/color/ycbcr.go's func YCbCrToRGB. + yy1 := int32(src.Y[yi]) * 0x10100 // Convert 0x12 to 0x121200. + cb1 := int32(src.Cb[ci]) - 128 + cr1 := int32(src.Cr[ci]) - 128 + r := (yy1 + 91881*cr1) >> 16 + g := (yy1 - 22554*cb1 - 46802*cr1) >> 16 + b := (yy1 + 116130*cb1) >> 16 + if r < 0 { + r = 0 + } else if r > 255 { + r = 255 + } + if g < 0 { + g = 0 + } else if g > 255 { + g = 255 + } + if b < 0 { + b = 0 + } else if b > 255 { + b = 255 + } + + dpix[x+0] = uint8(r) + dpix[x+1] = uint8(g) + dpix[x+2] = uint8(b) + dpix[x+3] = 255 + } + } + + case image.YCbCrSubsampleRatio440: + for y, sy := y0, sp.Y; y != y1; y, sy = y+1, sy+1 { + dpix := dst.Pix[y*dst.Stride:] + yi := (sy-src.Rect.Min.Y)*src.YStride + (sp.X - src.Rect.Min.X) + + ci := (sy/2-src.Rect.Min.Y/2)*src.CStride + (sp.X - src.Rect.Min.X) + for x := x0; x != x1; x, yi, ci = x+4, yi+1, ci+1 { + + // This is an inline version of image/color/ycbcr.go's func YCbCrToRGB. + yy1 := int32(src.Y[yi]) * 0x10100 // Convert 0x12 to 0x121200. + cb1 := int32(src.Cb[ci]) - 128 + cr1 := int32(src.Cr[ci]) - 128 + r := (yy1 + 91881*cr1) >> 16 + g := (yy1 - 22554*cb1 - 46802*cr1) >> 16 + b := (yy1 + 116130*cb1) >> 16 + if r < 0 { + r = 0 + } else if r > 255 { + r = 255 + } + if g < 0 { + g = 0 + } else if g > 255 { + g = 255 + } + if b < 0 { + b = 0 + } else if b > 255 { + b = 255 + } + + dpix[x+0] = uint8(r) + dpix[x+1] = uint8(g) + dpix[x+2] = uint8(b) + dpix[x+3] = 255 + } + } + + default: + return false + } + return true +} diff --git a/libgo/go/image/jpeg/huffman.go b/libgo/go/image/jpeg/huffman.go index d4ff4cfa0ce..4f8fe8eff32 100644 --- a/libgo/go/image/jpeg/huffman.go +++ b/libgo/go/image/jpeg/huffman.go @@ -187,7 +187,9 @@ func (d *decoder) decodeHuffman(h *huffman) (uint8, error) { // There are no more bytes of data in this segment, but we may still // be able to read the next symbol out of the previously read bits. // First, undo the readByte that the ensureNBits call made. - d.unreadByteStuffedByte() + if d.bytes.nUnreadable != 0 { + d.unreadByteStuffedByte() + } goto slowPath } } diff --git a/libgo/go/image/jpeg/reader.go b/libgo/go/image/jpeg/reader.go index 6d8b1d1d036..adf97abbd1d 100644 --- a/libgo/go/image/jpeg/reader.go +++ b/libgo/go/image/jpeg/reader.go @@ -10,6 +10,7 @@ package jpeg import ( "image" "image/color" + "image/internal/imageutil" "io" ) @@ -26,6 +27,8 @@ type UnsupportedError string func (e UnsupportedError) Error() string { return "unsupported JPEG feature: " + string(e) } +var errUnsupportedSubsamplingRatio = UnsupportedError("luma/chroma subsampling ratio") + // Component specification, specified in section B.2.2. type component struct { h int // Horizontal sampling factor. @@ -41,32 +44,35 @@ const ( maxTh = 3 maxTq = 3 - // A grayscale JPEG image has only a Y component. - nGrayComponent = 1 - // A color JPEG image has Y, Cb and Cr components. - nColorComponent = 3 + maxComponents = 4 +) - // We only support 4:4:4, 4:4:0, 4:2:2 and 4:2:0 downsampling, and therefore the - // number of luma samples per chroma sample is at most 2 in the horizontal - // and 2 in the vertical direction. - maxH = 2 - maxV = 2 +const ( + sof0Marker = 0xc0 // Start Of Frame (Baseline). + sof1Marker = 0xc1 // Start Of Frame (Extended Sequential). + sof2Marker = 0xc2 // Start Of Frame (Progressive). + dhtMarker = 0xc4 // Define Huffman Table. + rst0Marker = 0xd0 // ReSTart (0). + rst7Marker = 0xd7 // ReSTart (7). + soiMarker = 0xd8 // Start Of Image. + eoiMarker = 0xd9 // End Of Image. + sosMarker = 0xda // Start Of Scan. + dqtMarker = 0xdb // Define Quantization Table. + driMarker = 0xdd // Define Restart Interval. + comMarker = 0xfe // COMment. + // "APPlication specific" markers aren't part of the JPEG spec per se, + // but in practice, their use is described at + // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/JPEG.html + app0Marker = 0xe0 + app14Marker = 0xee + app15Marker = 0xef ) +// See http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/JPEG.html#Adobe const ( - soiMarker = 0xd8 // Start Of Image. - eoiMarker = 0xd9 // End Of Image. - sof0Marker = 0xc0 // Start Of Frame (Baseline). - sof2Marker = 0xc2 // Start Of Frame (Progressive). - dhtMarker = 0xc4 // Define Huffman Table. - dqtMarker = 0xdb // Define Quantization Table. - sosMarker = 0xda // Start Of Scan. - driMarker = 0xdd // Define Restart Interval. - rst0Marker = 0xd0 // ReSTart (0). - rst7Marker = 0xd7 // ReSTart (7). - app0Marker = 0xe0 // APPlication specific (0). - app15Marker = 0xef // APPlication specific (15). - comMarker = 0xfe // COMment. + adobeTransformUnknown = 0 + adobeTransformYCbCr = 1 + adobeTransformYCbCrK = 2 ) // unzig maps from the zig-zag ordering to the natural ordering. For example, @@ -83,7 +89,7 @@ var unzig = [blockSize]int{ 53, 60, 61, 54, 47, 55, 62, 63, } -// Reader is deprecated. +// Deprecated: Reader is deprecated. type Reader interface { io.ByteReader io.Reader @@ -114,17 +120,25 @@ type decoder struct { nUnreadable int } width, height int - img1 *image.Gray - img3 *image.YCbCr - ri int // Restart Interval. - nComp int - progressive bool - eobRun uint16 // End-of-Band run, specified in section G.1.2.2. - comp [nColorComponent]component - progCoeffs [nColorComponent][]block // Saved state between progressive-mode scans. - huff [maxTc + 1][maxTh + 1]huffman - quant [maxTq + 1]block // Quantization tables, in zig-zag order. - tmp [blockSize + 1]byte + + img1 *image.Gray + img3 *image.YCbCr + blackPix []byte + blackStride int + + ri int // Restart Interval. + nComp int + progressive bool + jfif bool + adobeTransformValid bool + adobeTransform uint8 + eobRun uint16 // End-of-Band run, specified in section G.1.2.2. + + comp [maxComponents]component + progCoeffs [maxComponents][]block // Saved state between progressive-mode scans. + huff [maxTc + 1][maxTh + 1]huffman + quant [maxTq + 1]block // Quantization tables, in zig-zag order. + tmp [2 * blockSize]byte } // fill fills up the d.bytes.buf buffer from the underlying io.Reader. It @@ -155,9 +169,6 @@ func (d *decoder) fill() error { // sometimes overshoot and read one or two too many bytes. Two-byte overshoot // can happen when expecting to read a 0xff 0x00 byte-stuffed byte. func (d *decoder) unreadByteStuffedByte() { - if d.bytes.nUnreadable == 0 { - panic("jpeg: unreadByteStuffedByte call cannot be fulfilled") - } d.bytes.i -= d.bytes.nUnreadable d.bytes.nUnreadable = 0 if d.bits.n >= 8 { @@ -203,18 +214,19 @@ func (d *decoder) readByteStuffedByte() (x byte, err error) { return 0xff, nil } + d.bytes.nUnreadable = 0 + x, err = d.readByte() if err != nil { return 0, err } + d.bytes.nUnreadable = 1 if x != 0xff { - d.bytes.nUnreadable = 1 return x, nil } x, err = d.readByte() if err != nil { - d.bytes.nUnreadable = 1 return 0, err } d.bytes.nUnreadable = 2 @@ -284,13 +296,18 @@ func (d *decoder) ignore(n int) error { // Specified in section B.2.2. func (d *decoder) processSOF(n int) error { + if d.nComp != 0 { + return FormatError("multiple SOF markers") + } switch n { - case 6 + 3*nGrayComponent: - d.nComp = nGrayComponent - case 6 + 3*nColorComponent: - d.nComp = nColorComponent + case 6 + 3*1: // Grayscale image. + d.nComp = 1 + case 6 + 3*3: // YCbCr or RGB image. + d.nComp = 3 + case 6 + 3*4: // YCbCrK or CMYK image. + d.nComp = 4 default: - return UnsupportedError("SOF has wrong length") + return UnsupportedError("number of components") } if err := d.readFull(d.tmp[:n]); err != nil { return err @@ -302,12 +319,34 @@ func (d *decoder) processSOF(n int) error { d.height = int(d.tmp[1])<<8 + int(d.tmp[2]) d.width = int(d.tmp[3])<<8 + int(d.tmp[4]) if int(d.tmp[5]) != d.nComp { - return UnsupportedError("SOF has wrong number of image components") + return FormatError("SOF has wrong length") } + for i := 0; i < d.nComp; i++ { d.comp[i].c = d.tmp[6+3*i] + // Section B.2.2 states that "the value of C_i shall be different from + // the values of C_1 through C_(i-1)". + for j := 0; j < i; j++ { + if d.comp[i].c == d.comp[j].c { + return FormatError("repeated component identifier") + } + } + d.comp[i].tq = d.tmp[8+3*i] - if d.nComp == nGrayComponent { + if d.comp[i].tq > maxTq { + return FormatError("bad Tq value") + } + + hv := d.tmp[7+3*i] + h, v := int(hv>>4), int(hv&0x0f) + if h < 1 || 4 < h || v < 1 || 4 < v { + return FormatError("luma/chroma subsampling ratio") + } + if h == 3 || v == 3 { + return errUnsupportedSubsamplingRatio + } + switch d.nComp { + case 1: // If a JPEG image has only one component, section A.2 says "this data // is non-interleaved by definition" and section A.2.2 says "[in this // case...] the order of data units within a scan shall be left-to-right @@ -319,45 +358,104 @@ func (d *decoder) processSOF(n int) error { // always 1. The component's (h, v) is effectively always (1, 1): even if // the nominal (h, v) is (2, 1), a 20x5 image is encoded in three 8x8 // MCUs, not two 16x8 MCUs. - d.comp[i].h = 1 - d.comp[i].v = 1 - continue - } - hv := d.tmp[7+3*i] - d.comp[i].h = int(hv >> 4) - d.comp[i].v = int(hv & 0x0f) - // For color images, we only support 4:4:4, 4:4:0, 4:2:2 or 4:2:0 chroma - // downsampling ratios. This implies that the (h, v) values for the Y - // component are either (1, 1), (1, 2), (2, 1) or (2, 2), and the (h, v) - // values for the Cr and Cb components must be (1, 1). - if i == 0 { - if hv != 0x11 && hv != 0x21 && hv != 0x22 && hv != 0x12 { - return UnsupportedError("luma/chroma downsample ratio") + h, v = 1, 1 + + case 3: + // For YCbCr images, we only support 4:4:4, 4:4:0, 4:2:2, 4:2:0, + // 4:1:1 or 4:1:0 chroma subsampling ratios. This implies that the + // (h, v) values for the Y component are either (1, 1), (1, 2), + // (2, 1), (2, 2), (4, 1) or (4, 2), and the Y component's values + // must be a multiple of the Cb and Cr component's values. We also + // assume that the two chroma components have the same subsampling + // ratio. + switch i { + case 0: // Y. + // We have already verified, above, that h and v are both + // either 1, 2 or 4, so invalid (h, v) combinations are those + // with v == 4. + if v == 4 { + return errUnsupportedSubsamplingRatio + } + case 1: // Cb. + if d.comp[0].h%h != 0 || d.comp[0].v%v != 0 { + return errUnsupportedSubsamplingRatio + } + case 2: // Cr. + if d.comp[1].h != h || d.comp[1].v != v { + return errUnsupportedSubsamplingRatio + } + } + + case 4: + // For 4-component images (either CMYK or YCbCrK), we only support two + // hv vectors: [0x11 0x11 0x11 0x11] and [0x22 0x11 0x11 0x22]. + // Theoretically, 4-component JPEG images could mix and match hv values + // but in practice, those two combinations are the only ones in use, + // and it simplifies the applyBlack code below if we can assume that: + // - for CMYK, the C and K channels have full samples, and if the M + // and Y channels subsample, they subsample both horizontally and + // vertically. + // - for YCbCrK, the Y and K channels have full samples. + switch i { + case 0: + if hv != 0x11 && hv != 0x22 { + return errUnsupportedSubsamplingRatio + } + case 1, 2: + if hv != 0x11 { + return errUnsupportedSubsamplingRatio + } + case 3: + if d.comp[0].h != h || d.comp[0].v != v { + return errUnsupportedSubsamplingRatio + } } - } else if hv != 0x11 { - return UnsupportedError("luma/chroma downsample ratio") } + + d.comp[i].h = h + d.comp[i].v = v } return nil } // Specified in section B.2.4.1. func (d *decoder) processDQT(n int) error { - const qtLength = 1 + blockSize - for ; n >= qtLength; n -= qtLength { - if err := d.readFull(d.tmp[:qtLength]); err != nil { +loop: + for n > 0 { + n-- + x, err := d.readByte() + if err != nil { return err } - pq := d.tmp[0] >> 4 - if pq != 0 { - return UnsupportedError("bad Pq value") - } - tq := d.tmp[0] & 0x0f + tq := x & 0x0f if tq > maxTq { return FormatError("bad Tq value") } - for i := range d.quant[tq] { - d.quant[tq][i] = int32(d.tmp[i+1]) + switch x >> 4 { + default: + return FormatError("bad Pq value") + case 0: + if n < blockSize { + break loop + } + n -= blockSize + if err := d.readFull(d.tmp[:blockSize]); err != nil { + return err + } + for i := range d.quant[tq] { + d.quant[tq][i] = int32(d.tmp[i]) + } + case 1: + if n < 2*blockSize { + break loop + } + n -= 2 * blockSize + if err := d.readFull(d.tmp[:2*blockSize]); err != nil { + return err + } + for i := range d.quant[tq] { + d.quant[tq][i] = int32(d.tmp[2*i])<<8 | int32(d.tmp[2*i+1]) + } } } if n != 0 { @@ -378,6 +476,43 @@ func (d *decoder) processDRI(n int) error { return nil } +func (d *decoder) processApp0Marker(n int) error { + if n < 5 { + return d.ignore(n) + } + if err := d.readFull(d.tmp[:5]); err != nil { + return err + } + n -= 5 + + d.jfif = d.tmp[0] == 'J' && d.tmp[1] == 'F' && d.tmp[2] == 'I' && d.tmp[3] == 'F' && d.tmp[4] == '\x00' + + if n > 0 { + return d.ignore(n) + } + return nil +} + +func (d *decoder) processApp14Marker(n int) error { + if n < 12 { + return d.ignore(n) + } + if err := d.readFull(d.tmp[:12]); err != nil { + return err + } + n -= 12 + + if d.tmp[0] == 'A' && d.tmp[1] == 'd' && d.tmp[2] == 'o' && d.tmp[3] == 'b' && d.tmp[4] == 'e' { + d.adobeTransformValid = true + d.adobeTransform = d.tmp[11] + } + + if n > 0 { + return d.ignore(n) + } + return nil +} + // decode reads a JPEG image from r and returns it as an image.Image. func (d *decoder) decode(r io.Reader, configOnly bool) (image.Image, error) { d.r = r @@ -459,25 +594,48 @@ func (d *decoder) decode(r io.Reader, configOnly bool) (image.Image, error) { return nil, FormatError("short segment length") } - switch { - case marker == sof0Marker || marker == sof2Marker: // Start Of Frame. + switch marker { + case sof0Marker, sof1Marker, sof2Marker: d.progressive = marker == sof2Marker err = d.processSOF(n) - if configOnly { + if configOnly && d.jfif { return nil, err } - case marker == dhtMarker: // Define Huffman Table. - err = d.processDHT(n) - case marker == dqtMarker: // Define Quantization Table. - err = d.processDQT(n) - case marker == sosMarker: // Start Of Scan. + case dhtMarker: + if configOnly { + err = d.ignore(n) + } else { + err = d.processDHT(n) + } + case dqtMarker: + if configOnly { + err = d.ignore(n) + } else { + err = d.processDQT(n) + } + case sosMarker: + if configOnly { + return nil, nil + } err = d.processSOS(n) - case marker == driMarker: // Define Restart Interval. - err = d.processDRI(n) - case app0Marker <= marker && marker <= app15Marker || marker == comMarker: // APPlication specific, or COMment. - err = d.ignore(n) + case driMarker: + if configOnly { + err = d.ignore(n) + } else { + err = d.processDRI(n) + } + case app0Marker: + err = d.processApp0Marker(n) + case app14Marker: + err = d.processApp14Marker(n) default: - err = UnsupportedError("unknown marker") + if app0Marker <= marker && marker <= app15Marker || marker == comMarker { + err = d.ignore(n) + } else if marker < 0xc0 { // See Table B.1 "Marker code assignments". + err = FormatError("unknown marker") + } else { + err = UnsupportedError("unknown marker") + } } if err != nil { return nil, err @@ -487,11 +645,118 @@ func (d *decoder) decode(r io.Reader, configOnly bool) (image.Image, error) { return d.img1, nil } if d.img3 != nil { + if d.blackPix != nil { + return d.applyBlack() + } else if d.isRGB() { + return d.convertToRGB() + } return d.img3, nil } return nil, FormatError("missing SOS marker") } +// applyBlack combines d.img3 and d.blackPix into a CMYK image. The formula +// used depends on whether the JPEG image is stored as CMYK or YCbCrK, +// indicated by the APP14 (Adobe) metadata. +// +// Adobe CMYK JPEG images are inverted, where 255 means no ink instead of full +// ink, so we apply "v = 255 - v" at various points. Note that a double +// inversion is a no-op, so inversions might be implicit in the code below. +func (d *decoder) applyBlack() (image.Image, error) { + if !d.adobeTransformValid { + return nil, UnsupportedError("unknown color model: 4-component JPEG doesn't have Adobe APP14 metadata") + } + + // If the 4-component JPEG image isn't explicitly marked as "Unknown (RGB + // or CMYK)" as per + // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/JPEG.html#Adobe + // we assume that it is YCbCrK. This matches libjpeg's jdapimin.c. + if d.adobeTransform != adobeTransformUnknown { + // Convert the YCbCr part of the YCbCrK to RGB, invert the RGB to get + // CMY, and patch in the original K. The RGB to CMY inversion cancels + // out the 'Adobe inversion' described in the applyBlack doc comment + // above, so in practice, only the fourth channel (black) is inverted. + bounds := d.img3.Bounds() + img := image.NewRGBA(bounds) + imageutil.DrawYCbCr(img, bounds, d.img3, bounds.Min) + for iBase, y := 0, bounds.Min.Y; y < bounds.Max.Y; iBase, y = iBase+img.Stride, y+1 { + for i, x := iBase+3, bounds.Min.X; x < bounds.Max.X; i, x = i+4, x+1 { + img.Pix[i] = 255 - d.blackPix[(y-bounds.Min.Y)*d.blackStride+(x-bounds.Min.X)] + } + } + return &image.CMYK{ + Pix: img.Pix, + Stride: img.Stride, + Rect: img.Rect, + }, nil + } + + // The first three channels (cyan, magenta, yellow) of the CMYK + // were decoded into d.img3, but each channel was decoded into a separate + // []byte slice, and some channels may be subsampled. We interleave the + // separate channels into an image.CMYK's single []byte slice containing 4 + // contiguous bytes per pixel. + bounds := d.img3.Bounds() + img := image.NewCMYK(bounds) + + translations := [4]struct { + src []byte + stride int + }{ + {d.img3.Y, d.img3.YStride}, + {d.img3.Cb, d.img3.CStride}, + {d.img3.Cr, d.img3.CStride}, + {d.blackPix, d.blackStride}, + } + for t, translation := range translations { + subsample := d.comp[t].h != d.comp[0].h || d.comp[t].v != d.comp[0].v + for iBase, y := 0, bounds.Min.Y; y < bounds.Max.Y; iBase, y = iBase+img.Stride, y+1 { + sy := y - bounds.Min.Y + if subsample { + sy /= 2 + } + for i, x := iBase+t, bounds.Min.X; x < bounds.Max.X; i, x = i+4, x+1 { + sx := x - bounds.Min.X + if subsample { + sx /= 2 + } + img.Pix[i] = 255 - translation.src[sy*translation.stride+sx] + } + } + } + return img, nil +} + +func (d *decoder) isRGB() bool { + if d.jfif { + return false + } + if d.adobeTransformValid && d.adobeTransform == adobeTransformUnknown { + // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/JPEG.html#Adobe + // says that 0 means Unknown (and in practice RGB) and 1 means YCbCr. + return true + } + return d.comp[0].c == 'R' && d.comp[1].c == 'G' && d.comp[2].c == 'B' +} + +func (d *decoder) convertToRGB() (image.Image, error) { + cScale := d.comp[0].h / d.comp[1].h + bounds := d.img3.Bounds() + img := image.NewRGBA(bounds) + for y := bounds.Min.Y; y < bounds.Max.Y; y++ { + po := img.PixOffset(bounds.Min.X, y) + yo := d.img3.YOffset(bounds.Min.X, y) + co := d.img3.COffset(bounds.Min.X, y) + for i, iMax := 0, bounds.Max.X-bounds.Min.X; i < iMax; i++ { + img.Pix[po+4*i+0] = d.img3.Y[yo+i] + img.Pix[po+4*i+1] = d.img3.Cb[co+i/cScale] + img.Pix[po+4*i+2] = d.img3.Cr[co+i/cScale] + img.Pix[po+4*i+3] = 255 + } + } + return img, nil +} + // Decode reads a JPEG image from r and returns it as an image.Image. func Decode(r io.Reader) (image.Image, error) { var d decoder @@ -506,15 +771,25 @@ func DecodeConfig(r io.Reader) (image.Config, error) { return image.Config{}, err } switch d.nComp { - case nGrayComponent: + case 1: return image.Config{ ColorModel: color.GrayModel, Width: d.width, Height: d.height, }, nil - case nColorComponent: + case 3: + cm := color.YCbCrModel + if d.isRGB() { + cm = color.RGBAModel + } + return image.Config{ + ColorModel: cm, + Width: d.width, + Height: d.height, + }, nil + case 4: return image.Config{ - ColorModel: color.YCbCrModel, + ColorModel: color.CMYKModel, Width: d.width, Height: d.height, }, nil diff --git a/libgo/go/image/jpeg/reader_test.go b/libgo/go/image/jpeg/reader_test.go index 4de2e8ee737..77376152bc0 100644 --- a/libgo/go/image/jpeg/reader_test.go +++ b/libgo/go/image/jpeg/reader_test.go @@ -15,6 +15,7 @@ import ( "os" "strings" "testing" + "time" ) // TestDecodeProgressive tests that decoding the baseline and progressive @@ -23,6 +24,8 @@ import ( func TestDecodeProgressive(t *testing.T) { testCases := []string{ "../testdata/video-001", + "../testdata/video-001.q50.410", + "../testdata/video-001.q50.411", "../testdata/video-001.q50.420", "../testdata/video-001.q50.422", "../testdata/video-001.q50.440", @@ -184,6 +187,81 @@ func pixString(pix []byte, stride, x, y int) string { return s.String() } +func TestTruncatedSOSDataDoesntPanic(t *testing.T) { + b, err := ioutil.ReadFile("../testdata/video-005.gray.q50.jpeg") + if err != nil { + t.Fatal(err) + } + sosMarker := []byte{0xff, 0xda} + i := bytes.Index(b, sosMarker) + if i < 0 { + t.Fatal("SOS marker not found") + } + i += len(sosMarker) + j := i + 10 + if j > len(b) { + j = len(b) + } + for ; i < j; i++ { + Decode(bytes.NewReader(b[:i])) + } +} + +func TestLargeImageWithShortData(t *testing.T) { + // This input is an invalid JPEG image, based on the fuzzer-generated image + // in issue 10413. It is only 504 bytes, and shouldn't take long for Decode + // to return an error. The Start Of Frame marker gives the image dimensions + // as 8192 wide and 8192 high, so even if an unreadByteStuffedByte bug + // doesn't technically lead to an infinite loop, such a bug can still cause + // an unreasonably long loop for such a short input. + const input = "" + + "\xff\xd8\xff\xe0\x00\x10\x4a\x46\x49\x46\x00\x01\x01\x00\x00\x01" + + "\x00\x01\x00\x00\xff\xdb\x00\x43\x00\x10\x0b\x0c\x0e\x0c\x0a\x10" + + "\x0e\x89\x0e\x12\x11\x10\x13\x18\xff\xd8\xff\xe0\x00\x10\x4a\x46" + + "\x49\x46\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xff\xdb\x00\x43" + + "\x00\x10\x0b\x0c\x0e\x0c\x0a\x10\x0e\x0d\x0e\x12\x11\x10\x13\x18" + + "\x28\x1a\x18\x16\x16\x18\x31\x23\x25\x1d\x28\x3a\x33\x3d\x3c\x39" + + "\x33\x38\x37\x40\x48\x5c\x4e\x40\x44\x57\x45\x37\x38\x50\x6d\x51" + + "\x57\x5f\x62\x67\x68\x67\x3e\x4d\x71\x79\x70\x64\x78\x5c\x65\x67" + + "\x63\xff\xc0\x00\x0b\x08\x20\x00\x20\x00\x01\x01\x11\x00\xff\xc4" + + "\x00\x1f\x00\x00\x01\x05\x01\x01\x01\x01\x01\x01\x00\x00\x00\x00" + + "\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\xff" + + "\xc4\x00\xb5\x10\x00\x02\x01\x03\x03\x02\x04\x03\x05\x05\x04\x04" + + "\x00\x00\x01\x7d\x01\x02\x03\x00\x04\x11\x05\x12\x21\x31\x01\x06" + + "\x13\x51\x61\x07\x22\x71\x14\x32\x81\x91\xa1\x08\x23\xd8\xff\xdd" + + "\x42\xb1\xc1\x15\x52\xd1\xf0\x24\x33\x62\x72\x82\x09\x0a\x16\x17" + + "\x18\x19\x1a\x25\x26\x27\x28\x29\x2a\x34\x35\x36\x37\x38\x39\x3a" + + "\x43\x44\x45\x46\x47\x48\x49\x4a\x53\x54\x55\x56\x57\x58\x59\x5a" + + "\x00\x63\x64\x65\x66\x67\x68\x69\x6a\x73\x74\x75\x76\x77\x78\x79" + + "\x7a\x83\x84\x85\x86\x87\x88\x89\x8a\x92\x93\x94\x95\x96\x97\x98" + + "\x99\x9a\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xb2\xb3\xb4\xb5\xb6" + + "\xb7\xb8\xb9\xba\xc2\xc3\xc4\xc5\xc6\xc7\xff\xd8\xff\xe0\x00\x10" + + "\x4a\x46\x49\x46\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xff\xdb" + + "\x00\x43\x00\x10\x0b\x0c\x0e\x0c\x0a\x10\x0e\x0d\x0e\x12\x11\x10" + + "\x13\x18\x28\x1a\x18\x16\x16\x18\x31\x23\x25\x1d\xc8\xc9\xca\xd2" + + "\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8" + + "\xe9\xea\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xff\xda\x00\x08" + + "\x01\x01\x00\x00\x3f\x00\xb9\xeb\x50\xb0\xdb\xc8\xa8\xe4\x63\x80" + + "\xdd\x31\xd6\x9d\xbb\xf2\xc5\x42\x1f\x6c\x6f\xf4\x34\xdd\x3c\xfc" + + "\xac\xe7\x3d\x80\xa9\xcc\x87\x34\xb3\x37\xfa\x2b\x9f\x6a\xad\x63" + + "\x20\x36\x9f\x78\x64\x75\xe6\xab\x7d\xb2\xde\x29\x70\xd3\x20\x27" + + "\xde\xaf\xa4\xf0\xca\x9f\x24\xa8\xdf\x46\xa8\x24\x84\x96\xe3\x77" + + "\xf9\x2e\xe0\x0a\x62\x7f\xdf\xd9" + c := make(chan error, 1) + go func() { + _, err := Decode(strings.NewReader(input)) + c <- err + }() + select { + case err := <-c: + if err == nil { + t.Fatalf("got nil error, want non-nil") + } + case <-time.After(3 * time.Second): + t.Fatalf("timed out") + } +} + func TestExtraneousData(t *testing.T) { // Encode a 1x1 red image. src := image.NewRGBA(image.Rect(0, 0, 1, 1)) diff --git a/libgo/go/image/jpeg/scan.go b/libgo/go/image/jpeg/scan.go index 2bd1d9d531d..99734c01af0 100644 --- a/libgo/go/image/jpeg/scan.go +++ b/libgo/go/image/jpeg/scan.go @@ -9,27 +9,42 @@ import ( ) // makeImg allocates and initializes the destination image. -func (d *decoder) makeImg(h0, v0, mxx, myy int) { - if d.nComp == nGrayComponent { +func (d *decoder) makeImg(mxx, myy int) { + if d.nComp == 1 { m := image.NewGray(image.Rect(0, 0, 8*mxx, 8*myy)) d.img1 = m.SubImage(image.Rect(0, 0, d.width, d.height)).(*image.Gray) return } + + h0 := d.comp[0].h + v0 := d.comp[0].v + hRatio := h0 / d.comp[1].h + vRatio := v0 / d.comp[1].v var subsampleRatio image.YCbCrSubsampleRatio - switch { - case h0 == 1 && v0 == 1: + switch hRatio<<4 | vRatio { + case 0x11: subsampleRatio = image.YCbCrSubsampleRatio444 - case h0 == 1 && v0 == 2: + case 0x12: subsampleRatio = image.YCbCrSubsampleRatio440 - case h0 == 2 && v0 == 1: + case 0x21: subsampleRatio = image.YCbCrSubsampleRatio422 - case h0 == 2 && v0 == 2: + case 0x22: subsampleRatio = image.YCbCrSubsampleRatio420 + case 0x41: + subsampleRatio = image.YCbCrSubsampleRatio411 + case 0x42: + subsampleRatio = image.YCbCrSubsampleRatio410 default: panic("unreachable") } m := image.NewYCbCr(image.Rect(0, 0, 8*h0*mxx, 8*v0*myy), subsampleRatio) d.img3 = m.SubImage(image.Rect(0, 0, d.width, d.height)).(*image.YCbCr) + + if d.nComp == 4 { + h3, v3 := d.comp[3].h, d.comp[3].v + d.blackPix = make([]byte, 8*h3*mxx*8*v3*myy) + d.blackStride = 8 * h3 * mxx + } } // Specified in section B.2.3. @@ -47,15 +62,16 @@ func (d *decoder) processSOS(n int) error { if n != 4+2*nComp { return FormatError("SOS length inconsistent with number of components") } - var scan [nColorComponent]struct { + var scan [maxComponents]struct { compIndex uint8 td uint8 // DC table selector. ta uint8 // AC table selector. } + totalHV := 0 for i := 0; i < nComp; i++ { cs := d.tmp[1+2*i] // Component selector. compIndex := -1 - for j, comp := range d.comp { + for j, comp := range d.comp[:d.nComp] { if cs == comp.c { compIndex = j } @@ -64,6 +80,18 @@ func (d *decoder) processSOS(n int) error { return FormatError("unknown component selector") } scan[i].compIndex = uint8(compIndex) + // Section B.2.3 states that "the value of Cs_j shall be different from + // the values of Cs_1 through Cs_(j-1)". Since we have previously + // verified that a frame's component identifiers (C_i values in section + // B.2.2) are unique, it suffices to check that the implicit indexes + // into d.comp are unique. + for j := 0; j < i; j++ { + if scan[i].compIndex == scan[j].compIndex { + return FormatError("repeated component selector") + } + } + totalHV += d.comp[compIndex].h * d.comp[compIndex].v + scan[i].td = d.tmp[2+2*i] >> 4 if scan[i].td > maxTh { return FormatError("bad Td value") @@ -73,6 +101,11 @@ func (d *decoder) processSOS(n int) error { return FormatError("bad Ta value") } } + // Section B.2.3 states that if there is more than one component then the + // total H*V values in a scan must be <= 10. + if d.nComp > 1 && totalHV > 10 { + return FormatError("total sampling factors too large") + } // zigStart and zigEnd are the spectral selection bounds. // ah and al are the successive approximation high and low values. @@ -112,7 +145,7 @@ func (d *decoder) processSOS(n int) error { mxx := (d.width + 8*h0 - 1) / (8 * h0) myy := (d.height + 8*v0 - 1) / (8 * v0) if d.img1 == nil && d.img3 == nil { - d.makeImg(h0, v0, mxx, myy) + d.makeImg(mxx, myy) } if d.progressive { for i := 0; i < nComp; i++ { @@ -128,11 +161,9 @@ func (d *decoder) processSOS(n int) error { var ( // b is the decoded coefficients, in natural (not zig-zag) order. b block - dc [nColorComponent]int32 - // bx and by are the location of the current (in terms of 8x8 blocks). - // For example, with 4:2:0 chroma subsampling, the block whose top left - // pixel co-ordinates are (16, 8) is the third block in the first row: - // bx is 2 and by is 0, even though the pixel is in the second MCU. + dc [maxComponents]int32 + // bx and by are the location of the current block, in units of 8x8 + // blocks: the third block in the first row has (bx, by) = (2, 0). bx, by int blockCount int ) @@ -140,8 +171,10 @@ func (d *decoder) processSOS(n int) error { for mx := 0; mx < mxx; mx++ { for i := 0; i < nComp; i++ { compIndex := scan[i].compIndex + hi := d.comp[compIndex].h + vi := d.comp[compIndex].v qt := &d.quant[d.comp[compIndex].tq] - for j := 0; j < d.comp[compIndex].h*d.comp[compIndex].v; j++ { + for j := 0; j < hi*vi; j++ { // The blocks are traversed one MCU at a time. For 4:2:0 chroma // subsampling, there are four Y 8x8 blocks in every 16x16 MCU. // @@ -168,15 +201,10 @@ func (d *decoder) processSOS(n int) error { // 0 1 2 // 3 4 5 if nComp != 1 { - bx, by = d.comp[compIndex].h*mx, d.comp[compIndex].v*my - if h0 == 1 { - by += j - } else { - bx += j % 2 - by += j / 2 - } + bx = hi*mx + j%hi + by = vi*my + j/hi } else { - q := mxx * d.comp[compIndex].h + q := mxx * hi bx = blockCount % q by = blockCount / q blockCount++ @@ -187,7 +215,7 @@ func (d *decoder) processSOS(n int) error { // Load the previous partially decoded coefficients, if applicable. if d.progressive { - b = d.progCoeffs[compIndex][by*mxx*d.comp[compIndex].h+bx] + b = d.progCoeffs[compIndex][by*mxx*hi+bx] } else { b = block{} } @@ -260,7 +288,7 @@ func (d *decoder) processSOS(n int) error { if d.progressive { if zigEnd != blockSize-1 || al != 0 { // We haven't completely decoded this 8x8 block. Save the coefficients. - d.progCoeffs[compIndex][by*mxx*d.comp[compIndex].h+bx] = b + d.progCoeffs[compIndex][by*mxx*hi+bx] = b // At this point, we could execute the rest of the loop body to dequantize and // perform the inverse DCT, to save early stages of a progressive image to the // *image.YCbCr buffers (the whole point of progressive encoding), but in Go, @@ -276,7 +304,7 @@ func (d *decoder) processSOS(n int) error { } idct(&b) dst, stride := []byte(nil), 0 - if d.nComp == nGrayComponent { + if d.nComp == 1 { dst, stride = d.img1.Pix[8*(by*d.img1.Stride+bx):], d.img1.Stride } else { switch compIndex { @@ -286,6 +314,8 @@ func (d *decoder) processSOS(n int) error { dst, stride = d.img3.Cb[8*(by*d.img3.CStride+bx):], d.img3.CStride case 2: dst, stride = d.img3.Cr[8*(by*d.img3.CStride+bx):], d.img3.CStride + case 3: + dst, stride = d.blackPix[8*(by*d.blackStride+bx):], d.blackStride default: return UnsupportedError("too many components") } @@ -325,7 +355,7 @@ func (d *decoder) processSOS(n int) error { // Reset the Huffman decoder. d.bits = bits{} // Reset the DC components, as per section F.2.1.3.1. - dc = [nColorComponent]int32{} + dc = [maxComponents]int32{} // Reset the progressive decoder state, as per section G.1.2.2. d.eobRun = 0 } diff --git a/libgo/go/image/png/reader.go b/libgo/go/image/png/reader.go index 0a40ca161d9..bbd6f753fad 100644 --- a/libgo/go/image/png/reader.go +++ b/libgo/go/image/png/reader.go @@ -47,6 +47,10 @@ const ( cbTCA16 ) +func cbPaletted(cb int) bool { + return cbP1 <= cb && cb <= cbP8 +} + // Filter type, as per the PNG spec. const ( ftNone = 0 @@ -81,15 +85,16 @@ var interlacing = []interlaceScan{ } // Decoding stage. -// The PNG specification says that the IHDR, PLTE (if present), IDAT and IEND -// chunks must appear in that order. There may be multiple IDAT chunks, and -// IDAT chunks must be sequential (i.e. they may not have any other chunks -// between them). +// The PNG specification says that the IHDR, PLTE (if present), tRNS (if +// present), IDAT and IEND chunks must appear in that order. There may be +// multiple IDAT chunks, and IDAT chunks must be sequential (i.e. they may not +// have any other chunks between them). // http://www.w3.org/TR/PNG/#5ChunkOrdering const ( dsStart = iota dsSeenIHDR dsSeenPLTE + dsSeentRNS dsSeenIDAT dsSeenIEND ) @@ -321,15 +326,23 @@ func (d *decoder) decode() (image.Image, error) { var img image.Image if d.interlace == itNone { img, err = d.readImagePass(r, 0, false) + if err != nil { + return nil, err + } } else if d.interlace == itAdam7 { // Allocate a blank image of the full size. img, err = d.readImagePass(nil, 0, true) + if err != nil { + return nil, err + } for pass := 0; pass < 7; pass++ { imagePass, err := d.readImagePass(r, pass, false) if err != nil { return nil, err } - d.mergePassInto(img, imagePass, pass) + if imagePass != nil { + d.mergePassInto(img, imagePass, pass) + } } } @@ -371,6 +384,12 @@ func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image // Add the multiplication factor and subtract one, effectively rounding up. width = (width - p.xOffset + p.xFactor - 1) / p.xFactor height = (height - p.yOffset + p.yFactor - 1) / p.yFactor + // A PNG image can't have zero width or height, but for an interlaced + // image, an individual pass might have zero width or height. If so, we + // shouldn't even read a per-row filter type byte, so return early. + if width == 0 || height == 0 { + return nil, nil + } } switch d.cb { case cbG1, cbG2, cbG4, cbG8: @@ -425,6 +444,9 @@ func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image // Read the decompressed bytes. _, err := io.ReadFull(r, cr) if err != nil { + if err == io.EOF || err == io.ErrUnexpectedEOF { + return nil, FormatError("not enough pixel data") + } return nil, err } @@ -443,6 +465,9 @@ func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image cdat[i] += p } case ftAverage: + // The first column has no column to the left of it, so it is a + // special case. We know that the first column exists because we + // check above that width != 0, and so len(cdat) != 0. for i := 0; i < bytesPerPixel; i++ { cdat[i] += pdat[i] / 2 } @@ -687,9 +712,10 @@ func (d *decoder) parseChunk() error { if d.stage != dsSeenPLTE { return chunkOrderError } + d.stage = dsSeentRNS return d.parsetRNS(length) case "IDAT": - if d.stage < dsSeenIHDR || d.stage > dsSeenIDAT || (d.cb == cbP8 && d.stage == dsSeenIHDR) { + if d.stage < dsSeenIHDR || d.stage > dsSeenIDAT || (d.stage == dsSeenIHDR && cbPaletted(d.cb)) { return chunkOrderError } d.stage = dsSeenIDAT @@ -779,7 +805,7 @@ func DecodeConfig(r io.Reader) (image.Config, error) { } return image.Config{}, err } - paletted := d.cb == cbP8 || d.cb == cbP4 || d.cb == cbP2 || d.cb == cbP1 + paletted := cbPaletted(d.cb) if d.stage == dsSeenIHDR && !paletted { break } diff --git a/libgo/go/image/png/reader_test.go b/libgo/go/image/png/reader_test.go index ce772eb6f09..f89e7efe7fe 100644 --- a/libgo/go/image/png/reader_test.go +++ b/libgo/go/image/png/reader_test.go @@ -6,12 +6,14 @@ package png import ( "bufio" + "bytes" "fmt" "image" "image/color" "io" "io/ioutil" "os" + "reflect" "strings" "testing" ) @@ -319,6 +321,93 @@ func TestPalettedDecodeConfig(t *testing.T) { } } +func TestInterlaced(t *testing.T) { + a, err := readPNG("testdata/gray-gradient.png") + if err != nil { + t.Fatal(err) + } + b, err := readPNG("testdata/gray-gradient.interlaced.png") + if err != nil { + t.Fatal(err) + } + if !reflect.DeepEqual(a, b) { + t.Fatalf("decodings differ:\nnon-interlaced:\n%#v\ninterlaced:\n%#v", a, b) + } +} + +func TestIncompleteIDATOnRowBoundary(t *testing.T) { + // The following is an invalid 1x2 grayscale PNG image. The header is OK, + // but the zlib-compressed IDAT payload contains two bytes "\x02\x00", + // which is only one row of data (the leading "\x02" is a row filter). + const ( + ihdr = "\x00\x00\x00\x0dIHDR\x00\x00\x00\x01\x00\x00\x00\x02\x08\x00\x00\x00\x00\xbc\xea\xe9\xfb" + idat = "\x00\x00\x00\x0eIDAT\x78\x9c\x62\x62\x00\x04\x00\x00\xff\xff\x00\x06\x00\x03\xfa\xd0\x59\xae" + iend = "\x00\x00\x00\x00IEND\xae\x42\x60\x82" + ) + _, err := Decode(strings.NewReader(pngHeader + ihdr + idat + iend)) + if err == nil { + t.Fatal("got nil error, want non-nil") + } +} + +func TestMultipletRNSChunks(t *testing.T) { + /* + The following is a valid 1x1 paletted PNG image with a 1-element palette + containing color.NRGBA{0xff, 0x00, 0x00, 0x7f}: + 0000000: 8950 4e47 0d0a 1a0a 0000 000d 4948 4452 .PNG........IHDR + 0000010: 0000 0001 0000 0001 0803 0000 0028 cb34 .............(.4 + 0000020: bb00 0000 0350 4c54 45ff 0000 19e2 0937 .....PLTE......7 + 0000030: 0000 0001 7452 4e53 7f80 5cb4 cb00 0000 ....tRNS..\..... + 0000040: 0e49 4441 5478 9c62 6200 0400 00ff ff00 .IDATx.bb....... + 0000050: 0600 03fa d059 ae00 0000 0049 454e 44ae .....Y.....IEND. + 0000060: 4260 82 B`. + Dropping the tRNS chunk makes that color's alpha 0xff instead of 0x7f. + */ + const ( + ihdr = "\x00\x00\x00\x0dIHDR\x00\x00\x00\x01\x00\x00\x00\x01\x08\x03\x00\x00\x00\x28\xcb\x34\xbb" + plte = "\x00\x00\x00\x03PLTE\xff\x00\x00\x19\xe2\x09\x37" + trns = "\x00\x00\x00\x01tRNS\x7f\x80\x5c\xb4\xcb" + idat = "\x00\x00\x00\x0eIDAT\x78\x9c\x62\x62\x00\x04\x00\x00\xff\xff\x00\x06\x00\x03\xfa\xd0\x59\xae" + iend = "\x00\x00\x00\x00IEND\xae\x42\x60\x82" + ) + for i := 0; i < 4; i++ { + var b []byte + b = append(b, pngHeader...) + b = append(b, ihdr...) + b = append(b, plte...) + for j := 0; j < i; j++ { + b = append(b, trns...) + } + b = append(b, idat...) + b = append(b, iend...) + + var want color.Color + m, err := Decode(bytes.NewReader(b)) + switch i { + case 0: + if err != nil { + t.Errorf("%d tRNS chunks: %v", i, err) + continue + } + want = color.RGBA{0xff, 0x00, 0x00, 0xff} + case 1: + if err != nil { + t.Errorf("%d tRNS chunks: %v", i, err) + continue + } + want = color.NRGBA{0xff, 0x00, 0x00, 0x7f} + default: + if err == nil { + t.Errorf("%d tRNS chunks: got nil error, want non-nil", i) + } + continue + } + if got := m.At(0, 0); got != want { + t.Errorf("%d tRNS chunks: got %T %v, want %T %v", i, got, got, want, want) + } + } +} + func benchmarkDecode(b *testing.B, filename string, bytesPerPixel int) { b.StopTimer() data, err := ioutil.ReadFile(filename) diff --git a/libgo/go/image/png/testdata/benchRGB-interlace.png b/libgo/go/image/png/testdata/benchRGB-interlace.png new file mode 100644 index 00000000000..b4b5daba3c6 Binary files /dev/null and b/libgo/go/image/png/testdata/benchRGB-interlace.png differ diff --git a/libgo/go/image/png/testdata/gray-gradient.interlaced.png b/libgo/go/image/png/testdata/gray-gradient.interlaced.png new file mode 100644 index 00000000000..01f657ae86d Binary files /dev/null and b/libgo/go/image/png/testdata/gray-gradient.interlaced.png differ diff --git a/libgo/go/image/png/testdata/gray-gradient.png b/libgo/go/image/png/testdata/gray-gradient.png new file mode 100644 index 00000000000..6de1cd36f4a Binary files /dev/null and b/libgo/go/image/png/testdata/gray-gradient.png differ diff --git a/libgo/go/image/png/testdata/pngsuite/basn3p04-31i.png b/libgo/go/image/png/testdata/pngsuite/basn3p04-31i.png new file mode 100644 index 00000000000..540137cb556 Binary files /dev/null and b/libgo/go/image/png/testdata/pngsuite/basn3p04-31i.png differ diff --git a/libgo/go/image/png/testdata/pngsuite/basn3p04-31i.sng b/libgo/go/image/png/testdata/pngsuite/basn3p04-31i.sng new file mode 100644 index 00000000000..31b87c72d12 --- /dev/null +++ b/libgo/go/image/png/testdata/pngsuite/basn3p04-31i.sng @@ -0,0 +1,57 @@ +#SNG: from basn3p04-31i.png +IHDR { + width: 31; height: 31; bitdepth: 4; + using color palette; +} +gAMA {1.0000} +PLTE { + ( 34, 0,255) # rgb = (0x22,0x00,0xff) + ( 0,255,255) # rgb = (0x00,0xff,0xff) + (136, 0,255) # rgb = (0x88,0x00,0xff) + ( 34,255, 0) # rgb = (0x22,0xff,0x00) + ( 0,153,255) # rgb = (0x00,0x99,0xff) + (255,102, 0) # rgb = (0xff,0x66,0x00) + (221, 0,255) # rgb = (0xdd,0x00,0xff) + (119,255, 0) # rgb = (0x77,0xff,0x00) + (255, 0, 0) # rgb = (0xff,0x00,0x00) + ( 0,255,153) # rgb = (0x00,0xff,0x99) + (221,255, 0) # rgb = (0xdd,0xff,0x00) + (255, 0,187) # rgb = (0xff,0x00,0xbb) + (255,187, 0) # rgb = (0xff,0xbb,0x00) + ( 0, 68,255) # rgb = (0x00,0x44,0xff) + ( 0,255, 68) # rgb = (0x00,0xff,0x44) +} +IMAGE { + pixels hex +88885555ccccaaaa77773333eeee9990 +88885555ccccaaaa77773333eeee9990 +88885555ccccaaaa77773333eeee9990 +88885555ccccaaaa77773333eeee9990 +5555ccccaaaa77773333eeee99991110 +5555ccccaaaa77773333eeee99991110 +5555ccccaaaa77773333eeee99991110 +5555ccccaaaa77773333eeee99991110 +ccccaaaa77773333eeee999911114440 +ccccaaaa77773333eeee999911114440 +ccccaaaa77773333eeee999911114440 +ccccaaaa77773333eeee999911114440 +aaaa77773333eeee999911114444ddd0 +aaaa77773333eeee999911114444ddd0 +aaaa77773333eeee999911114444ddd0 +aaaa77773333eeee999911114444ddd0 +77773333eeee999911114444dddd0000 +77773333eeee999911114444dddd0000 +77773333eeee999911114444dddd0000 +77773333eeee999911114444dddd0000 +3333eeee999911114444dddd00002220 +3333eeee999911114444dddd00002220 +3333eeee999911114444dddd00002220 +3333eeee999911114444dddd00002220 +eeee999911114444dddd000022226660 +eeee999911114444dddd000022226660 +eeee999911114444dddd000022226660 +eeee999911114444dddd000022226660 +999911114444dddd000022226666bbb0 +999911114444dddd000022226666bbb0 +999911114444dddd000022226666bbb0 +} diff --git a/libgo/go/image/testdata/video-001.221212.jpeg b/libgo/go/image/testdata/video-001.221212.jpeg new file mode 100644 index 00000000000..f069c76af9c Binary files /dev/null and b/libgo/go/image/testdata/video-001.221212.jpeg differ diff --git a/libgo/go/image/testdata/video-001.221212.png b/libgo/go/image/testdata/video-001.221212.png new file mode 100644 index 00000000000..d619a6286bc Binary files /dev/null and b/libgo/go/image/testdata/video-001.221212.png differ diff --git a/libgo/go/image/testdata/video-001.cmyk.jpeg b/libgo/go/image/testdata/video-001.cmyk.jpeg new file mode 100644 index 00000000000..507df843b5a Binary files /dev/null and b/libgo/go/image/testdata/video-001.cmyk.jpeg differ diff --git a/libgo/go/image/testdata/video-001.cmyk.png b/libgo/go/image/testdata/video-001.cmyk.png new file mode 100644 index 00000000000..ef7b2b88d87 Binary files /dev/null and b/libgo/go/image/testdata/video-001.cmyk.png differ diff --git a/libgo/go/image/testdata/video-001.q50.410.jpeg b/libgo/go/image/testdata/video-001.q50.410.jpeg new file mode 100644 index 00000000000..4cebd1eb25c Binary files /dev/null and b/libgo/go/image/testdata/video-001.q50.410.jpeg differ diff --git a/libgo/go/image/testdata/video-001.q50.410.progressive.jpeg b/libgo/go/image/testdata/video-001.q50.410.progressive.jpeg new file mode 100644 index 00000000000..fb7140217e2 Binary files /dev/null and b/libgo/go/image/testdata/video-001.q50.410.progressive.jpeg differ diff --git a/libgo/go/image/testdata/video-001.q50.411.jpeg b/libgo/go/image/testdata/video-001.q50.411.jpeg new file mode 100644 index 00000000000..b90de18721d Binary files /dev/null and b/libgo/go/image/testdata/video-001.q50.411.jpeg differ diff --git a/libgo/go/image/testdata/video-001.q50.411.progressive.jpeg b/libgo/go/image/testdata/video-001.q50.411.progressive.jpeg new file mode 100644 index 00000000000..1ddb22b8b0e Binary files /dev/null and b/libgo/go/image/testdata/video-001.q50.411.progressive.jpeg differ diff --git a/libgo/go/image/testdata/video-001.rgb.jpeg b/libgo/go/image/testdata/video-001.rgb.jpeg new file mode 100644 index 00000000000..fc2ce3ca91f Binary files /dev/null and b/libgo/go/image/testdata/video-001.rgb.jpeg differ diff --git a/libgo/go/image/testdata/video-001.rgb.png b/libgo/go/image/testdata/video-001.rgb.png new file mode 100644 index 00000000000..edb716d3415 Binary files /dev/null and b/libgo/go/image/testdata/video-001.rgb.png differ diff --git a/libgo/go/image/ycbcr.go b/libgo/go/image/ycbcr.go index 7c773f2f0a4..93c354b33b4 100644 --- a/libgo/go/image/ycbcr.go +++ b/libgo/go/image/ycbcr.go @@ -16,6 +16,8 @@ const ( YCbCrSubsampleRatio422 YCbCrSubsampleRatio420 YCbCrSubsampleRatio440 + YCbCrSubsampleRatio411 + YCbCrSubsampleRatio410 ) func (s YCbCrSubsampleRatio) String() string { @@ -28,6 +30,10 @@ func (s YCbCrSubsampleRatio) String() string { return "YCbCrSubsampleRatio420" case YCbCrSubsampleRatio440: return "YCbCrSubsampleRatio440" + case YCbCrSubsampleRatio411: + return "YCbCrSubsampleRatio411" + case YCbCrSubsampleRatio410: + return "YCbCrSubsampleRatio410" } return "YCbCrSubsampleRatioUnknown" } @@ -43,6 +49,8 @@ func (s YCbCrSubsampleRatio) String() string { // For 4:2:2, CStride == YStride/2 && len(Cb) == len(Cr) == len(Y)/2. // For 4:2:0, CStride == YStride/2 && len(Cb) == len(Cr) == len(Y)/4. // For 4:4:0, CStride == YStride/1 && len(Cb) == len(Cr) == len(Y)/2. +// For 4:1:1, CStride == YStride/4 && len(Cb) == len(Cr) == len(Y)/4. +// For 4:1:0, CStride == YStride/4 && len(Cb) == len(Cr) == len(Y)/8. type YCbCr struct { Y, Cb, Cr []uint8 YStride int @@ -92,6 +100,10 @@ func (p *YCbCr) COffset(x, y int) int { return (y/2-p.Rect.Min.Y/2)*p.CStride + (x/2 - p.Rect.Min.X/2) case YCbCrSubsampleRatio440: return (y/2-p.Rect.Min.Y/2)*p.CStride + (x - p.Rect.Min.X) + case YCbCrSubsampleRatio411: + return (y-p.Rect.Min.Y)*p.CStride + (x/4 - p.Rect.Min.X/4) + case YCbCrSubsampleRatio410: + return (y/2-p.Rect.Min.Y/2)*p.CStride + (x/4 - p.Rect.Min.X/4) } // Default to 4:4:4 subsampling. return (y-p.Rect.Min.Y)*p.CStride + (x - p.Rect.Min.X) @@ -139,16 +151,25 @@ func NewYCbCr(r Rectangle, subsampleRatio YCbCrSubsampleRatio) *YCbCr { case YCbCrSubsampleRatio440: cw = w ch = (r.Max.Y+1)/2 - r.Min.Y/2 + case YCbCrSubsampleRatio411: + cw = (r.Max.X+3)/4 - r.Min.X/4 + ch = h + case YCbCrSubsampleRatio410: + cw = (r.Max.X+3)/4 - r.Min.X/4 + ch = (r.Max.Y+1)/2 - r.Min.Y/2 default: // Default to 4:4:4 subsampling. cw = w ch = h } - b := make([]byte, w*h+2*cw*ch) + i0 := w*h + 0*cw*ch + i1 := w*h + 1*cw*ch + i2 := w*h + 2*cw*ch + b := make([]byte, i2) return &YCbCr{ - Y: b[:w*h], - Cb: b[w*h+0*cw*ch : w*h+1*cw*ch], - Cr: b[w*h+1*cw*ch : w*h+2*cw*ch], + Y: b[:i0:i0], + Cb: b[i0:i1:i1], + Cr: b[i1:i2:i2], SubsampleRatio: subsampleRatio, YStride: w, CStride: cw, diff --git a/libgo/go/image/ycbcr_test.go b/libgo/go/image/ycbcr_test.go index a5f4482654f..4996bc8dcae 100644 --- a/libgo/go/image/ycbcr_test.go +++ b/libgo/go/image/ycbcr_test.go @@ -37,6 +37,8 @@ func TestYCbCr(t *testing.T) { YCbCrSubsampleRatio422, YCbCrSubsampleRatio420, YCbCrSubsampleRatio440, + YCbCrSubsampleRatio411, + YCbCrSubsampleRatio410, } deltas := []Point{ Pt(0, 0), @@ -105,3 +107,27 @@ func testYCbCr(t *testing.T, r Rectangle, subsampleRatio YCbCrSubsampleRatio, de } } } + +func TestYCbCrSlicesDontOverlap(t *testing.T) { + m := NewYCbCr(Rect(0, 0, 8, 8), YCbCrSubsampleRatio420) + names := []string{"Y", "Cb", "Cr"} + slices := [][]byte{ + m.Y[:cap(m.Y)], + m.Cb[:cap(m.Cb)], + m.Cr[:cap(m.Cr)], + } + for i, slice := range slices { + want := uint8(10 + i) + for j := range slice { + slice[j] = want + } + } + for i, slice := range slices { + want := uint8(10 + i) + for j, got := range slice { + if got != want { + t.Fatalf("m.%s[%d]: got %d, want %d", names[i], j, got, want) + } + } + } +} diff --git a/libgo/go/internal/format/format.go b/libgo/go/internal/format/format.go new file mode 100644 index 00000000000..a8270ba669a --- /dev/null +++ b/libgo/go/internal/format/format.go @@ -0,0 +1,163 @@ +// Copyright 2015 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 format + +import ( + "bytes" + "go/ast" + "go/parser" + "go/printer" + "go/token" + "strings" +) + +const parserMode = parser.ParseComments + +// Parse parses src, which was read from the named file, +// as a Go source file, declaration, or statement list. +func Parse(fset *token.FileSet, filename string, src []byte, fragmentOk bool) ( + file *ast.File, + sourceAdj func(src []byte, indent int) []byte, + indentAdj int, + err error, +) { + // Try as whole source file. + file, err = parser.ParseFile(fset, filename, src, parserMode) + // If there's no error, return. If the error is that the source file didn't begin with a + // package line and source fragments are ok, fall through to + // try as a source fragment. Stop and return on any other error. + if err == nil || !fragmentOk || !strings.Contains(err.Error(), "expected 'package'") { + return + } + + // If this is a declaration list, make it a source file + // by inserting a package clause. + // Insert using a ;, not a newline, so that the line numbers + // in psrc match the ones in src. + psrc := append([]byte("package p;"), src...) + file, err = parser.ParseFile(fset, filename, psrc, parserMode) + if err == nil { + sourceAdj = func(src []byte, indent int) []byte { + // Remove the package clause. + // Gofmt has turned the ; into a \n. + src = src[indent+len("package p\n"):] + return bytes.TrimSpace(src) + } + return + } + // If the error is that the source file didn't begin with a + // declaration, fall through to try as a statement list. + // Stop and return on any other error. + if !strings.Contains(err.Error(), "expected declaration") { + return + } + + // If this is a statement list, make it a source file + // by inserting a package clause and turning the list + // into a function body. This handles expressions too. + // Insert using a ;, not a newline, so that the line numbers + // in fsrc match the ones in src. Add an extra '\n' before the '}' + // to make sure comments are flushed before the '}'. + fsrc := append(append([]byte("package p; func _() {"), src...), '\n', '\n', '}') + file, err = parser.ParseFile(fset, filename, fsrc, parserMode) + if err == nil { + sourceAdj = func(src []byte, indent int) []byte { + // Cap adjusted indent to zero. + if indent < 0 { + indent = 0 + } + // Remove the wrapping. + // Gofmt has turned the ; into a \n\n. + // There will be two non-blank lines with indent, hence 2*indent. + src = src[2*indent+len("package p\n\nfunc _() {"):] + // Remove only the "}\n" suffix: remaining whitespaces will be trimmed anyway + src = src[:len(src)-len("}\n")] + return bytes.TrimSpace(src) + } + // Gofmt has also indented the function body one level. + // Adjust that with indentAdj. + indentAdj = -1 + } + + // Succeeded, or out of options. + return +} + +// Format formats the given package file originally obtained from src +// and adjusts the result based on the original source via sourceAdj +// and indentAdj. +func Format( + fset *token.FileSet, + file *ast.File, + sourceAdj func(src []byte, indent int) []byte, + indentAdj int, + src []byte, + cfg printer.Config, +) ([]byte, error) { + if sourceAdj == nil { + // Complete source file. + var buf bytes.Buffer + err := cfg.Fprint(&buf, fset, file) + if err != nil { + return nil, err + } + return buf.Bytes(), nil + } + + // Partial source file. + // Determine and prepend leading space. + i, j := 0, 0 + for j < len(src) && IsSpace(src[j]) { + if src[j] == '\n' { + i = j + 1 // byte offset of last line in leading space + } + j++ + } + var res []byte + res = append(res, src[:i]...) + + // Determine and prepend indentation of first code line. + // Spaces are ignored unless there are no tabs, + // in which case spaces count as one tab. + indent := 0 + hasSpace := false + for _, b := range src[i:j] { + switch b { + case ' ': + hasSpace = true + case '\t': + indent++ + } + } + if indent == 0 && hasSpace { + indent = 1 + } + for i := 0; i < indent; i++ { + res = append(res, '\t') + } + + // Format the source. + // Write it without any leading and trailing space. + cfg.Indent = indent + indentAdj + var buf bytes.Buffer + err := cfg.Fprint(&buf, fset, file) + if err != nil { + return nil, err + } + res = append(res, sourceAdj(buf.Bytes(), cfg.Indent)...) + + // Determine and append trailing space. + i = len(src) + for i > 0 && IsSpace(src[i-1]) { + i-- + } + return append(res, src[i:]...), nil +} + +// IsSpace reports whether the byte is a space character. +// IsSpace defines a space as being among the following bytes: ' ', '\t', '\n' and '\r'. +func IsSpace(b byte) bool { + return b == ' ' || b == '\t' || b == '\n' || b == '\r' +} diff --git a/libgo/go/internal/singleflight/singleflight.go b/libgo/go/internal/singleflight/singleflight.go new file mode 100644 index 00000000000..f4cb2d670d4 --- /dev/null +++ b/libgo/go/internal/singleflight/singleflight.go @@ -0,0 +1,111 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package singleflight provides a duplicate function call suppression +// mechanism. +package singleflight + +import "sync" + +// call is an in-flight or completed singleflight.Do call +type call struct { + wg sync.WaitGroup + + // These fields are written once before the WaitGroup is done + // and are only read after the WaitGroup is done. + val interface{} + err error + + // These fields are read and written with the singleflight + // mutex held before the WaitGroup is done, and are read but + // not written after the WaitGroup is done. + dups int + chans []chan<- Result +} + +// Group represents a class of work and forms a namespace in +// which units of work can be executed with duplicate suppression. +type Group struct { + mu sync.Mutex // protects m + m map[string]*call // lazily initialized +} + +// Result holds the results of Do, so they can be passed +// on a channel. +type Result struct { + Val interface{} + Err error + Shared bool +} + +// Do executes and returns the results of the given function, making +// sure that only one execution is in-flight for a given key at a +// time. If a duplicate comes in, the duplicate caller waits for the +// original to complete and receives the same results. +// The return value shared indicates whether v was given to multiple callers. +func (g *Group) Do(key string, fn func() (interface{}, error)) (v interface{}, err error, shared bool) { + g.mu.Lock() + if g.m == nil { + g.m = make(map[string]*call) + } + if c, ok := g.m[key]; ok { + c.dups++ + g.mu.Unlock() + c.wg.Wait() + return c.val, c.err, true + } + c := new(call) + c.wg.Add(1) + g.m[key] = c + g.mu.Unlock() + + g.doCall(c, key, fn) + return c.val, c.err, c.dups > 0 +} + +// DoChan is like Do but returns a channel that will receive the +// results when they are ready. +func (g *Group) DoChan(key string, fn func() (interface{}, error)) <-chan Result { + ch := make(chan Result, 1) + g.mu.Lock() + if g.m == nil { + g.m = make(map[string]*call) + } + if c, ok := g.m[key]; ok { + c.dups++ + c.chans = append(c.chans, ch) + g.mu.Unlock() + return ch + } + c := &call{chans: []chan<- Result{ch}} + c.wg.Add(1) + g.m[key] = c + g.mu.Unlock() + + go g.doCall(c, key, fn) + + return ch +} + +// doCall handles the single call for a key. +func (g *Group) doCall(c *call, key string, fn func() (interface{}, error)) { + c.val, c.err = fn() + c.wg.Done() + + g.mu.Lock() + delete(g.m, key) + for _, ch := range c.chans { + ch <- Result{c.val, c.err, c.dups > 0} + } + g.mu.Unlock() +} + +// Forget tells the singleflight to forget about a key. Future calls +// to Do for this key will call the function rather than waiting for +// an earlier call to complete. +func (g *Group) Forget(key string) { + g.mu.Lock() + delete(g.m, key) + g.mu.Unlock() +} diff --git a/libgo/go/internal/singleflight/singleflight_test.go b/libgo/go/internal/singleflight/singleflight_test.go new file mode 100644 index 00000000000..c0ec0240c72 --- /dev/null +++ b/libgo/go/internal/singleflight/singleflight_test.go @@ -0,0 +1,87 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package singleflight + +import ( + "errors" + "fmt" + "sync" + "sync/atomic" + "testing" + "time" +) + +func TestDo(t *testing.T) { + var g Group + v, err, _ := g.Do("key", func() (interface{}, error) { + return "bar", nil + }) + if got, want := fmt.Sprintf("%v (%T)", v, v), "bar (string)"; got != want { + t.Errorf("Do = %v; want %v", got, want) + } + if err != nil { + t.Errorf("Do error = %v", err) + } +} + +func TestDoErr(t *testing.T) { + var g Group + someErr := errors.New("Some error") + v, err, _ := g.Do("key", func() (interface{}, error) { + return nil, someErr + }) + if err != someErr { + t.Errorf("Do error = %v; want someErr %v", err, someErr) + } + if v != nil { + t.Errorf("unexpected non-nil value %#v", v) + } +} + +func TestDoDupSuppress(t *testing.T) { + var g Group + var wg1, wg2 sync.WaitGroup + c := make(chan string, 1) + var calls int32 + fn := func() (interface{}, error) { + if atomic.AddInt32(&calls, 1) == 1 { + // First invocation. + wg1.Done() + } + v := <-c + c <- v // pump; make available for any future calls + + time.Sleep(10 * time.Millisecond) // let more goroutines enter Do + + return v, nil + } + + const n = 10 + wg1.Add(1) + for i := 0; i < n; i++ { + wg1.Add(1) + wg2.Add(1) + go func() { + defer wg2.Done() + wg1.Done() + v, err, _ := g.Do("key", fn) + if err != nil { + t.Errorf("Do error: %v", err) + return + } + if s, _ := v.(string); s != "bar" { + t.Errorf("Do = %T %v; want %q", v, v, "bar") + } + }() + } + wg1.Wait() + // At least one goroutine is in fn now and all of them have at + // least reached the line before the Do. + c <- "bar" + wg2.Wait() + if got := atomic.LoadInt32(&calls); got <= 0 || got >= n { + t.Errorf("number of calls = %d; want over 0 and less than %d", got, n) + } +} diff --git a/libgo/go/internal/syscall/dummy.go b/libgo/go/internal/syscall/dummy.go deleted file mode 100644 index b00eb273f92..00000000000 --- a/libgo/go/internal/syscall/dummy.go +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright 2015 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package syscall diff --git a/libgo/go/internal/syscall/getrandom_linux.go b/libgo/go/internal/syscall/getrandom_linux.go deleted file mode 100644 index 944bab3f5d4..00000000000 --- a/libgo/go/internal/syscall/getrandom_linux.go +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package syscall - -import ( - "runtime" - "sync/atomic" - stdsyscall "syscall" - "unsafe" -) - -var randomTrap = map[string]uintptr{ - "386": 355, - "amd64": 318, - "arm": 384, -}[runtime.GOARCH] - -var randomUnsupported int32 // atomic - -// GetRandomFlag is a flag supported by the getrandom system call. -type GetRandomFlag uintptr - -const ( - // GRND_NONBLOCK means return EAGAIN rather than blocking. - GRND_NONBLOCK GetRandomFlag = 0x0001 - - // GRND_RANDOM means use the /dev/random pool instead of /dev/urandom. - GRND_RANDOM GetRandomFlag = 0x0002 -) - -// GetRandom calls the Linux getrandom system call. -// See https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=c6e9d6f38894798696f23c8084ca7edbf16ee895 -func GetRandom(p []byte, flags GetRandomFlag) (n int, err error) { - if randomTrap == 0 { - return 0, stdsyscall.ENOSYS - } - if len(p) == 0 { - return 0, nil - } - if atomic.LoadInt32(&randomUnsupported) != 0 { - return 0, stdsyscall.ENOSYS - } - r1, _, errno := stdsyscall.Syscall(randomTrap, - uintptr(unsafe.Pointer(&p[0])), - uintptr(len(p)), - uintptr(flags)) - if errno != 0 { - if errno == stdsyscall.ENOSYS { - atomic.StoreInt32(&randomUnsupported, 1) - } - return 0, errno - } - return int(r1), nil -} diff --git a/libgo/go/internal/syscall/unix/dummy.go b/libgo/go/internal/syscall/unix/dummy.go new file mode 100644 index 00000000000..a40e6a3f5da --- /dev/null +++ b/libgo/go/internal/syscall/unix/dummy.go @@ -0,0 +1,5 @@ +// Copyright 2015 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 unix diff --git a/libgo/go/internal/syscall/unix/getrandom_linux.go b/libgo/go/internal/syscall/unix/getrandom_linux.go new file mode 100644 index 00000000000..7388271ef19 --- /dev/null +++ b/libgo/go/internal/syscall/unix/getrandom_linux.go @@ -0,0 +1,58 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package unix + +import ( + "runtime" + "sync/atomic" + "syscall" + "unsafe" +) + +var randomTrap = map[string]uintptr{ + "386": 355, + "amd64": 318, + "arm": 384, + "ppc64": 359, + "ppc64le": 359, +}[runtime.GOARCH] + +var randomUnsupported int32 // atomic + +// GetRandomFlag is a flag supported by the getrandom system call. +type GetRandomFlag uintptr + +const ( + // GRND_NONBLOCK means return EAGAIN rather than blocking. + GRND_NONBLOCK GetRandomFlag = 0x0001 + + // GRND_RANDOM means use the /dev/random pool instead of /dev/urandom. + GRND_RANDOM GetRandomFlag = 0x0002 +) + +// GetRandom calls the Linux getrandom system call. +// See https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=c6e9d6f38894798696f23c8084ca7edbf16ee895 +func GetRandom(p []byte, flags GetRandomFlag) (n int, err error) { + if randomTrap == 0 { + return 0, syscall.ENOSYS + } + if len(p) == 0 { + return 0, nil + } + if atomic.LoadInt32(&randomUnsupported) != 0 { + return 0, syscall.ENOSYS + } + r1, _, errno := syscall.Syscall(randomTrap, + uintptr(unsafe.Pointer(&p[0])), + uintptr(len(p)), + uintptr(flags)) + if errno != 0 { + if errno == syscall.ENOSYS { + atomic.StoreInt32(&randomUnsupported, 1) + } + return 0, errno + } + return int(r1), nil +} diff --git a/libgo/go/internal/syscall/windows/registry/export_test.go b/libgo/go/internal/syscall/windows/registry/export_test.go new file mode 100644 index 00000000000..8badf6fdcf1 --- /dev/null +++ b/libgo/go/internal/syscall/windows/registry/export_test.go @@ -0,0 +1,11 @@ +// Copyright 2015 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 registry + +func (k Key) SetValue(name string, valtype uint32, data []byte) error { + return k.setValue(name, valtype, data) +} diff --git a/libgo/go/internal/syscall/windows/registry/key.go b/libgo/go/internal/syscall/windows/registry/key.go new file mode 100644 index 00000000000..62144d39b76 --- /dev/null +++ b/libgo/go/internal/syscall/windows/registry/key.go @@ -0,0 +1,175 @@ +// Copyright 2015 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 registry provides access to the Windows registry. +// +// Here is a simple example, opening a registry key and reading a string value from it. +// +// k, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion`, registry.QUERY_VALUE) +// if err != nil { +// log.Fatal(err) +// } +// defer k.Close() +// +// s, _, err := k.GetStringValue("SystemRoot") +// if err != nil { +// log.Fatal(err) +// } +// fmt.Printf("Windows system root is %q\n", s) +// +// NOTE: This package is a copy of golang.org/x/sys/windows/registry +// with KeyInfo.ModTime removed to prevent dependency cycles. +// +package registry + +import ( + "io" + "syscall" +) + +const ( + // Registry key security and access rights. + // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms724878.aspx + // for details. + ALL_ACCESS = 0xf003f + CREATE_LINK = 0x00020 + CREATE_SUB_KEY = 0x00004 + ENUMERATE_SUB_KEYS = 0x00008 + EXECUTE = 0x20019 + NOTIFY = 0x00010 + QUERY_VALUE = 0x00001 + READ = 0x20019 + SET_VALUE = 0x00002 + WOW64_32KEY = 0x00200 + WOW64_64KEY = 0x00100 + WRITE = 0x20006 +) + +// Key is a handle to an open Windows registry key. +// Keys can be obtained by calling OpenKey; there are +// also some predefined root keys such as CURRENT_USER. +// Keys can be used directly in the Windows API. +type Key syscall.Handle + +const ( + // Windows defines some predefined root keys that are always open. + // An application can use these keys as entry points to the registry. + // Normally these keys are used in OpenKey to open new keys, + // but they can also be used anywhere a Key is required. + CLASSES_ROOT = Key(syscall.HKEY_CLASSES_ROOT) + CURRENT_USER = Key(syscall.HKEY_CURRENT_USER) + LOCAL_MACHINE = Key(syscall.HKEY_LOCAL_MACHINE) + USERS = Key(syscall.HKEY_USERS) + CURRENT_CONFIG = Key(syscall.HKEY_CURRENT_CONFIG) +) + +// Close closes open key k. +func (k Key) Close() error { + return syscall.RegCloseKey(syscall.Handle(k)) +} + +// OpenKey opens a new key with path name relative to key k. +// It accepts any open key, including CURRENT_USER and others, +// and returns the new key and an error. +// The access parameter specifies desired access rights to the +// key to be opened. +func OpenKey(k Key, path string, access uint32) (Key, error) { + p, err := syscall.UTF16PtrFromString(path) + if err != nil { + return 0, err + } + var subkey syscall.Handle + err = syscall.RegOpenKeyEx(syscall.Handle(k), p, 0, access, &subkey) + if err != nil { + return 0, err + } + return Key(subkey), nil +} + +// ReadSubKeyNames returns the names of subkeys of key k. +// The parameter n controls the number of returned names, +// analogous to the way os.File.Readdirnames works. +func (k Key) ReadSubKeyNames(n int) ([]string, error) { + ki, err := k.Stat() + if err != nil { + return nil, err + } + names := make([]string, 0, ki.SubKeyCount) + buf := make([]uint16, ki.MaxSubKeyLen+1) // extra room for terminating zero byte +loopItems: + for i := uint32(0); ; i++ { + if n > 0 { + if len(names) == n { + return names, nil + } + } + l := uint32(len(buf)) + for { + err := syscall.RegEnumKeyEx(syscall.Handle(k), i, &buf[0], &l, nil, nil, nil, nil) + if err == nil { + break + } + if err == syscall.ERROR_MORE_DATA { + // Double buffer size and try again. + l = uint32(2 * len(buf)) + buf = make([]uint16, l) + continue + } + if err == _ERROR_NO_MORE_ITEMS { + break loopItems + } + return names, err + } + names = append(names, syscall.UTF16ToString(buf[:l])) + } + if n > len(names) { + return names, io.EOF + } + return names, nil +} + +// CreateKey creates a key named path under open key k. +// CreateKey returns the new key and a boolean flag that reports +// whether the key already existed. +// The access parameter specifies the access rights for the key +// to be created. +func CreateKey(k Key, path string, access uint32) (newk Key, openedExisting bool, err error) { + var h syscall.Handle + var d uint32 + err = regCreateKeyEx(syscall.Handle(k), syscall.StringToUTF16Ptr(path), + 0, nil, _REG_OPTION_NON_VOLATILE, access, nil, &h, &d) + if err != nil { + return 0, false, err + } + return Key(h), d == _REG_OPENED_EXISTING_KEY, nil +} + +// DeleteKey deletes the subkey path of key k and its values. +func DeleteKey(k Key, path string) error { + return regDeleteKey(syscall.Handle(k), syscall.StringToUTF16Ptr(path)) +} + +// A KeyInfo describes the statistics of a key. It is returned by Stat. +type KeyInfo struct { + SubKeyCount uint32 + MaxSubKeyLen uint32 // size of the key's subkey with the longest name, in Unicode characters, not including the terminating zero byte + ValueCount uint32 + MaxValueNameLen uint32 // size of the key's longest value name, in Unicode characters, not including the terminating zero byte + MaxValueLen uint32 // longest data component among the key's values, in bytes + lastWriteTime syscall.Filetime +} + +// Stat retrieves information about the open key k. +func (k Key) Stat() (*KeyInfo, error) { + var ki KeyInfo + err := syscall.RegQueryInfoKey(syscall.Handle(k), nil, nil, nil, + &ki.SubKeyCount, &ki.MaxSubKeyLen, nil, &ki.ValueCount, + &ki.MaxValueNameLen, &ki.MaxValueLen, nil, &ki.lastWriteTime) + if err != nil { + return nil, err + } + return &ki, nil +} diff --git a/libgo/go/internal/syscall/windows/registry/registry_test.go b/libgo/go/internal/syscall/windows/registry/registry_test.go new file mode 100644 index 00000000000..07eccb23d8f --- /dev/null +++ b/libgo/go/internal/syscall/windows/registry/registry_test.go @@ -0,0 +1,678 @@ +// Copyright 2015 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 registry_test + +import ( + "bytes" + "crypto/rand" + "os" + "syscall" + "testing" + + "internal/syscall/windows/registry" +) + +func randKeyName(prefix string) string { + const numbers = "0123456789" + buf := make([]byte, 10) + rand.Read(buf) + for i, b := range buf { + buf[i] = numbers[b%byte(len(numbers))] + } + return prefix + string(buf) +} + +func TestReadSubKeyNames(t *testing.T) { + k, err := registry.OpenKey(registry.CLASSES_ROOT, "TypeLib", registry.ENUMERATE_SUB_KEYS|registry.QUERY_VALUE) + if err != nil { + t.Fatal(err) + } + defer k.Close() + + names, err := k.ReadSubKeyNames(-1) + if err != nil { + t.Fatal(err) + } + var foundStdOle bool + for _, name := range names { + // Every PC has "stdole 2.0 OLE Automation" library installed. + if name == "{00020430-0000-0000-C000-000000000046}" { + foundStdOle = true + } + } + if !foundStdOle { + t.Fatal("could not find stdole 2.0 OLE Automation") + } +} + +func TestCreateOpenDeleteKey(t *testing.T) { + k, err := registry.OpenKey(registry.CURRENT_USER, "Software", registry.QUERY_VALUE) + if err != nil { + t.Fatal(err) + } + defer k.Close() + + testKName := randKeyName("TestCreateOpenDeleteKey_") + + testK, exist, err := registry.CreateKey(k, testKName, registry.CREATE_SUB_KEY) + if err != nil { + t.Fatal(err) + } + defer testK.Close() + + if exist { + t.Fatalf("key %q already exists", testKName) + } + + testKAgain, exist, err := registry.CreateKey(k, testKName, registry.CREATE_SUB_KEY) + if err != nil { + t.Fatal(err) + } + defer testKAgain.Close() + + if !exist { + t.Fatalf("key %q should already exist", testKName) + } + + testKOpened, err := registry.OpenKey(k, testKName, registry.ENUMERATE_SUB_KEYS) + if err != nil { + t.Fatal(err) + } + defer testKOpened.Close() + + err = registry.DeleteKey(k, testKName) + if err != nil { + t.Fatal(err) + } + + testKOpenedAgain, err := registry.OpenKey(k, testKName, registry.ENUMERATE_SUB_KEYS) + if err == nil { + defer testKOpenedAgain.Close() + t.Fatalf("key %q should already been deleted", testKName) + } + if err != registry.ErrNotExist { + t.Fatalf(`unexpected error ("not exist" expected): %v`, err) + } +} + +func equalStringSlice(a, b []string) bool { + if len(a) != len(b) { + return false + } + if a == nil { + return true + } + for i := range a { + if a[i] != b[i] { + return false + } + } + return true +} + +type ValueTest struct { + Type uint32 + Name string + Value interface{} + WillFail bool +} + +var ValueTests = []ValueTest{ + {Type: registry.SZ, Name: "String1", Value: ""}, + {Type: registry.SZ, Name: "String2", Value: "\000", WillFail: true}, + {Type: registry.SZ, Name: "String3", Value: "Hello World"}, + {Type: registry.SZ, Name: "String4", Value: "Hello World\000", WillFail: true}, + {Type: registry.EXPAND_SZ, Name: "ExpString1", Value: ""}, + {Type: registry.EXPAND_SZ, Name: "ExpString2", Value: "\000", WillFail: true}, + {Type: registry.EXPAND_SZ, Name: "ExpString3", Value: "Hello World"}, + {Type: registry.EXPAND_SZ, Name: "ExpString4", Value: "Hello\000World", WillFail: true}, + {Type: registry.EXPAND_SZ, Name: "ExpString5", Value: "%PATH%"}, + {Type: registry.EXPAND_SZ, Name: "ExpString6", Value: "%NO_SUCH_VARIABLE%"}, + {Type: registry.EXPAND_SZ, Name: "ExpString7", Value: "%PATH%;."}, + {Type: registry.BINARY, Name: "Binary1", Value: []byte{}}, + {Type: registry.BINARY, Name: "Binary2", Value: []byte{1, 2, 3}}, + {Type: registry.BINARY, Name: "Binary3", Value: []byte{3, 2, 1, 0, 1, 2, 3}}, + {Type: registry.DWORD, Name: "Dword1", Value: uint64(0)}, + {Type: registry.DWORD, Name: "Dword2", Value: uint64(1)}, + {Type: registry.DWORD, Name: "Dword3", Value: uint64(0xff)}, + {Type: registry.DWORD, Name: "Dword4", Value: uint64(0xffff)}, + {Type: registry.QWORD, Name: "Qword1", Value: uint64(0)}, + {Type: registry.QWORD, Name: "Qword2", Value: uint64(1)}, + {Type: registry.QWORD, Name: "Qword3", Value: uint64(0xff)}, + {Type: registry.QWORD, Name: "Qword4", Value: uint64(0xffff)}, + {Type: registry.QWORD, Name: "Qword5", Value: uint64(0xffffff)}, + {Type: registry.QWORD, Name: "Qword6", Value: uint64(0xffffffff)}, + {Type: registry.MULTI_SZ, Name: "MultiString1", Value: []string{"a", "b", "c"}}, + {Type: registry.MULTI_SZ, Name: "MultiString2", Value: []string{"abc", "", "cba"}}, + {Type: registry.MULTI_SZ, Name: "MultiString3", Value: []string{""}}, + {Type: registry.MULTI_SZ, Name: "MultiString4", Value: []string{"abcdef"}}, + {Type: registry.MULTI_SZ, Name: "MultiString5", Value: []string{"\000"}, WillFail: true}, + {Type: registry.MULTI_SZ, Name: "MultiString6", Value: []string{"a\000b"}, WillFail: true}, + {Type: registry.MULTI_SZ, Name: "MultiString7", Value: []string{"ab", "\000", "cd"}, WillFail: true}, + {Type: registry.MULTI_SZ, Name: "MultiString8", Value: []string{"\000", "cd"}, WillFail: true}, + {Type: registry.MULTI_SZ, Name: "MultiString9", Value: []string{"ab", "\000"}, WillFail: true}, +} + +func setValues(t *testing.T, k registry.Key) { + for _, test := range ValueTests { + var err error + switch test.Type { + case registry.SZ: + err = k.SetStringValue(test.Name, test.Value.(string)) + case registry.EXPAND_SZ: + err = k.SetExpandStringValue(test.Name, test.Value.(string)) + case registry.MULTI_SZ: + err = k.SetStringsValue(test.Name, test.Value.([]string)) + case registry.BINARY: + err = k.SetBinaryValue(test.Name, test.Value.([]byte)) + case registry.DWORD: + err = k.SetDWordValue(test.Name, uint32(test.Value.(uint64))) + case registry.QWORD: + err = k.SetQWordValue(test.Name, test.Value.(uint64)) + default: + t.Fatalf("unsupported type %d for %s value", test.Type, test.Name) + } + if test.WillFail { + if err == nil { + t.Fatalf("setting %s value %q should fail, but succeeded", test.Name, test.Value) + } + } else { + if err != nil { + t.Fatal(err) + } + } + } +} + +func enumerateValues(t *testing.T, k registry.Key) { + names, err := k.ReadValueNames(-1) + if err != nil { + t.Error(err) + return + } + haveNames := make(map[string]bool) + for _, n := range names { + haveNames[n] = false + } + for _, test := range ValueTests { + wantFound := !test.WillFail + _, haveFound := haveNames[test.Name] + if wantFound && !haveFound { + t.Errorf("value %s is not found while enumerating", test.Name) + } + if haveFound && !wantFound { + t.Errorf("value %s is found while enumerating, but expected to fail", test.Name) + } + if haveFound { + delete(haveNames, test.Name) + } + } + for n, v := range haveNames { + t.Errorf("value %s (%v) is found while enumerating, but has not been cretaed", n, v) + } +} + +func testErrNotExist(t *testing.T, name string, err error) { + if err == nil { + t.Errorf("%s value should not exist", name) + return + } + if err != registry.ErrNotExist { + t.Errorf("reading %s value should return 'not exist' error, but got: %s", name, err) + return + } +} + +func testErrUnexpectedType(t *testing.T, test ValueTest, gottype uint32, err error) { + if err == nil { + t.Errorf("GetXValue(%q) should not succeed", test.Name) + return + } + if err != registry.ErrUnexpectedType { + t.Errorf("reading %s value should return 'unexpected key value type' error, but got: %s", test.Name, err) + return + } + if gottype != test.Type { + t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype) + return + } +} + +func testGetStringValue(t *testing.T, k registry.Key, test ValueTest) { + got, gottype, err := k.GetStringValue(test.Name) + if err != nil { + t.Errorf("GetStringValue(%s) failed: %v", test.Name, err) + return + } + if got != test.Value { + t.Errorf("want %s value %q, got %q", test.Name, test.Value, got) + return + } + if gottype != test.Type { + t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype) + return + } + if gottype == registry.EXPAND_SZ { + _, err = registry.ExpandString(got) + if err != nil { + t.Errorf("ExpandString(%s) failed: %v", got, err) + return + } + } +} + +func testGetIntegerValue(t *testing.T, k registry.Key, test ValueTest) { + got, gottype, err := k.GetIntegerValue(test.Name) + if err != nil { + t.Errorf("GetIntegerValue(%s) failed: %v", test.Name, err) + return + } + if got != test.Value.(uint64) { + t.Errorf("want %s value %v, got %v", test.Name, test.Value, got) + return + } + if gottype != test.Type { + t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype) + return + } +} + +func testGetBinaryValue(t *testing.T, k registry.Key, test ValueTest) { + got, gottype, err := k.GetBinaryValue(test.Name) + if err != nil { + t.Errorf("GetBinaryValue(%s) failed: %v", test.Name, err) + return + } + if !bytes.Equal(got, test.Value.([]byte)) { + t.Errorf("want %s value %v, got %v", test.Name, test.Value, got) + return + } + if gottype != test.Type { + t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype) + return + } +} + +func testGetStringsValue(t *testing.T, k registry.Key, test ValueTest) { + got, gottype, err := k.GetStringsValue(test.Name) + if err != nil { + t.Errorf("GetStringsValue(%s) failed: %v", test.Name, err) + return + } + if !equalStringSlice(got, test.Value.([]string)) { + t.Errorf("want %s value %#v, got %#v", test.Name, test.Value, got) + return + } + if gottype != test.Type { + t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype) + return + } +} + +func testGetValue(t *testing.T, k registry.Key, test ValueTest, size int) { + if size <= 0 { + return + } + // read data with no buffer + gotsize, gottype, err := k.GetValue(test.Name, nil) + if err != nil { + t.Errorf("GetValue(%s, [%d]byte) failed: %v", test.Name, size, err) + return + } + if gotsize != size { + t.Errorf("want %s value size of %d, got %v", test.Name, size, gotsize) + return + } + if gottype != test.Type { + t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype) + return + } + // read data with short buffer + gotsize, gottype, err = k.GetValue(test.Name, make([]byte, size-1)) + if err == nil { + t.Errorf("GetValue(%s, [%d]byte) should fail, but suceeded", test.Name, size-1) + return + } + if err != registry.ErrShortBuffer { + t.Errorf("reading %s value should return 'short buffer' error, but got: %s", test.Name, err) + return + } + if gotsize != size { + t.Errorf("want %s value size of %d, got %v", test.Name, size, gotsize) + return + } + if gottype != test.Type { + t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype) + return + } + // read full data + gotsize, gottype, err = k.GetValue(test.Name, make([]byte, size)) + if err != nil { + t.Errorf("GetValue(%s, [%d]byte) failed: %v", test.Name, size, err) + return + } + if gotsize != size { + t.Errorf("want %s value size of %d, got %v", test.Name, size, gotsize) + return + } + if gottype != test.Type { + t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype) + return + } + // check GetValue returns ErrNotExist as required + _, _, err = k.GetValue(test.Name+"_not_there", make([]byte, size)) + if err == nil { + t.Errorf("GetValue(%q) should not succeed", test.Name) + return + } + if err != registry.ErrNotExist { + t.Errorf("GetValue(%q) should return 'not exist' error, but got: %s", test.Name, err) + return + } +} + +func testValues(t *testing.T, k registry.Key) { + for _, test := range ValueTests { + switch test.Type { + case registry.SZ, registry.EXPAND_SZ: + if test.WillFail { + _, _, err := k.GetStringValue(test.Name) + testErrNotExist(t, test.Name, err) + } else { + testGetStringValue(t, k, test) + _, gottype, err := k.GetIntegerValue(test.Name) + testErrUnexpectedType(t, test, gottype, err) + // Size of utf16 string in bytes is not perfect, + // but correct for current test values. + // Size also includes terminating 0. + testGetValue(t, k, test, (len(test.Value.(string))+1)*2) + } + _, _, err := k.GetStringValue(test.Name + "_string_not_created") + testErrNotExist(t, test.Name+"_string_not_created", err) + case registry.DWORD, registry.QWORD: + testGetIntegerValue(t, k, test) + _, gottype, err := k.GetBinaryValue(test.Name) + testErrUnexpectedType(t, test, gottype, err) + _, _, err = k.GetIntegerValue(test.Name + "_int_not_created") + testErrNotExist(t, test.Name+"_int_not_created", err) + size := 8 + if test.Type == registry.DWORD { + size = 4 + } + testGetValue(t, k, test, size) + case registry.BINARY: + testGetBinaryValue(t, k, test) + _, gottype, err := k.GetStringsValue(test.Name) + testErrUnexpectedType(t, test, gottype, err) + _, _, err = k.GetBinaryValue(test.Name + "_byte_not_created") + testErrNotExist(t, test.Name+"_byte_not_created", err) + testGetValue(t, k, test, len(test.Value.([]byte))) + case registry.MULTI_SZ: + if test.WillFail { + _, _, err := k.GetStringsValue(test.Name) + testErrNotExist(t, test.Name, err) + } else { + testGetStringsValue(t, k, test) + _, gottype, err := k.GetStringValue(test.Name) + testErrUnexpectedType(t, test, gottype, err) + size := 0 + for _, s := range test.Value.([]string) { + size += len(s) + 1 // nil terminated + } + size += 1 // extra nil at the end + size *= 2 // count bytes, not uint16 + testGetValue(t, k, test, size) + } + _, _, err := k.GetStringsValue(test.Name + "_strings_not_created") + testErrNotExist(t, test.Name+"_strings_not_created", err) + default: + t.Errorf("unsupported type %d for %s value", test.Type, test.Name) + continue + } + } +} + +func testStat(t *testing.T, k registry.Key) { + subk, _, err := registry.CreateKey(k, "subkey", registry.CREATE_SUB_KEY) + if err != nil { + t.Error(err) + return + } + defer subk.Close() + + defer registry.DeleteKey(k, "subkey") + + ki, err := k.Stat() + if err != nil { + t.Error(err) + return + } + if ki.SubKeyCount != 1 { + t.Error("key must have 1 subkey") + } + if ki.MaxSubKeyLen != 6 { + t.Error("key max subkey name length must be 6") + } + if ki.ValueCount != 24 { + t.Errorf("key must have 24 values, but is %d", ki.ValueCount) + } + if ki.MaxValueNameLen != 12 { + t.Errorf("key max value name length must be 10, but is %d", ki.MaxValueNameLen) + } + if ki.MaxValueLen != 38 { + t.Errorf("key max value length must be 38, but is %d", ki.MaxValueLen) + } +} + +func deleteValues(t *testing.T, k registry.Key) { + for _, test := range ValueTests { + if test.WillFail { + continue + } + err := k.DeleteValue(test.Name) + if err != nil { + t.Error(err) + continue + } + } + names, err := k.ReadValueNames(-1) + if err != nil { + t.Error(err) + return + } + if len(names) != 0 { + t.Errorf("some values remain after deletion: %v", names) + } +} + +func TestValues(t *testing.T) { + softwareK, err := registry.OpenKey(registry.CURRENT_USER, "Software", registry.QUERY_VALUE) + if err != nil { + t.Fatal(err) + } + defer softwareK.Close() + + testKName := randKeyName("TestValues_") + + k, exist, err := registry.CreateKey(softwareK, testKName, registry.CREATE_SUB_KEY|registry.QUERY_VALUE|registry.SET_VALUE) + if err != nil { + t.Fatal(err) + } + defer k.Close() + + if exist { + t.Fatalf("key %q already exists", testKName) + } + + defer registry.DeleteKey(softwareK, testKName) + + setValues(t, k) + + enumerateValues(t, k) + + testValues(t, k) + + testStat(t, k) + + deleteValues(t, k) +} + +func walkKey(t *testing.T, k registry.Key, kname string) { + names, err := k.ReadValueNames(-1) + if err != nil { + t.Fatalf("reading value names of %s failed: %v", kname, err) + } + for _, name := range names { + _, valtype, err := k.GetValue(name, nil) + if err != nil { + t.Fatalf("reading value type of %s of %s failed: %v", name, kname, err) + } + switch valtype { + case registry.NONE: + case registry.SZ: + _, _, err := k.GetStringValue(name) + if err != nil { + t.Error(err) + } + case registry.EXPAND_SZ: + s, _, err := k.GetStringValue(name) + if err != nil { + t.Error(err) + } + _, err = registry.ExpandString(s) + if err != nil { + t.Error(err) + } + case registry.DWORD, registry.QWORD: + _, _, err := k.GetIntegerValue(name) + if err != nil { + t.Error(err) + } + case registry.BINARY: + _, _, err := k.GetBinaryValue(name) + if err != nil { + t.Error(err) + } + case registry.MULTI_SZ: + _, _, err := k.GetStringsValue(name) + if err != nil { + t.Error(err) + } + case registry.FULL_RESOURCE_DESCRIPTOR, registry.RESOURCE_LIST, registry.RESOURCE_REQUIREMENTS_LIST: + // TODO: not implemented + default: + t.Fatalf("value type %d of %s of %s failed: %v", valtype, name, kname, err) + } + } + + names, err = k.ReadSubKeyNames(-1) + if err != nil { + t.Fatalf("reading sub-keys of %s failed: %v", kname, err) + } + for _, name := range names { + func() { + subk, err := registry.OpenKey(k, name, registry.ENUMERATE_SUB_KEYS|registry.QUERY_VALUE) + if err != nil { + if err == syscall.ERROR_ACCESS_DENIED { + // ignore error, if we are not allowed to access this key + return + } + t.Fatalf("opening sub-keys %s of %s failed: %v", name, kname, err) + } + defer subk.Close() + + walkKey(t, subk, kname+`\`+name) + }() + } +} + +func TestWalkFullRegistry(t *testing.T) { + if testing.Short() { + t.Skip("skipping long running test in short mode") + } + walkKey(t, registry.CLASSES_ROOT, "CLASSES_ROOT") + walkKey(t, registry.CURRENT_USER, "CURRENT_USER") + walkKey(t, registry.LOCAL_MACHINE, "LOCAL_MACHINE") + walkKey(t, registry.USERS, "USERS") + walkKey(t, registry.CURRENT_CONFIG, "CURRENT_CONFIG") +} + +func TestExpandString(t *testing.T) { + got, err := registry.ExpandString("%PATH%") + if err != nil { + t.Fatal(err) + } + want := os.Getenv("PATH") + if got != want { + t.Errorf("want %q string expanded, got %q", want, got) + } +} + +func TestInvalidValues(t *testing.T) { + softwareK, err := registry.OpenKey(registry.CURRENT_USER, "Software", registry.QUERY_VALUE) + if err != nil { + t.Fatal(err) + } + defer softwareK.Close() + + testKName := randKeyName("TestInvalidValues_") + + k, exist, err := registry.CreateKey(softwareK, testKName, registry.CREATE_SUB_KEY|registry.QUERY_VALUE|registry.SET_VALUE) + if err != nil { + t.Fatal(err) + } + defer k.Close() + + if exist { + t.Fatalf("key %q already exists", testKName) + } + + defer registry.DeleteKey(softwareK, testKName) + + var tests = []struct { + Type uint32 + Name string + Data []byte + }{ + {registry.DWORD, "Dword1", nil}, + {registry.DWORD, "Dword2", []byte{1, 2, 3}}, + {registry.QWORD, "Qword1", nil}, + {registry.QWORD, "Qword2", []byte{1, 2, 3}}, + {registry.QWORD, "Qword3", []byte{1, 2, 3, 4, 5, 6, 7}}, + {registry.MULTI_SZ, "MultiString1", nil}, + {registry.MULTI_SZ, "MultiString2", []byte{0}}, + {registry.MULTI_SZ, "MultiString3", []byte{'a', 'b', 0}}, + {registry.MULTI_SZ, "MultiString4", []byte{'a', 0, 0, 'b', 0}}, + {registry.MULTI_SZ, "MultiString5", []byte{'a', 0, 0}}, + } + + for _, test := range tests { + err := k.SetValue(test.Name, test.Type, test.Data) + if err != nil { + t.Fatalf("SetValue for %q failed: %v", test.Name, err) + } + } + + for _, test := range tests { + switch test.Type { + case registry.DWORD, registry.QWORD: + value, valType, err := k.GetIntegerValue(test.Name) + if err == nil { + t.Errorf("GetIntegerValue(%q) succeeded. Returns type=%d value=%v", test.Name, valType, value) + } + case registry.MULTI_SZ: + value, valType, err := k.GetStringsValue(test.Name) + if err == nil { + if len(value) != 0 { + t.Errorf("GetStringsValue(%q) succeeded. Returns type=%d value=%v", test.Name, valType, value) + } + } + default: + t.Errorf("unsupported type %d for %s value", test.Type, test.Name) + } + } +} diff --git a/libgo/go/internal/syscall/windows/registry/syscall.go b/libgo/go/internal/syscall/windows/registry/syscall.go new file mode 100644 index 00000000000..38e573fd227 --- /dev/null +++ b/libgo/go/internal/syscall/windows/registry/syscall.go @@ -0,0 +1,28 @@ +// Copyright 2015 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 registry + +import "syscall" + +//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go syscall.go + +const ( + _REG_OPTION_NON_VOLATILE = 0 + + _REG_CREATED_NEW_KEY = 1 + _REG_OPENED_EXISTING_KEY = 2 + + _ERROR_NO_MORE_ITEMS syscall.Errno = 259 +) + +//sys regCreateKeyEx(key syscall.Handle, subkey *uint16, reserved uint32, class *uint16, options uint32, desired uint32, sa *syscall.SecurityAttributes, result *syscall.Handle, disposition *uint32) (regerrno error) = advapi32.RegCreateKeyExW +//sys regDeleteKey(key syscall.Handle, subkey *uint16) (regerrno error) = advapi32.RegDeleteKeyW +//sys regSetValueEx(key syscall.Handle, valueName *uint16, reserved uint32, vtype uint32, buf *byte, bufsize uint32) (regerrno error) = advapi32.RegSetValueExW +//sys regEnumValue(key syscall.Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, valtype *uint32, buf *byte, buflen *uint32) (regerrno error) = advapi32.RegEnumValueW +//sys regDeleteValue(key syscall.Handle, name *uint16) (regerrno error) = advapi32.RegDeleteValueW + +//sys expandEnvironmentStrings(src *uint16, dst *uint16, size uint32) (n uint32, err error) = kernel32.ExpandEnvironmentStringsW diff --git a/libgo/go/internal/syscall/windows/registry/value.go b/libgo/go/internal/syscall/windows/registry/value.go new file mode 100644 index 00000000000..bb45a236434 --- /dev/null +++ b/libgo/go/internal/syscall/windows/registry/value.go @@ -0,0 +1,330 @@ +// Copyright 2015 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 registry + +import ( + "errors" + "io" + "syscall" + "unicode/utf16" + "unsafe" +) + +const ( + // Registry value types. + NONE = 0 + SZ = 1 + EXPAND_SZ = 2 + BINARY = 3 + DWORD = 4 + DWORD_BIG_ENDIAN = 5 + LINK = 6 + MULTI_SZ = 7 + RESOURCE_LIST = 8 + FULL_RESOURCE_DESCRIPTOR = 9 + RESOURCE_REQUIREMENTS_LIST = 10 + QWORD = 11 +) + +var ( + // ErrShortBuffer is returned when the buffer was too short for the operation. + ErrShortBuffer = syscall.ERROR_MORE_DATA + + // ErrNotExist is returned when a registry key or value does not exist. + ErrNotExist = syscall.ERROR_FILE_NOT_FOUND + + // ErrUnexpectedType is returned by Get*Value when the value's type was unexpected. + ErrUnexpectedType = errors.New("unexpected key value type") +) + +// GetValue retrieves the type and data for the specified value associated +// with an open key k. It fills up buffer buf and returns the retrieved +// byte count n. If buf is too small to fit the stored value it returns +// ErrShortBuffer error along with the required buffer size n. +// If no buffer is provided, it returns true and actual buffer size n. +// If no buffer is provided, GetValue returns the value's type only. +// If the value does not exist, the error returned is ErrNotExist. +// +// GetValue is a low level function. If value's type is known, use the appropriate +// Get*Value function instead. +func (k Key) GetValue(name string, buf []byte) (n int, valtype uint32, err error) { + pname, err := syscall.UTF16PtrFromString(name) + if err != nil { + return 0, 0, err + } + var pbuf *byte + if len(buf) > 0 { + pbuf = (*byte)(unsafe.Pointer(&buf[0])) + } + l := uint32(len(buf)) + err = syscall.RegQueryValueEx(syscall.Handle(k), pname, nil, &valtype, pbuf, &l) + if err != nil { + return int(l), valtype, err + } + return int(l), valtype, nil +} + +func (k Key) getValue(name string, buf []byte) (date []byte, valtype uint32, err error) { + p, err := syscall.UTF16PtrFromString(name) + if err != nil { + return nil, 0, err + } + var t uint32 + n := uint32(len(buf)) + for { + err = syscall.RegQueryValueEx(syscall.Handle(k), p, nil, &t, (*byte)(unsafe.Pointer(&buf[0])), &n) + if err == nil { + return buf[:n], t, nil + } + if err != syscall.ERROR_MORE_DATA { + return nil, 0, err + } + if n <= uint32(len(buf)) { + return nil, 0, err + } + buf = make([]byte, n) + } +} + +// GetStringValue retrieves the string value for the specified +// value name associated with an open key k. It also returns the value's type. +// If value does not exist, GetStringValue returns ErrNotExist. +// If value is not SZ or EXPAND_SZ, it will return the correct value +// type and ErrUnexpectedType. +func (k Key) GetStringValue(name string) (val string, valtype uint32, err error) { + data, typ, err2 := k.getValue(name, make([]byte, 64)) + if err2 != nil { + return "", typ, err2 + } + switch typ { + case SZ, EXPAND_SZ: + default: + return "", typ, ErrUnexpectedType + } + if len(data) == 0 { + return "", typ, nil + } + u := (*[1 << 10]uint16)(unsafe.Pointer(&data[0]))[:] + return syscall.UTF16ToString(u), typ, nil +} + +// ExpandString expands environment-variable strings and replaces +// them with the values defined for the current user. +// Use ExpandString to expand EXPAND_SZ strings. +func ExpandString(value string) (string, error) { + if value == "" { + return "", nil + } + p, err := syscall.UTF16PtrFromString(value) + if err != nil { + return "", err + } + r := make([]uint16, 100) + for { + n, err := expandEnvironmentStrings(p, &r[0], uint32(len(r))) + if err != nil { + return "", err + } + if n <= uint32(len(r)) { + u := (*[1 << 15]uint16)(unsafe.Pointer(&r[0]))[:] + return syscall.UTF16ToString(u), nil + } + r = make([]uint16, n) + } +} + +// GetStringsValue retrieves the []string value for the specified +// value name associated with an open key k. It also returns the value's type. +// If value does not exist, GetStringsValue returns ErrNotExist. +// If value is not MULTI_SZ, it will return the correct value +// type and ErrUnexpectedType. +func (k Key) GetStringsValue(name string) (val []string, valtype uint32, err error) { + data, typ, err2 := k.getValue(name, make([]byte, 64)) + if err2 != nil { + return nil, typ, err2 + } + if typ != MULTI_SZ { + return nil, typ, ErrUnexpectedType + } + if len(data) == 0 { + return nil, typ, nil + } + p := (*[1 << 24]uint16)(unsafe.Pointer(&data[0]))[:len(data)/2] + if len(p) == 0 { + return nil, typ, nil + } + if p[len(p)-1] == 0 { + p = p[:len(p)-1] // remove terminating null + } + val = make([]string, 0, 5) + from := 0 + for i, c := range p { + if c == 0 { + val = append(val, string(utf16.Decode(p[from:i]))) + from = i + 1 + } + } + return val, typ, nil +} + +// GetIntegerValue retrieves the integer value for the specified +// value name associated with an open key k. It also returns the value's type. +// If value does not exist, GetIntegerValue returns ErrNotExist. +// If value is not DWORD or QWORD, it will return the correct value +// type and ErrUnexpectedType. +func (k Key) GetIntegerValue(name string) (val uint64, valtype uint32, err error) { + data, typ, err2 := k.getValue(name, make([]byte, 8)) + if err2 != nil { + return 0, typ, err2 + } + switch typ { + case DWORD: + if len(data) != 4 { + return 0, typ, errors.New("DWORD value is not 4 bytes long") + } + return uint64(*(*uint32)(unsafe.Pointer(&data[0]))), DWORD, nil + case QWORD: + if len(data) != 8 { + return 0, typ, errors.New("QWORD value is not 8 bytes long") + } + return uint64(*(*uint64)(unsafe.Pointer(&data[0]))), QWORD, nil + default: + return 0, typ, ErrUnexpectedType + } +} + +// GetBinaryValue retrieves the binary value for the specified +// value name associated with an open key k. It also returns the value's type. +// If value does not exist, GetBinaryValue returns ErrNotExist. +// If value is not BINARY, it will return the correct value +// type and ErrUnexpectedType. +func (k Key) GetBinaryValue(name string) (val []byte, valtype uint32, err error) { + data, typ, err2 := k.getValue(name, make([]byte, 64)) + if err2 != nil { + return nil, typ, err2 + } + if typ != BINARY { + return nil, typ, ErrUnexpectedType + } + return data, typ, nil +} + +func (k Key) setValue(name string, valtype uint32, data []byte) error { + p, err := syscall.UTF16PtrFromString(name) + if err != nil { + return err + } + if len(data) == 0 { + return regSetValueEx(syscall.Handle(k), p, 0, valtype, nil, 0) + } + return regSetValueEx(syscall.Handle(k), p, 0, valtype, &data[0], uint32(len(data))) +} + +// SetDWordValue sets the data and type of a name value +// under key k to value and DWORD. +func (k Key) SetDWordValue(name string, value uint32) error { + return k.setValue(name, DWORD, (*[4]byte)(unsafe.Pointer(&value))[:]) +} + +// SetQWordValue sets the data and type of a name value +// under key k to value and QWORD. +func (k Key) SetQWordValue(name string, value uint64) error { + return k.setValue(name, QWORD, (*[8]byte)(unsafe.Pointer(&value))[:]) +} + +func (k Key) setStringValue(name string, valtype uint32, value string) error { + v, err := syscall.UTF16FromString(value) + if err != nil { + return err + } + buf := (*[1 << 10]byte)(unsafe.Pointer(&v[0]))[:len(v)*2] + return k.setValue(name, valtype, buf) +} + +// SetStringValue sets the data and type of a name value +// under key k to value and SZ. The value must not contain a zero byte. +func (k Key) SetStringValue(name, value string) error { + return k.setStringValue(name, SZ, value) +} + +// SetExpandStringValue sets the data and type of a name value +// under key k to value and EXPAND_SZ. The value must not contain a zero byte. +func (k Key) SetExpandStringValue(name, value string) error { + return k.setStringValue(name, EXPAND_SZ, value) +} + +// SetStringsValue sets the data and type of a name value +// under key k to value and MULTI_SZ. The value strings +// must not contain a zero byte. +func (k Key) SetStringsValue(name string, value []string) error { + ss := "" + for _, s := range value { + for i := 0; i < len(s); i++ { + if s[i] == 0 { + return errors.New("string cannot have 0 inside") + } + } + ss += s + "\x00" + } + v := utf16.Encode([]rune(ss + "\x00")) + buf := (*[1 << 10]byte)(unsafe.Pointer(&v[0]))[:len(v)*2] + return k.setValue(name, MULTI_SZ, buf) +} + +// SetBinaryValue sets the data and type of a name value +// under key k to value and BINARY. +func (k Key) SetBinaryValue(name string, value []byte) error { + return k.setValue(name, BINARY, value) +} + +// DeleteValue removes a named value from the key k. +func (k Key) DeleteValue(name string) error { + return regDeleteValue(syscall.Handle(k), syscall.StringToUTF16Ptr(name)) +} + +// ReadValueNames returns the value names of key k. +// The parameter n controls the number of returned names, +// analogous to the way os.File.Readdirnames works. +func (k Key) ReadValueNames(n int) ([]string, error) { + ki, err := k.Stat() + if err != nil { + return nil, err + } + names := make([]string, 0, ki.ValueCount) + buf := make([]uint16, ki.MaxValueNameLen+1) // extra room for terminating null character +loopItems: + for i := uint32(0); ; i++ { + if n > 0 { + if len(names) == n { + return names, nil + } + } + l := uint32(len(buf)) + for { + err := regEnumValue(syscall.Handle(k), i, &buf[0], &l, nil, nil, nil, nil) + if err == nil { + break + } + if err == syscall.ERROR_MORE_DATA { + println(len(buf), l) + // Double buffer size and try again. + l = uint32(2 * len(buf)) + buf = make([]uint16, l) + continue + } + if err == _ERROR_NO_MORE_ITEMS { + break loopItems + } + return names, err + } + names = append(names, syscall.UTF16ToString(buf[:l])) + } + if n > len(names) { + return names, io.EOF + } + return names, nil +} diff --git a/libgo/go/internal/syscall/windows/registry/zsyscall_windows.go b/libgo/go/internal/syscall/windows/registry/zsyscall_windows.go new file mode 100644 index 00000000000..2b3de633c9b --- /dev/null +++ b/libgo/go/internal/syscall/windows/registry/zsyscall_windows.go @@ -0,0 +1,73 @@ +// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT + +package registry + +import "unsafe" +import "syscall" + +var _ unsafe.Pointer + +var ( + modadvapi32 = syscall.NewLazyDLL("advapi32.dll") + modkernel32 = syscall.NewLazyDLL("kernel32.dll") + + procRegCreateKeyExW = modadvapi32.NewProc("RegCreateKeyExW") + procRegDeleteKeyW = modadvapi32.NewProc("RegDeleteKeyW") + procRegSetValueExW = modadvapi32.NewProc("RegSetValueExW") + procRegEnumValueW = modadvapi32.NewProc("RegEnumValueW") + procRegDeleteValueW = modadvapi32.NewProc("RegDeleteValueW") + procExpandEnvironmentStringsW = modkernel32.NewProc("ExpandEnvironmentStringsW") +) + +func regCreateKeyEx(key syscall.Handle, subkey *uint16, reserved uint32, class *uint16, options uint32, desired uint32, sa *syscall.SecurityAttributes, result *syscall.Handle, disposition *uint32) (regerrno error) { + r0, _, _ := syscall.Syscall9(procRegCreateKeyExW.Addr(), 9, uintptr(key), uintptr(unsafe.Pointer(subkey)), uintptr(reserved), uintptr(unsafe.Pointer(class)), uintptr(options), uintptr(desired), uintptr(unsafe.Pointer(sa)), uintptr(unsafe.Pointer(result)), uintptr(unsafe.Pointer(disposition))) + if r0 != 0 { + regerrno = syscall.Errno(r0) + } + return +} + +func regDeleteKey(key syscall.Handle, subkey *uint16) (regerrno error) { + r0, _, _ := syscall.Syscall(procRegDeleteKeyW.Addr(), 2, uintptr(key), uintptr(unsafe.Pointer(subkey)), 0) + if r0 != 0 { + regerrno = syscall.Errno(r0) + } + return +} + +func regSetValueEx(key syscall.Handle, valueName *uint16, reserved uint32, vtype uint32, buf *byte, bufsize uint32) (regerrno error) { + r0, _, _ := syscall.Syscall6(procRegSetValueExW.Addr(), 6, uintptr(key), uintptr(unsafe.Pointer(valueName)), uintptr(reserved), uintptr(vtype), uintptr(unsafe.Pointer(buf)), uintptr(bufsize)) + if r0 != 0 { + regerrno = syscall.Errno(r0) + } + return +} + +func regEnumValue(key syscall.Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, valtype *uint32, buf *byte, buflen *uint32) (regerrno error) { + r0, _, _ := syscall.Syscall9(procRegEnumValueW.Addr(), 8, uintptr(key), uintptr(index), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameLen)), uintptr(unsafe.Pointer(reserved)), uintptr(unsafe.Pointer(valtype)), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(buflen)), 0) + if r0 != 0 { + regerrno = syscall.Errno(r0) + } + return +} + +func regDeleteValue(key syscall.Handle, name *uint16) (regerrno error) { + r0, _, _ := syscall.Syscall(procRegDeleteValueW.Addr(), 2, uintptr(key), uintptr(unsafe.Pointer(name)), 0) + if r0 != 0 { + regerrno = syscall.Errno(r0) + } + return +} + +func expandEnvironmentStrings(src *uint16, dst *uint16, size uint32) (n uint32, err error) { + r0, _, e1 := syscall.Syscall(procExpandEnvironmentStringsW.Addr(), 3, uintptr(unsafe.Pointer(src)), uintptr(unsafe.Pointer(dst)), uintptr(size)) + n = uint32(r0) + if n == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} diff --git a/libgo/go/internal/syscall/windows/syscall_windows.go b/libgo/go/internal/syscall/windows/syscall_windows.go new file mode 100644 index 00000000000..dc8a91626de --- /dev/null +++ b/libgo/go/internal/syscall/windows/syscall_windows.go @@ -0,0 +1,130 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package windows + +import "syscall" + +//go:generate go run ../../../syscall/mksyscall_windows.go -output zsyscall_windows.go syscall_windows.go + +const GAA_FLAG_INCLUDE_PREFIX = 0x00000010 + +const IF_TYPE_SOFTWARE_LOOPBACK = 24 + +type SocketAddress struct { + Sockaddr *syscall.RawSockaddrAny + SockaddrLength int32 +} + +type IpAdapterUnicastAddress struct { + Length uint32 + Flags uint32 + Next *IpAdapterUnicastAddress + Address SocketAddress + PrefixOrigin int32 + SuffixOrigin int32 + DadState int32 + ValidLifetime uint32 + PreferredLifetime uint32 + LeaseLifetime uint32 + OnLinkPrefixLength uint8 +} + +type IpAdapterAnycastAddress struct { + Length uint32 + Flags uint32 + Next *IpAdapterAnycastAddress + Address SocketAddress +} + +type IpAdapterMulticastAddress struct { + Length uint32 + Flags uint32 + Next *IpAdapterMulticastAddress + Address SocketAddress +} + +type IpAdapterDnsServerAdapter struct { + Length uint32 + Reserved uint32 + Next *IpAdapterDnsServerAdapter + Address SocketAddress +} + +type IpAdapterPrefix struct { + Length uint32 + Flags uint32 + Next *IpAdapterPrefix + Address SocketAddress + PrefixLength uint32 +} + +type IpAdapterAddresses struct { + Length uint32 + IfIndex uint32 + Next *IpAdapterAddresses + AdapterName *byte + FirstUnicastAddress *IpAdapterUnicastAddress + FirstAnycastAddress *IpAdapterAnycastAddress + FirstMulticastAddress *IpAdapterMulticastAddress + FirstDnsServerAddress *IpAdapterDnsServerAdapter + DnsSuffix *uint16 + Description *uint16 + FriendlyName *uint16 + PhysicalAddress [syscall.MAX_ADAPTER_ADDRESS_LENGTH]byte + PhysicalAddressLength uint32 + Flags uint32 + Mtu uint32 + IfType uint32 + OperStatus uint32 + Ipv6IfIndex uint32 + ZoneIndices [16]uint32 + FirstPrefix *IpAdapterPrefix + /* more fields might be present here. */ +} + +const ( + IfOperStatusUp = 1 + IfOperStatusDown = 2 + IfOperStatusTesting = 3 + IfOperStatusUnknown = 4 + IfOperStatusDormant = 5 + IfOperStatusNotPresent = 6 + IfOperStatusLowerLayerDown = 7 +) + +//sys GetAdaptersAddresses(family uint32, flags uint32, reserved uintptr, adapterAddresses *IpAdapterAddresses, sizeOfPointer *uint32) (errcode error) = iphlpapi.GetAdaptersAddresses +//sys GetComputerNameEx(nameformat uint32, buf *uint16, n *uint32) (err error) = GetComputerNameExW +//sys MoveFileEx(from *uint16, to *uint16, flags uint32) (err error) = MoveFileExW + +const ( + ComputerNameNetBIOS = 0 + ComputerNameDnsHostname = 1 + ComputerNameDnsDomain = 2 + ComputerNameDnsFullyQualified = 3 + ComputerNamePhysicalNetBIOS = 4 + ComputerNamePhysicalDnsHostname = 5 + ComputerNamePhysicalDnsDomain = 6 + ComputerNamePhysicalDnsFullyQualified = 7 + ComputerNameMax = 8 + + MOVEFILE_REPLACE_EXISTING = 0x1 + MOVEFILE_COPY_ALLOWED = 0x2 + MOVEFILE_DELAY_UNTIL_REBOOT = 0x4 + MOVEFILE_WRITE_THROUGH = 0x8 + MOVEFILE_CREATE_HARDLINK = 0x10 + MOVEFILE_FAIL_IF_NOT_TRACKABLE = 0x20 +) + +func Rename(oldpath, newpath string) error { + from, err := syscall.UTF16PtrFromString(oldpath) + if err != nil { + return err + } + to, err := syscall.UTF16PtrFromString(newpath) + if err != nil { + return err + } + return MoveFileEx(from, to, MOVEFILE_REPLACE_EXISTING) +} diff --git a/libgo/go/internal/syscall/windows/zsyscall_windows.go b/libgo/go/internal/syscall/windows/zsyscall_windows.go new file mode 100644 index 00000000000..c6f607a46ad --- /dev/null +++ b/libgo/go/internal/syscall/windows/zsyscall_windows.go @@ -0,0 +1,49 @@ +// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT + +package windows + +import "unsafe" +import "syscall" + +var _ unsafe.Pointer + +var ( + modiphlpapi = syscall.NewLazyDLL("iphlpapi.dll") + modkernel32 = syscall.NewLazyDLL("kernel32.dll") + + procGetAdaptersAddresses = modiphlpapi.NewProc("GetAdaptersAddresses") + procGetComputerNameExW = modkernel32.NewProc("GetComputerNameExW") + procMoveFileExW = modkernel32.NewProc("MoveFileExW") +) + +func GetAdaptersAddresses(family uint32, flags uint32, reserved uintptr, adapterAddresses *IpAdapterAddresses, sizeOfPointer *uint32) (errcode error) { + r0, _, _ := syscall.Syscall6(procGetAdaptersAddresses.Addr(), 5, uintptr(family), uintptr(flags), uintptr(reserved), uintptr(unsafe.Pointer(adapterAddresses)), uintptr(unsafe.Pointer(sizeOfPointer)), 0) + if r0 != 0 { + errcode = syscall.Errno(r0) + } + return +} + +func GetComputerNameEx(nameformat uint32, buf *uint16, n *uint32) (err error) { + r1, _, e1 := syscall.Syscall(procGetComputerNameExW.Addr(), 3, uintptr(nameformat), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(n))) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} + +func MoveFileEx(from *uint16, to *uint16, flags uint32) (err error) { + r1, _, e1 := syscall.Syscall(procMoveFileExW.Addr(), 3, uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(to)), uintptr(flags)) + if r1 == 0 { + if e1 != 0 { + err = error(e1) + } else { + err = syscall.EINVAL + } + } + return +} diff --git a/libgo/go/internal/testenv/testenv.go b/libgo/go/internal/testenv/testenv.go new file mode 100644 index 00000000000..10719084bbb --- /dev/null +++ b/libgo/go/internal/testenv/testenv.go @@ -0,0 +1,104 @@ +// Copyright 2015 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 testenv provides information about what functionality +// is available in different testing environments run by the Go team. +// +// It is an internal package because these details are specific +// to the Go team's test setup (on build.golang.org) and not +// fundamental to tests in general. +package testenv + +import ( + "os" + "runtime" + "strings" + "testing" +) + +// Builder reports the name of the builder running this test +// (for example, "linux-amd64" or "windows-386-gce"). +// If the test is not running on the build infrastructure, +// Builder returns the empty string. +func Builder() string { + return os.Getenv("GO_BUILDER_NAME") +} + +// HasGoBuild reports whether the current system can build programs with ``go build'' +// and then run them with os.StartProcess or exec.Command. +func HasGoBuild() bool { + switch runtime.GOOS { + case "android", "nacl": + return false + case "darwin": + if strings.HasPrefix(runtime.GOARCH, "arm") { + return false + } + } + // gccgo tests can not run "go build". + return false +} + +// MustHaveGoBuild checks that the current system can build programs with ``go build'' +// and then run them with os.StartProcess or exec.Command. +// If not, MustHaveGoBuild calls t.Skip with an explanation. +func MustHaveGoBuild(t *testing.T) { + t.Skip("skipping test: 'go build' not available for gccgo tests") + if !HasGoBuild() { + t.Skipf("skipping test: 'go build' not available on %s/%s", runtime.GOOS, runtime.GOARCH) + } +} + +// HasGoRun reports whether the current system can run programs with ``go run.'' +func HasGoRun() bool { + // For now, having go run and having go build are the same. + return HasGoBuild() +} + +// MustHaveGoRun checks that the current system can run programs with ``go run.'' +// If not, MustHaveGoRun calls t.Skip with an explanation. +func MustHaveGoRun(t *testing.T) { + t.Skip("skipping test: 'go run' not available for gccgo tests") + if !HasGoRun() { + t.Skipf("skipping test: 'go run' not available on %s/%s", runtime.GOOS, runtime.GOARCH) + } +} + +// HasExec reports whether the current system can start new processes +// using os.StartProcess or (more commonly) exec.Command. +func HasExec() bool { + switch runtime.GOOS { + case "nacl": + return false + case "darwin": + if strings.HasPrefix(runtime.GOARCH, "arm") { + return false + } + } + return true +} + +// MustHaveExec checks that the current system can start new processes +// using os.StartProcess or (more commonly) exec.Command. +// If not, MustHaveExec calls t.Skip with an explanation. +func MustHaveExec(t *testing.T) { + if !HasExec() { + t.Skipf("skipping test: cannot exec subprocess on %s/%s", runtime.GOOS, runtime.GOARCH) + } +} + +// HasExternalNetwork reports whether the current system can use +// external (non-localhost) networks. +func HasExternalNetwork() bool { + return !testing.Short() +} + +// MustHaveExternalNetwork checks that the current system can use +// external (non-localhost) networks. +// If not, MustHaveExternalNetwork calls t.Skip with an explanation. +func MustHaveExternalNetwork(t *testing.T) { + if testing.Short() { + t.Skipf("skipping test: no external network in -short mode") + } +} diff --git a/libgo/go/internal/trace/goroutines.go b/libgo/go/internal/trace/goroutines.go new file mode 100644 index 00000000000..f8673e20bc2 --- /dev/null +++ b/libgo/go/internal/trace/goroutines.go @@ -0,0 +1,180 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package trace + +// GDesc contains statistics about execution of a single goroutine. +type GDesc struct { + ID uint64 + Name string + PC uint64 + CreationTime int64 + StartTime int64 + EndTime int64 + + ExecTime int64 + SchedWaitTime int64 + IOTime int64 + BlockTime int64 + SyscallTime int64 + GCTime int64 + SweepTime int64 + TotalTime int64 + + *gdesc // private part +} + +// gdesc is a private part of GDesc that is required only during analysis. +type gdesc struct { + lastStartTime int64 + blockNetTime int64 + blockSyncTime int64 + blockSyscallTime int64 + blockSweepTime int64 + blockGCTime int64 + blockSchedTime int64 +} + +// GoroutineStats generates statistics for all goroutines in the trace. +func GoroutineStats(events []*Event) map[uint64]*GDesc { + gs := make(map[uint64]*GDesc) + var lastTs int64 + var gcStartTime int64 + for _, ev := range events { + lastTs = ev.Ts + switch ev.Type { + case EvGoCreate: + g := &GDesc{ID: ev.Args[0], CreationTime: ev.Ts, gdesc: new(gdesc)} + g.blockSchedTime = ev.Ts + gs[g.ID] = g + case EvGoStart: + g := gs[ev.G] + if g.PC == 0 { + g.PC = ev.Stk[0].PC + g.Name = ev.Stk[0].Fn + } + g.lastStartTime = ev.Ts + if g.StartTime == 0 { + g.StartTime = ev.Ts + } + if g.blockSchedTime != 0 { + g.SchedWaitTime += ev.Ts - g.blockSchedTime + g.blockSchedTime = 0 + } + case EvGoEnd, EvGoStop: + g := gs[ev.G] + g.ExecTime += ev.Ts - g.lastStartTime + g.TotalTime = ev.Ts - g.CreationTime + g.EndTime = ev.Ts + case EvGoBlockSend, EvGoBlockRecv, EvGoBlockSelect, + EvGoBlockSync, EvGoBlockCond: + g := gs[ev.G] + g.ExecTime += ev.Ts - g.lastStartTime + g.blockSyncTime = ev.Ts + case EvGoSched, EvGoPreempt: + g := gs[ev.G] + g.ExecTime += ev.Ts - g.lastStartTime + g.blockSchedTime = ev.Ts + case EvGoSleep, EvGoBlock: + g := gs[ev.G] + g.ExecTime += ev.Ts - g.lastStartTime + case EvGoBlockNet: + g := gs[ev.G] + g.ExecTime += ev.Ts - g.lastStartTime + g.blockNetTime = ev.Ts + case EvGoUnblock: + g := gs[ev.Args[0]] + if g.blockNetTime != 0 { + g.IOTime += ev.Ts - g.blockNetTime + g.blockNetTime = 0 + } + if g.blockSyncTime != 0 { + g.BlockTime += ev.Ts - g.blockSyncTime + g.blockSyncTime = 0 + } + g.blockSchedTime = ev.Ts + case EvGoSysBlock: + g := gs[ev.G] + g.ExecTime += ev.Ts - g.lastStartTime + g.blockSyscallTime = ev.Ts + case EvGoSysExit: + g := gs[ev.G] + if g.blockSyscallTime != 0 { + g.SyscallTime += ev.Ts - g.blockSyscallTime + g.blockSyscallTime = 0 + } + g.blockSchedTime = ev.Ts + case EvGCSweepStart: + g := gs[ev.G] + if g != nil { + // Sweep can happen during GC on system goroutine. + g.blockSweepTime = ev.Ts + } + case EvGCSweepDone: + g := gs[ev.G] + if g != nil && g.blockSweepTime != 0 { + g.SweepTime += ev.Ts - g.blockSweepTime + g.blockSweepTime = 0 + } + case EvGCStart: + gcStartTime = ev.Ts + case EvGCDone: + for _, g := range gs { + if g.EndTime == 0 { + g.GCTime += ev.Ts - gcStartTime + } + } + } + } + + for _, g := range gs { + if g.TotalTime == 0 { + g.TotalTime = lastTs - g.CreationTime + } + if g.EndTime == 0 { + g.EndTime = lastTs + } + if g.blockNetTime != 0 { + g.IOTime += lastTs - g.blockNetTime + g.blockNetTime = 0 + } + if g.blockSyncTime != 0 { + g.BlockTime += lastTs - g.blockSyncTime + g.blockSyncTime = 0 + } + if g.blockSyscallTime != 0 { + g.SyscallTime += lastTs - g.blockSyscallTime + g.blockSyscallTime = 0 + } + if g.blockSchedTime != 0 { + g.SchedWaitTime += lastTs - g.blockSchedTime + g.blockSchedTime = 0 + } + g.gdesc = nil + } + + return gs +} + +// RelatedGoroutines finds a set of goroutines related to goroutine goid. +func RelatedGoroutines(events []*Event, goid uint64) map[uint64]bool { + // BFS of depth 2 over "unblock" edges + // (what goroutines unblock goroutine goid?). + gmap := make(map[uint64]bool) + gmap[goid] = true + for i := 0; i < 2; i++ { + gmap1 := make(map[uint64]bool) + for g := range gmap { + gmap1[g] = true + } + for _, ev := range events { + if ev.Type == EvGoUnblock && gmap[ev.Args[0]] { + gmap1[ev.G] = true + } + } + gmap = gmap1 + } + gmap[0] = true // for GC events + return gmap +} diff --git a/libgo/go/internal/trace/parser.go b/libgo/go/internal/trace/parser.go new file mode 100644 index 00000000000..1eb39ddd76c --- /dev/null +++ b/libgo/go/internal/trace/parser.go @@ -0,0 +1,786 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package trace + +import ( + "bufio" + "bytes" + "fmt" + "io" + "os" + "os/exec" + "sort" + "strconv" + "strings" +) + +// Event describes one event in the trace. +type Event struct { + Off int // offset in input file (for debugging and error reporting) + Type byte // one of Ev* + Seq int64 // sequence number + Ts int64 // timestamp in nanoseconds + P int // P on which the event happened (can be one of TimerP, NetpollP, SyscallP) + G uint64 // G on which the event happened + StkID uint64 // unique stack ID + Stk []*Frame // stack trace (can be empty) + Args [3]uint64 // event-type-specific arguments + // linked event (can be nil), depends on event type: + // for GCStart: the GCStop + // for GCScanStart: the GCScanDone + // for GCSweepStart: the GCSweepDone + // for GoCreate: first GoStart of the created goroutine + // for GoStart: the associated GoEnd, GoBlock or other blocking event + // for GoSched/GoPreempt: the next GoStart + // for GoBlock and other blocking events: the unblock event + // for GoUnblock: the associated GoStart + // for blocking GoSysCall: the associated GoSysExit + // for GoSysExit: the next GoStart + Link *Event +} + +// Frame is a frame in stack traces. +type Frame struct { + PC uint64 + Fn string + File string + Line int +} + +const ( + // Special P identifiers: + FakeP = 1000000 + iota + TimerP // depicts timer unblocks + NetpollP // depicts network unblocks + SyscallP // depicts returns from syscalls +) + +// Parse parses, post-processes and verifies the trace. +func Parse(r io.Reader) ([]*Event, error) { + rawEvents, err := readTrace(r) + if err != nil { + return nil, err + } + events, err := parseEvents(rawEvents) + if err != nil { + return nil, err + } + events, err = removeFutile(events) + if err != nil { + return nil, err + } + err = postProcessTrace(events) + if err != nil { + return nil, err + } + return events, nil +} + +// rawEvent is a helper type used during parsing. +type rawEvent struct { + off int + typ byte + args []uint64 +} + +// readTrace does wire-format parsing and verification. +// It does not care about specific event types and argument meaning. +func readTrace(r io.Reader) ([]rawEvent, error) { + // Read and validate trace header. + var buf [16]byte + off, err := r.Read(buf[:]) + if off != 16 || err != nil { + return nil, fmt.Errorf("failed to read header: read %v, err %v", off, err) + } + if bytes.Compare(buf[:], []byte("go 1.5 trace\x00\x00\x00\x00")) != 0 { + return nil, fmt.Errorf("not a trace file") + } + + // Read events. + var events []rawEvent + for { + // Read event type and number of arguments (1 byte). + off0 := off + n, err := r.Read(buf[:1]) + if err == io.EOF { + break + } + if err != nil || n != 1 { + return nil, fmt.Errorf("failed to read trace at offset 0x%x: n=%v err=%v", off0, n, err) + } + off += n + typ := buf[0] << 2 >> 2 + narg := buf[0] >> 6 + ev := rawEvent{typ: typ, off: off0} + if narg < 3 { + for i := 0; i < int(narg)+2; i++ { // sequence number and time stamp are present but not counted in narg + var v uint64 + v, off, err = readVal(r, off) + if err != nil { + return nil, err + } + ev.args = append(ev.args, v) + } + } else { + // If narg == 3, the first value is length of the event in bytes. + var v uint64 + v, off, err = readVal(r, off) + if err != nil { + return nil, err + } + evLen := v + off1 := off + for evLen > uint64(off-off1) { + v, off, err = readVal(r, off) + if err != nil { + return nil, err + } + ev.args = append(ev.args, v) + } + if evLen != uint64(off-off1) { + return nil, fmt.Errorf("event has wrong length at offset 0x%x: want %v, got %v", off0, evLen, off-off1) + } + } + events = append(events, ev) + } + return events, nil +} + +// Parse events transforms raw events into events. +// It does analyze and verify per-event-type arguments. +func parseEvents(rawEvents []rawEvent) (events []*Event, err error) { + var ticksPerSec, lastSeq, lastTs int64 + var lastG, timerGoid uint64 + var lastP int + lastGs := make(map[int]uint64) // last goroutine running on P + stacks := make(map[uint64][]*Frame) + for _, raw := range rawEvents { + if raw.typ == EvNone || raw.typ >= EvCount { + err = fmt.Errorf("unknown event type %v at offset 0x%x", raw.typ, raw.off) + return + } + desc := EventDescriptions[raw.typ] + if desc.Name == "" { + err = fmt.Errorf("missing description for event type %v", raw.typ) + return + } + if raw.typ != EvStack { + narg := len(desc.Args) + if desc.Stack { + narg++ + } + if raw.typ != EvBatch && raw.typ != EvFrequency && raw.typ != EvTimerGoroutine { + narg++ // sequence number + narg++ // timestamp + } + if len(raw.args) != narg { + err = fmt.Errorf("%v has wrong number of arguments at offset 0x%x: want %v, got %v", + desc.Name, raw.off, narg, len(raw.args)) + return + } + } + switch raw.typ { + case EvBatch: + lastGs[lastP] = lastG + lastP = int(raw.args[0]) + lastG = lastGs[lastP] + lastSeq = int64(raw.args[1]) + lastTs = int64(raw.args[2]) + case EvFrequency: + ticksPerSec = int64(raw.args[0]) + if ticksPerSec <= 0 { + // The most likely cause for this is tick skew on different CPUs. + // For example, solaris/amd64 seems to have wildly different + // ticks on different CPUs. + err = ErrTimeOrder + return + } + case EvTimerGoroutine: + timerGoid = raw.args[0] + case EvStack: + if len(raw.args) < 2 { + err = fmt.Errorf("EvStack has wrong number of arguments at offset 0x%x: want at least 2, got %v", + raw.off, len(raw.args)) + return + } + size := raw.args[1] + if size > 1000 { + err = fmt.Errorf("EvStack has bad number of frames at offset 0x%x: %v", + raw.off, size) + return + } + if uint64(len(raw.args)) != size+2 { + err = fmt.Errorf("EvStack has wrong number of arguments at offset 0x%x: want %v, got %v", + raw.off, size+2, len(raw.args)) + return + } + id := raw.args[0] + if id != 0 && size > 0 { + stk := make([]*Frame, size) + for i := 0; i < int(size); i++ { + stk[i] = &Frame{PC: raw.args[i+2]} + } + stacks[id] = stk + } + default: + e := &Event{Off: raw.off, Type: raw.typ, P: lastP, G: lastG} + e.Seq = lastSeq + int64(raw.args[0]) + e.Ts = lastTs + int64(raw.args[1]) + lastSeq = e.Seq + lastTs = e.Ts + for i := range desc.Args { + e.Args[i] = raw.args[i+2] + } + if desc.Stack { + e.StkID = raw.args[len(desc.Args)+2] + } + switch raw.typ { + case EvGoStart: + lastG = e.Args[0] + e.G = lastG + case EvGCStart, EvGCDone, EvGCScanStart, EvGCScanDone: + e.G = 0 + case EvGoEnd, EvGoStop, EvGoSched, EvGoPreempt, + EvGoSleep, EvGoBlock, EvGoBlockSend, EvGoBlockRecv, + EvGoBlockSelect, EvGoBlockSync, EvGoBlockCond, EvGoBlockNet, + EvGoSysBlock: + lastG = 0 + case EvGoSysExit: + // EvGoSysExit emission is delayed until the thread has a P. + // Give it the real sequence number and time stamp. + e.Seq = int64(e.Args[1]) + if e.Args[2] != 0 { + e.Ts = int64(e.Args[2]) + } + } + events = append(events, e) + } + } + if len(events) == 0 { + err = fmt.Errorf("trace is empty") + return + } + + // Attach stack traces. + for _, ev := range events { + if ev.StkID != 0 { + ev.Stk = stacks[ev.StkID] + } + } + + // Sort by sequence number and translate cpu ticks to real time. + sort.Sort(eventList(events)) + if ticksPerSec == 0 { + err = fmt.Errorf("no EvFrequency event") + return + } + minTs := events[0].Ts + for _, ev := range events { + ev.Ts = (ev.Ts - minTs) * 1e9 / ticksPerSec + // Move timers and syscalls to separate fake Ps. + if timerGoid != 0 && ev.G == timerGoid && ev.Type == EvGoUnblock { + ev.P = TimerP + } + if ev.Type == EvGoSysExit { + ev.P = SyscallP + ev.G = ev.Args[0] + } + } + + return +} + +// removeFutile removes all constituents of futile wakeups (block, unblock, start). +// For example, a goroutine was unblocked on a mutex, but another goroutine got +// ahead and acquired the mutex before the first goroutine is scheduled, +// so the first goroutine has to block again. Such wakeups happen on buffered +// channels and sync.Mutex, but are generally not interesting for end user. +func removeFutile(events []*Event) ([]*Event, error) { + // Two non-trivial aspects: + // 1. A goroutine can be preempted during a futile wakeup and migrate to another P. + // We want to remove all of that. + // 2. Tracing can start in the middle of a futile wakeup. + // That is, we can see a futile wakeup event w/o the actual wakeup before it. + // postProcessTrace runs after us and ensures that we leave the trace in a consistent state. + + // Phase 1: determine futile wakeup sequences. + type G struct { + futile bool + wakeup []*Event // wakeup sequence (subject for removal) + } + gs := make(map[uint64]G) + futile := make(map[*Event]bool) + for _, ev := range events { + switch ev.Type { + case EvGoUnblock: + g := gs[ev.Args[0]] + g.wakeup = []*Event{ev} + gs[ev.Args[0]] = g + case EvGoStart, EvGoPreempt, EvFutileWakeup: + g := gs[ev.G] + g.wakeup = append(g.wakeup, ev) + if ev.Type == EvFutileWakeup { + g.futile = true + } + gs[ev.G] = g + case EvGoBlock, EvGoBlockSend, EvGoBlockRecv, EvGoBlockSelect, EvGoBlockSync, EvGoBlockCond: + g := gs[ev.G] + if g.futile { + futile[ev] = true + for _, ev1 := range g.wakeup { + futile[ev1] = true + } + } + delete(gs, ev.G) + } + } + + // Phase 2: remove futile wakeup sequences. + newEvents := events[:0] // overwrite the original slice + for _, ev := range events { + if !futile[ev] { + newEvents = append(newEvents, ev) + } + } + return newEvents, nil +} + +// ErrTimeOrder is returned by Parse when the trace contains +// time stamps that do not respect actual event ordering. +var ErrTimeOrder = fmt.Errorf("time stamps out of order") + +// postProcessTrace does inter-event verification and information restoration. +// The resulting trace is guaranteed to be consistent +// (for example, a P does not run two Gs at the same time, or a G is indeed +// blocked before an unblock event). +func postProcessTrace(events []*Event) error { + const ( + gDead = iota + gRunnable + gRunning + gWaiting + ) + type gdesc struct { + state int + ev *Event + evStart *Event + evCreate *Event + } + type pdesc struct { + running bool + g uint64 + evScan *Event + evSweep *Event + } + + gs := make(map[uint64]gdesc) + ps := make(map[int]pdesc) + gs[0] = gdesc{state: gRunning} + var evGC *Event + + checkRunning := func(p pdesc, g gdesc, ev *Event, allowG0 bool) error { + name := EventDescriptions[ev.Type].Name + if g.state != gRunning { + return fmt.Errorf("g %v is not running while %v (offset %v, time %v)", ev.G, name, ev.Off, ev.Ts) + } + if p.g != ev.G { + return fmt.Errorf("p %v is not running g %v while %v (offset %v, time %v)", ev.P, ev.G, name, ev.Off, ev.Ts) + } + if !allowG0 && ev.G == 0 { + return fmt.Errorf("g 0 did %v (offset %v, time %v)", EventDescriptions[ev.Type].Name, ev.Off, ev.Ts) + } + return nil + } + + for _, ev := range events { + g := gs[ev.G] + p := ps[ev.P] + + switch ev.Type { + case EvProcStart: + if p.running { + return fmt.Errorf("p %v is running before start (offset %v, time %v)", ev.P, ev.Off, ev.Ts) + } + p.running = true + case EvProcStop: + if !p.running { + return fmt.Errorf("p %v is not running before stop (offset %v, time %v)", ev.P, ev.Off, ev.Ts) + } + if p.g != 0 { + return fmt.Errorf("p %v is running a goroutine %v during stop (offset %v, time %v)", ev.P, p.g, ev.Off, ev.Ts) + } + p.running = false + case EvGCStart: + if evGC != nil { + return fmt.Errorf("previous GC is not ended before a new one (offset %v, time %v)", ev.Off, ev.Ts) + } + evGC = ev + case EvGCDone: + if evGC == nil { + return fmt.Errorf("bogus GC end (offset %v, time %v)", ev.Off, ev.Ts) + } + evGC.Link = ev + evGC = nil + case EvGCScanStart: + if p.evScan != nil { + return fmt.Errorf("previous scanning is not ended before a new one (offset %v, time %v)", ev.Off, ev.Ts) + } + p.evScan = ev + case EvGCScanDone: + if p.evScan == nil { + return fmt.Errorf("bogus scanning end (offset %v, time %v)", ev.Off, ev.Ts) + } + p.evScan.Link = ev + p.evScan = nil + case EvGCSweepStart: + if p.evSweep != nil { + return fmt.Errorf("previous sweeping is not ended before a new one (offset %v, time %v)", ev.Off, ev.Ts) + } + p.evSweep = ev + case EvGCSweepDone: + if p.evSweep == nil { + return fmt.Errorf("bogus sweeping end (offset %v, time %v)", ev.Off, ev.Ts) + } + p.evSweep.Link = ev + p.evSweep = nil + case EvGoWaiting: + g1 := gs[ev.Args[0]] + if g1.state != gRunnable { + return fmt.Errorf("g %v is not runnable before EvGoWaiting (offset %v, time %v)", ev.Args[0], ev.Off, ev.Ts) + } + g1.state = gWaiting + gs[ev.Args[0]] = g1 + case EvGoInSyscall: + g1 := gs[ev.Args[0]] + if g1.state != gRunnable { + return fmt.Errorf("g %v is not runnable before EvGoInSyscall (offset %v, time %v)", ev.Args[0], ev.Off, ev.Ts) + } + g1.state = gWaiting + gs[ev.Args[0]] = g1 + case EvGoCreate: + if err := checkRunning(p, g, ev, true); err != nil { + return err + } + if _, ok := gs[ev.Args[0]]; ok { + return fmt.Errorf("g %v already exists (offset %v, time %v)", ev.Args[0], ev.Off, ev.Ts) + } + gs[ev.Args[0]] = gdesc{state: gRunnable, ev: ev, evCreate: ev} + case EvGoStart: + if g.state != gRunnable { + return fmt.Errorf("g %v is not runnable before start (offset %v, time %v)", ev.G, ev.Off, ev.Ts) + } + if p.g != 0 { + return fmt.Errorf("p %v is already running g %v while start g %v (offset %v, time %v)", ev.P, p.g, ev.G, ev.Off, ev.Ts) + } + g.state = gRunning + g.evStart = ev + p.g = ev.G + if g.evCreate != nil { + // +1 because symbolizer expects return pc. + ev.Stk = []*Frame{&Frame{PC: g.evCreate.Args[1] + 1}} + g.evCreate = nil + } + + if g.ev != nil { + g.ev.Link = ev + g.ev = nil + } + case EvGoEnd, EvGoStop: + if err := checkRunning(p, g, ev, false); err != nil { + return err + } + g.evStart.Link = ev + g.evStart = nil + g.state = gDead + p.g = 0 + case EvGoSched, EvGoPreempt: + if err := checkRunning(p, g, ev, false); err != nil { + return err + } + g.state = gRunnable + g.evStart.Link = ev + g.evStart = nil + p.g = 0 + g.ev = ev + case EvGoUnblock: + if g.state != gRunning { + return fmt.Errorf("g %v is not running while unpark (offset %v, time %v)", ev.G, ev.Off, ev.Ts) + } + if ev.P != TimerP && p.g != ev.G { + return fmt.Errorf("p %v is not running g %v while unpark (offset %v, time %v)", ev.P, ev.G, ev.Off, ev.Ts) + } + g1 := gs[ev.Args[0]] + if g1.state != gWaiting { + return fmt.Errorf("g %v is not waiting before unpark (offset %v, time %v)", ev.Args[0], ev.Off, ev.Ts) + } + if g1.ev != nil && g1.ev.Type == EvGoBlockNet && ev.P != TimerP { + ev.P = NetpollP + } + if g1.ev != nil { + g1.ev.Link = ev + } + g1.state = gRunnable + g1.ev = ev + gs[ev.Args[0]] = g1 + case EvGoSysCall: + if err := checkRunning(p, g, ev, false); err != nil { + return err + } + g.ev = ev + case EvGoSysBlock: + if err := checkRunning(p, g, ev, false); err != nil { + return err + } + g.state = gWaiting + g.evStart.Link = ev + g.evStart = nil + p.g = 0 + case EvGoSysExit: + if g.state != gWaiting { + return fmt.Errorf("g %v is not waiting during syscall exit (offset %v, time %v)", ev.G, ev.Off, ev.Ts) + } + if g.ev != nil && g.ev.Type == EvGoSysCall { + g.ev.Link = ev + } + g.state = gRunnable + g.ev = ev + case EvGoSleep, EvGoBlock, EvGoBlockSend, EvGoBlockRecv, + EvGoBlockSelect, EvGoBlockSync, EvGoBlockCond, EvGoBlockNet: + if err := checkRunning(p, g, ev, false); err != nil { + return err + } + g.state = gWaiting + g.ev = ev + g.evStart.Link = ev + g.evStart = nil + p.g = 0 + } + + gs[ev.G] = g + ps[ev.P] = p + } + + // TODO(dvyukov): restore stacks for EvGoStart events. + // TODO(dvyukov): test that all EvGoStart events has non-nil Link. + + // Last, after all the other consistency checks, + // make sure time stamps respect sequence numbers. + // The tests will skip (not fail) the test case if they see this error, + // so check everything else that could possibly be wrong first. + lastTs := int64(0) + for _, ev := range events { + if ev.Ts < lastTs { + return ErrTimeOrder + } + lastTs = ev.Ts + } + + return nil +} + +// symbolizeTrace attaches func/file/line info to stack traces. +func Symbolize(events []*Event, bin string) error { + // First, collect and dedup all pcs. + pcs := make(map[uint64]*Frame) + for _, ev := range events { + for _, f := range ev.Stk { + pcs[f.PC] = nil + } + } + + // Start addr2line. + cmd := exec.Command("go", "tool", "addr2line", bin) + in, err := cmd.StdinPipe() + if err != nil { + return fmt.Errorf("failed to pipe addr2line stdin: %v", err) + } + cmd.Stderr = os.Stderr + out, err := cmd.StdoutPipe() + if err != nil { + return fmt.Errorf("failed to pipe addr2line stdout: %v", err) + } + err = cmd.Start() + if err != nil { + return fmt.Errorf("failed to start addr2line: %v", err) + } + outb := bufio.NewReader(out) + + // Write all pcs to addr2line. + // Need to copy pcs to an array, because map iteration order is non-deterministic. + var pcArray []uint64 + for pc := range pcs { + pcArray = append(pcArray, pc) + _, err := fmt.Fprintf(in, "0x%x\n", pc-1) + if err != nil { + return fmt.Errorf("failed to write to addr2line: %v", err) + } + } + in.Close() + + // Read in answers. + for _, pc := range pcArray { + fn, err := outb.ReadString('\n') + if err != nil { + return fmt.Errorf("failed to read from addr2line: %v", err) + } + file, err := outb.ReadString('\n') + if err != nil { + return fmt.Errorf("failed to read from addr2line: %v", err) + } + f := &Frame{PC: pc} + f.Fn = fn[:len(fn)-1] + f.File = file[:len(file)-1] + if colon := strings.LastIndex(f.File, ":"); colon != -1 { + ln, err := strconv.Atoi(f.File[colon+1:]) + if err == nil { + f.File = f.File[:colon] + f.Line = ln + } + } + pcs[pc] = f + } + cmd.Wait() + + // Replace frames in events array. + for _, ev := range events { + for i, f := range ev.Stk { + ev.Stk[i] = pcs[f.PC] + } + } + + return nil +} + +// readVal reads unsigned base-128 value from r. +func readVal(r io.Reader, off0 int) (v uint64, off int, err error) { + off = off0 + for i := 0; i < 10; i++ { + var buf [1]byte + var n int + n, err = r.Read(buf[:]) + if err != nil || n != 1 { + return 0, 0, fmt.Errorf("failed to read trace at offset %d: read %v, error %v", off0, n, err) + } + off++ + v |= uint64(buf[0]&0x7f) << (uint(i) * 7) + if buf[0]&0x80 == 0 { + return + } + } + return 0, 0, fmt.Errorf("bad value at offset 0x%x", off0) +} + +type eventList []*Event + +func (l eventList) Len() int { + return len(l) +} + +func (l eventList) Less(i, j int) bool { + return l[i].Seq < l[j].Seq +} + +func (l eventList) Swap(i, j int) { + l[i], l[j] = l[j], l[i] +} + +// Print dumps events to stdout. For debugging. +func Print(events []*Event) { + for _, ev := range events { + desc := EventDescriptions[ev.Type] + fmt.Printf("%v %v p=%v g=%v off=%v", ev.Ts, desc.Name, ev.P, ev.G, ev.Off) + for i, a := range desc.Args { + fmt.Printf(" %v=%v", a, ev.Args[i]) + } + fmt.Printf("\n") + } +} + +// Event types in the trace. +// Verbatim copy from src/runtime/trace.go. +const ( + EvNone = 0 // unused + EvBatch = 1 // start of per-P batch of events [pid, timestamp] + EvFrequency = 2 // contains tracer timer frequency [frequency (ticks per second)] + EvStack = 3 // stack [stack id, number of PCs, array of PCs] + EvGomaxprocs = 4 // current value of GOMAXPROCS [timestamp, GOMAXPROCS, stack id] + EvProcStart = 5 // start of P [timestamp, thread id] + EvProcStop = 6 // stop of P [timestamp] + EvGCStart = 7 // GC start [timestamp, stack id] + EvGCDone = 8 // GC done [timestamp] + EvGCScanStart = 9 // GC scan start [timestamp] + EvGCScanDone = 10 // GC scan done [timestamp] + EvGCSweepStart = 11 // GC sweep start [timestamp, stack id] + EvGCSweepDone = 12 // GC sweep done [timestamp] + EvGoCreate = 13 // goroutine creation [timestamp, new goroutine id, start PC, stack id] + EvGoStart = 14 // goroutine starts running [timestamp, goroutine id] + EvGoEnd = 15 // goroutine ends [timestamp] + EvGoStop = 16 // goroutine stops (like in select{}) [timestamp, stack] + EvGoSched = 17 // goroutine calls Gosched [timestamp, stack] + EvGoPreempt = 18 // goroutine is preempted [timestamp, stack] + EvGoSleep = 19 // goroutine calls Sleep [timestamp, stack] + EvGoBlock = 20 // goroutine blocks [timestamp, stack] + EvGoUnblock = 21 // goroutine is unblocked [timestamp, goroutine id, stack] + EvGoBlockSend = 22 // goroutine blocks on chan send [timestamp, stack] + EvGoBlockRecv = 23 // goroutine blocks on chan recv [timestamp, stack] + EvGoBlockSelect = 24 // goroutine blocks on select [timestamp, stack] + EvGoBlockSync = 25 // goroutine blocks on Mutex/RWMutex [timestamp, stack] + EvGoBlockCond = 26 // goroutine blocks on Cond [timestamp, stack] + EvGoBlockNet = 27 // goroutine blocks on network [timestamp, stack] + EvGoSysCall = 28 // syscall enter [timestamp, stack] + EvGoSysExit = 29 // syscall exit [timestamp, goroutine id, real timestamp] + EvGoSysBlock = 30 // syscall blocks [timestamp] + EvGoWaiting = 31 // denotes that goroutine is blocked when tracing starts [goroutine id] + EvGoInSyscall = 32 // denotes that goroutine is in syscall when tracing starts [goroutine id] + EvHeapAlloc = 33 // memstats.heap_alloc change [timestamp, heap_alloc] + EvNextGC = 34 // memstats.next_gc change [timestamp, next_gc] + EvTimerGoroutine = 35 // denotes timer goroutine [timer goroutine id] + EvFutileWakeup = 36 // denotes that the previous wakeup of this goroutine was futile [timestamp] + EvCount = 37 +) + +var EventDescriptions = [EvCount]struct { + Name string + Stack bool + Args []string +}{ + EvNone: {"None", false, []string{}}, + EvBatch: {"Batch", false, []string{"p", "seq", "ticks"}}, + EvFrequency: {"Frequency", false, []string{"freq", "unused"}}, + EvStack: {"Stack", false, []string{"id", "siz"}}, + EvGomaxprocs: {"Gomaxprocs", true, []string{"procs"}}, + EvProcStart: {"ProcStart", false, []string{"thread"}}, + EvProcStop: {"ProcStop", false, []string{}}, + EvGCStart: {"GCStart", true, []string{}}, + EvGCDone: {"GCDone", false, []string{}}, + EvGCScanStart: {"GCScanStart", false, []string{}}, + EvGCScanDone: {"GCScanDone", false, []string{}}, + EvGCSweepStart: {"GCSweepStart", true, []string{}}, + EvGCSweepDone: {"GCSweepDone", false, []string{}}, + EvGoCreate: {"GoCreate", true, []string{"g", "pc"}}, + EvGoStart: {"GoStart", false, []string{"g"}}, + EvGoEnd: {"GoEnd", false, []string{}}, + EvGoStop: {"GoStop", true, []string{}}, + EvGoSched: {"GoSched", true, []string{}}, + EvGoPreempt: {"GoPreempt", true, []string{}}, + EvGoSleep: {"GoSleep", true, []string{}}, + EvGoBlock: {"GoBlock", true, []string{}}, + EvGoUnblock: {"GoUnblock", true, []string{"g"}}, + EvGoBlockSend: {"GoBlockSend", true, []string{}}, + EvGoBlockRecv: {"GoBlockRecv", true, []string{}}, + EvGoBlockSelect: {"GoBlockSelect", true, []string{}}, + EvGoBlockSync: {"GoBlockSync", true, []string{}}, + EvGoBlockCond: {"GoBlockCond", true, []string{}}, + EvGoBlockNet: {"GoBlockNet", true, []string{}}, + EvGoSysCall: {"GoSysCall", true, []string{}}, + EvGoSysExit: {"GoSysExit", false, []string{"g", "seq", "ts"}}, + EvGoSysBlock: {"GoSysBlock", false, []string{}}, + EvGoWaiting: {"GoWaiting", false, []string{"g"}}, + EvGoInSyscall: {"GoInSyscall", false, []string{"g"}}, + EvHeapAlloc: {"HeapAlloc", false, []string{"mem"}}, + EvNextGC: {"NextGC", false, []string{"mem"}}, + EvTimerGoroutine: {"TimerGoroutine", false, []string{"g", "unused"}}, + EvFutileWakeup: {"FutileWakeup", false, []string{}}, +} diff --git a/libgo/go/internal/trace/parser_test.go b/libgo/go/internal/trace/parser_test.go new file mode 100644 index 00000000000..0eeb3e600e4 --- /dev/null +++ b/libgo/go/internal/trace/parser_test.go @@ -0,0 +1,30 @@ +// Copyright 2015 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 trace + +import ( + "strings" + "testing" +) + +func TestCorruptedInputs(t *testing.T) { + // These inputs crashed parser previously. + tests := []string{ + "gotrace\x00\x020", + "gotrace\x00Q00\x020", + "gotrace\x00T00\x020", + "gotrace\x00\xc3\x0200", + "go 1.5 trace\x00\x00\x00\x00\x020", + "go 1.5 trace\x00\x00\x00\x00Q00\x020", + "go 1.5 trace\x00\x00\x00\x00T00\x020", + "go 1.5 trace\x00\x00\x00\x00\xc3\x0200", + } + for _, data := range tests { + events, err := Parse(strings.NewReader(data)) + if err == nil || events != nil { + t.Fatalf("no error on input: %q\n", t) + } + } +} diff --git a/libgo/go/io/io.go b/libgo/go/io/io.go index 7507a84929f..8851eaf00ab 100644 --- a/libgo/go/io/io.go +++ b/libgo/go/io/io.go @@ -54,7 +54,7 @@ var ErrNoProgress = errors.New("multiple Read calls return no data or error") // An instance of this general case is that a Reader returning // a non-zero number of bytes at the end of the input stream may // return either err == EOF or err == nil. The next Read should -// return 0, EOF regardless. +// return 0, EOF. // // Callers should always process the n > 0 bytes returned before // considering the error err. Doing so correctly handles I/O errors @@ -273,8 +273,8 @@ type stringWriter interface { WriteString(s string) (n int, err error) } -// WriteString writes the contents of the string s to w, which accepts an array of bytes. -// If w already implements a WriteString method, it is invoked directly. +// WriteString writes the contents of the string s to w, which accepts a slice of bytes. +// If w implements a WriteString method, it is invoked directly. func WriteString(w Writer, s string) (n int, err error) { if sw, ok := w.(stringWriter); ok { return sw.WriteString(s) @@ -348,6 +348,23 @@ func CopyN(dst Writer, src Reader, n int64) (written int64, err error) { // Otherwise, if dst implements the ReaderFrom interface, // the copy is implemented by calling dst.ReadFrom(src). func Copy(dst Writer, src Reader) (written int64, err error) { + return copyBuffer(dst, src, nil) +} + +// CopyBuffer is identical to Copy except that it stages through the +// provided buffer (if one is required) rather than allocating a +// temporary one. If buf is nil, one is allocated; otherwise if it has +// zero length, CopyBuffer panics. +func CopyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error) { + if buf != nil && len(buf) == 0 { + panic("empty buffer in io.CopyBuffer") + } + return copyBuffer(dst, src, buf) +} + +// copyBuffer is the actual implementation of Copy and CopyBuffer. +// if buf is nil, one is allocated. +func copyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error) { // If the reader has a WriteTo method, use it to do the copy. // Avoids an allocation and a copy. if wt, ok := src.(WriterTo); ok { @@ -357,7 +374,9 @@ func Copy(dst Writer, src Reader) (written int64, err error) { if rt, ok := dst.(ReaderFrom); ok { return rt.ReadFrom(src) } - buf := make([]byte, 32*1024) + if buf == nil { + buf = make([]byte, 32*1024) + } for { nr, er := src.Read(buf) if nr > 0 { diff --git a/libgo/go/io/io_test.go b/libgo/go/io/io_test.go index 57db1fbf0bf..e892574b0b5 100644 --- a/libgo/go/io/io_test.go +++ b/libgo/go/io/io_test.go @@ -20,7 +20,7 @@ type Buffer struct { WriterTo // conflicts with and hides bytes.Buffer's WriterTo. } -// Simple tests, primarily to verify the ReadFrom and WriteTo callouts inside Copy and CopyN. +// Simple tests, primarily to verify the ReadFrom and WriteTo callouts inside Copy, CopyBuffer and CopyN. func TestCopy(t *testing.T) { rb := new(Buffer) @@ -32,6 +32,26 @@ func TestCopy(t *testing.T) { } } +func TestCopyBuffer(t *testing.T) { + rb := new(Buffer) + wb := new(Buffer) + rb.WriteString("hello, world.") + CopyBuffer(wb, rb, make([]byte, 1)) // Tiny buffer to keep it honest. + if wb.String() != "hello, world." { + t.Errorf("CopyBuffer did not work properly") + } +} + +func TestCopyBufferNil(t *testing.T) { + rb := new(Buffer) + wb := new(Buffer) + rb.WriteString("hello, world.") + CopyBuffer(wb, rb, nil) // Should allocate a buffer. + if wb.String() != "hello, world." { + t.Errorf("CopyBuffer did not work properly") + } +} + func TestCopyReadFrom(t *testing.T) { rb := new(Buffer) wb := new(bytes.Buffer) // implements ReadFrom. @@ -78,6 +98,34 @@ func TestCopyPriority(t *testing.T) { } } +type zeroErrReader struct { + err error +} + +func (r zeroErrReader) Read(p []byte) (int, error) { + return copy(p, []byte{0}), r.err +} + +type errWriter struct { + err error +} + +func (w errWriter) Write([]byte) (int, error) { + return 0, w.err +} + +// In case a Read results in an error with non-zero bytes read, and +// the subsequent Write also results in an error, the error from Write +// is returned, as it is the one that prevented progressing further. +func TestCopyReadErrWriteErr(t *testing.T) { + er, ew := errors.New("readError"), errors.New("writeError") + r, w := zeroErrReader{err: er}, errWriter{err: ew} + n, err := Copy(w, r) + if n != 0 || err != ew { + t.Errorf("Copy(zeroErrReader, errWriter) = %d, %v; want 0, writeError", n, err) + } +} + func TestCopyN(t *testing.T) { rb := new(Buffer) wb := new(Buffer) diff --git a/libgo/go/io/ioutil/tempfile.go b/libgo/go/io/ioutil/tempfile.go index 4a06e9756fb..61d4a7ad37d 100644 --- a/libgo/go/io/ioutil/tempfile.go +++ b/libgo/go/io/ioutil/tempfile.go @@ -55,7 +55,9 @@ func TempFile(dir, prefix string) (f *os.File, err error) { f, err = os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600) if os.IsExist(err) { if nconflict++; nconflict > 10 { + randmu.Lock() rand = reseed() + randmu.Unlock() } continue } @@ -82,7 +84,9 @@ func TempDir(dir, prefix string) (name string, err error) { err = os.Mkdir(try, 0700) if os.IsExist(err) { if nconflict++; nconflict > 10 { + randmu.Lock() rand = reseed() + randmu.Unlock() } continue } diff --git a/libgo/go/io/pipe.go b/libgo/go/io/pipe.go index f65354a7f25..179515e78d3 100644 --- a/libgo/go/io/pipe.go +++ b/libgo/go/io/pipe.go @@ -168,7 +168,10 @@ func (w *PipeWriter) Close() error { } // CloseWithError closes the writer; subsequent reads from the -// read half of the pipe will return no bytes and the error err. +// read half of the pipe will return no bytes and the error err, +// or EOF if err is nil. +// +// CloseWithError always returns nil. func (w *PipeWriter) CloseWithError(err error) error { w.p.wclose(err) return nil diff --git a/libgo/go/log/log.go b/libgo/go/log/log.go index d37e4375e4c..4cfe5503006 100644 --- a/libgo/go/log/log.go +++ b/libgo/go/log/log.go @@ -23,15 +23,21 @@ import ( // These flags define which text to prefix to each log entry generated by the Logger. const ( - // Bits or'ed together to control what's printed. There is no control over the - // order they appear (the order listed here) or the format they present (as - // described in the comments). A colon appears after these items: + // Bits or'ed together to control what's printed. + // There is no control over the order they appear (the order listed + // here) or the format they present (as described in the comments). + // The prefix is followed by a colon only when Llongfile or Lshortfile + // is specified. + // For example, flags Ldate | Ltime (or LstdFlags) produce, + // 2009/01/23 01:23:23 message + // while flags Ldate | Ltime | Lmicroseconds | Llongfile produce, // 2009/01/23 01:23:23.123123 /a/b/c/d.go:23: message - Ldate = 1 << iota // the date: 2009/01/23 - Ltime // the time: 01:23:23 + Ldate = 1 << iota // the date in the local time zone: 2009/01/23 + Ltime // the time in the local time zone: 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 Lshortfile // final file name element and line number: d.go:23. overrides Llongfile + LUTC // if Ldate or Ltime is set, use UTC rather than the local time zone LstdFlags = Ldate | Ltime // initial values for the standard logger ) @@ -55,30 +61,37 @@ func New(out io.Writer, prefix string, flag int) *Logger { return &Logger{out: out, prefix: prefix, flag: flag} } +// SetOutput sets the output destination for the logger. +func (l *Logger) SetOutput(w io.Writer) { + l.mu.Lock() + defer l.mu.Unlock() + l.out = w +} + 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 *[]byte, i int, wid int) { - var u uint = uint(i) - if u == 0 && wid <= 1 { - *buf = append(*buf, '0') - return - } - // Assemble decimal in reverse order. - var b [32]byte - bp := len(b) - for ; u > 0 || wid > 0; u /= 10 { - bp-- + var b [20]byte + bp := len(b) - 1 + for i >= 10 || wid > 1 { wid-- - b[bp] = byte(u%10) + '0' + q := i / 10 + b[bp] = byte('0' + i - q*10) + bp-- + i = q } + // i < 10 + b[bp] = byte('0' + i) *buf = append(*buf, b[bp:]...) } func (l *Logger) formatHeader(buf *[]byte, t time.Time, file string, line int) { *buf = append(*buf, l.prefix...) + if l.flag&LUTC != 0 { + t = t.UTC() + } if l.flag&(Ldate|Ltime|Lmicroseconds) != 0 { if l.flag&Ldate != 0 { year, month, day := t.Date() @@ -147,7 +160,7 @@ func (l *Logger) Output(calldepth int, s string) error { l.buf = l.buf[:0] l.formatHeader(&l.buf, now, file, line) l.buf = append(l.buf, s...) - if len(s) > 0 && s[len(s)-1] != '\n' { + if len(s) == 0 || s[len(s)-1] != '\n' { l.buf = append(l.buf, '\n') } _, err := l.out.Write(l.buf) @@ -320,3 +333,14 @@ func Panicln(v ...interface{}) { std.Output(2, s) panic(s) } + +// Output writes the output for a logging event. The string s contains +// the text to print after the prefix specified by the flags of the +// Logger. A newline is appended if the last character of s is not +// already a newline. Calldepth is the count of the number of +// frames to skip when computing the file name and line number +// if Llongfile or Lshortfile is set; a value of 1 will print the details +// for the caller of Output. +func Output(calldepth int, s string) error { + return std.Output(calldepth+1, s) // +1 for this frame. +} diff --git a/libgo/go/log/log_test.go b/libgo/go/log/log_test.go index 158c3d93c7e..dd16c9d3e18 100644 --- a/libgo/go/log/log_test.go +++ b/libgo/go/log/log_test.go @@ -8,16 +8,19 @@ package log import ( "bytes" + "fmt" "os" "regexp" + "strings" "testing" + "time" ) const ( Rdate = `[0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9]` Rtime = `[0-9][0-9]:[0-9][0-9]:[0-9][0-9]` Rmicroseconds = `\.[0-9][0-9][0-9][0-9][0-9][0-9]` - Rline = `(54|56):` // must update if the calls to l.Printf / l.Print below move + Rline = `(57|59):` // must update if the calls to l.Printf / l.Print below move Rlongfile = `.*/[A-Za-z0-9_\-]+\.go:` + Rline Rshortfile = `[A-Za-z0-9_\-]+\.go:` + Rline ) @@ -117,3 +120,65 @@ func TestFlagAndPrefixSetting(t *testing.T) { t.Error("message did not match pattern") } } + +func TestUTCFlag(t *testing.T) { + var b bytes.Buffer + l := New(&b, "Test:", LstdFlags) + l.SetFlags(Ldate | Ltime | LUTC) + // Verify a log message looks right in the right time zone. Quantize to the second only. + now := time.Now().UTC() + l.Print("hello") + want := fmt.Sprintf("Test:%d/%.2d/%.2d %.2d:%.2d:%.2d hello\n", + now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second()) + got := b.String() + if got == want { + return + } + // It's possible we crossed a second boundary between getting now and logging, + // so add a second and try again. This should very nearly always work. + now = now.Add(time.Second) + want = fmt.Sprintf("Test:%d/%.2d/%.2d %.2d:%.2d:%.2d hello\n", + now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second()) + if got == want { + return + } + t.Errorf("got %q; want %q", got, want) +} + +func TestEmptyPrintCreatesLine(t *testing.T) { + var b bytes.Buffer + l := New(&b, "Header:", LstdFlags) + l.Print() + l.Println("non-empty") + output := b.String() + if n := strings.Count(output, "Header"); n != 2 { + t.Errorf("expected 2 headers, got %d", n) + } + if n := strings.Count(output, "\n"); n != 2 { + t.Errorf("expected 2 lines, got %d", n) + } +} + +func BenchmarkItoa(b *testing.B) { + dst := make([]byte, 0, 64) + for i := 0; i < b.N; i++ { + dst = dst[0:0] + itoa(&dst, 2015, 4) // year + itoa(&dst, 1, 2) // month + itoa(&dst, 30, 2) // day + itoa(&dst, 12, 2) // hour + itoa(&dst, 56, 2) // minute + itoa(&dst, 0, 2) // second + itoa(&dst, 987654, 6) // microsecond + } +} + +func BenchmarkPrintln(b *testing.B) { + const testString = "test" + var buf bytes.Buffer + l := New(&buf, "", LstdFlags) + for i := 0; i < b.N; i++ { + buf.Reset() + l.Println(testString) + } +} diff --git a/libgo/go/log/syslog/doc.go b/libgo/go/log/syslog/doc.go new file mode 100644 index 00000000000..54e76edb34b --- /dev/null +++ b/libgo/go/log/syslog/doc.go @@ -0,0 +1,18 @@ +// 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. It can send messages to the syslog daemon using UNIX +// domain sockets, UDP or TCP. +// +// Only one call to Dial is necessary. On write failures, +// the syslog client will attempt to reconnect to the server +// and write again. +package syslog + +// BUG(brainman): This package is not implemented on Windows yet. + +// BUG(akumar): This package is not implemented on Plan 9 yet. + +// BUG(minux): This package is not implemented on NaCl (Native Client) yet. diff --git a/libgo/go/log/syslog/syslog.go b/libgo/go/log/syslog/syslog.go index 5e095991626..4bf447626f2 100644 --- a/libgo/go/log/syslog/syslog.go +++ b/libgo/go/log/syslog/syslog.go @@ -4,13 +4,6 @@ // +build !windows,!nacl,!plan9 -// Package syslog provides a simple interface to the system log -// service. It can send messages to the syslog daemon using UNIX -// domain sockets, UDP or TCP. -// -// Only one call to Dial is necessary. On write failures, -// the syslog client will attempt to reconnect to the server -// and write again. package syslog import ( diff --git a/libgo/go/log/syslog/syslog_plan9.go b/libgo/go/log/syslog/syslog_plan9.go deleted file mode 100644 index 0c05f6f83c0..00000000000 --- a/libgo/go/log/syslog/syslog_plan9.go +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package syslog provides a simple interface to the system log service. -package syslog - -// BUG(akumar): This package is not implemented on Plan 9 yet. diff --git a/libgo/go/log/syslog/syslog_test.go b/libgo/go/log/syslog/syslog_test.go index 6a863fed312..85aec536abe 100644 --- a/libgo/go/log/syslog/syslog_test.go +++ b/libgo/go/log/syslog/syslog_test.go @@ -14,6 +14,7 @@ import ( "log" "net" "os" + "runtime" "sync" "testing" "time" @@ -120,6 +121,13 @@ func TestWithSimulated(t *testing.T) { msg := "Test 123" transport := []string{"unix", "unixgram", "udp", "tcp"} + if runtime.GOOS == "darwin" { + switch runtime.GOARCH { + case "arm", "arm64": + transport = []string{"udp", "tcp"} + } + } + for _, tr := range transport { done := make(chan string) addr, sock, srvWG := startServer(tr, "", done) @@ -142,6 +150,13 @@ func TestWithSimulated(t *testing.T) { } func TestFlap(t *testing.T) { + if runtime.GOOS == "darwin" { + switch runtime.GOARCH { + case "arm", "arm64": + t.Skipf("skipping on %s/%s", runtime.GOOS, runtime.GOARCH) + } + } + net := "unix" done := make(chan string) addr, sock, srvWG := startServer(net, "", done) @@ -306,9 +321,17 @@ func TestConcurrentReconnect(t *testing.T) { const N = 10 const M = 100 net := "unix" + if runtime.GOOS == "darwin" { + switch runtime.GOARCH { + case "arm", "arm64": + net = "tcp" + } + } done := make(chan string, N*M) addr, sock, srvWG := startServer(net, "", done) - defer os.Remove(addr) + if net == "unix" { + defer os.Remove(addr) + } // count all the messages arriving count := make(chan int) diff --git a/libgo/go/log/syslog/syslog_windows.go b/libgo/go/log/syslog/syslog_windows.go deleted file mode 100644 index 8d99e2e594d..00000000000 --- a/libgo/go/log/syslog/syslog_windows.go +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package 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/libgo/go/math/all_test.go b/libgo/go/math/all_test.go index 763efb2e647..e18e45e0202 100644 --- a/libgo/go/math/all_test.go +++ b/libgo/go/math/all_test.go @@ -946,16 +946,20 @@ var expSC = []float64{ var vfexpm1SC = []float64{ Inf(-1), + -710, Copysign(0, -1), 0, + 710, Inf(1), NaN(), } var expm1SC = []float64{ + -1, -1, Copysign(0, -1), 0, Inf(1), + Inf(1), NaN(), } @@ -991,6 +995,24 @@ var vffdimSC = [][2]float64{ {NaN(), Inf(1)}, {NaN(), NaN()}, } +var nan = Float64frombits(0xFFF8000000000000) // SSE2 DIVSD 0/0 +var vffdim2SC = [][2]float64{ + {Inf(-1), Inf(-1)}, + {Inf(-1), Inf(1)}, + {Inf(-1), nan}, + {Copysign(0, -1), Copysign(0, -1)}, + {Copysign(0, -1), 0}, + {0, Copysign(0, -1)}, + {0, 0}, + {Inf(1), Inf(-1)}, + {Inf(1), Inf(1)}, + {Inf(1), nan}, + {nan, Inf(-1)}, + {nan, Copysign(0, -1)}, + {nan, 0}, + {nan, Inf(1)}, + {nan, nan}, +} var fdimSC = []float64{ NaN(), 0, @@ -1708,8 +1730,10 @@ func tolerance(a, b, e float64) bool { d = -d } - if a != 0 { - e = e * a + // note: b is correct (expected) value, a is actual value. + // make error tolerance a fraction of b, not a. + if b != 0 { + e = e * b if e < 0 { e = -e } @@ -2015,6 +2039,11 @@ func TestDim(t *testing.T) { t.Errorf("Dim(%g, %g) = %g, want %g", vffdimSC[i][0], vffdimSC[i][1], f, fdimSC[i]) } } + for i := 0; i < len(vffdim2SC); i++ { + if f := Dim(vffdim2SC[i][0], vffdim2SC[i][1]); !alike(fdimSC[i], f) { + t.Errorf("Dim(%g, %g) = %g, want %g", vffdim2SC[i][0], vffdim2SC[i][1], f, fdimSC[i]) + } + } } func TestFloor(t *testing.T) { @@ -2041,6 +2070,11 @@ func TestMax(t *testing.T) { t.Errorf("Max(%g, %g) = %g, want %g", vffdimSC[i][0], vffdimSC[i][1], f, fmaxSC[i]) } } + for i := 0; i < len(vffdim2SC); i++ { + if f := Max(vffdim2SC[i][0], vffdim2SC[i][1]); !alike(fmaxSC[i], f) { + t.Errorf("Max(%g, %g) = %g, want %g", vffdim2SC[i][0], vffdim2SC[i][1], f, fmaxSC[i]) + } + } } func TestMin(t *testing.T) { @@ -2054,6 +2088,11 @@ func TestMin(t *testing.T) { t.Errorf("Min(%g, %g) = %g, want %g", vffdimSC[i][0], vffdimSC[i][1], f, fminSC[i]) } } + for i := 0; i < len(vffdim2SC); i++ { + if f := Min(vffdim2SC[i][0], vffdim2SC[i][1]); !alike(fminSC[i], f) { + t.Errorf("Min(%g, %g) = %g, want %g", vffdim2SC[i][0], vffdim2SC[i][1], f, fminSC[i]) + } + } } func TestMod(t *testing.T) { @@ -2606,7 +2645,7 @@ func TestLargeTan(t *testing.T) { // Check that math constants are accepted by compiler // and have right value (assumes strconv.ParseFloat works). -// http://code.google.com/p/go/issues/detail?id=201 +// https://golang.org/issue/201 type floatTest struct { val interface{} @@ -2944,15 +2983,56 @@ func BenchmarkSinh(b *testing.B) { } } +var Global float64 + func BenchmarkSqrt(b *testing.B) { + x, y := 0.0, 10.0 + for i := 0; i < b.N; i++ { + x += Sqrt(y) + } + Global = x +} + +func BenchmarkSqrtIndirect(b *testing.B) { + x, y := 0.0, 10.0 + f := Sqrt for i := 0; i < b.N; i++ { - Sqrt(10) + x += f(y) } + Global = x } func BenchmarkSqrtGo(b *testing.B) { + x, y := 0.0, 10.0 + for i := 0; i < b.N; i++ { + x += SqrtGo(y) + } + Global = x +} + +func isPrime(i int) bool { + // Yes, this is a dumb way to write this code, + // but calling Sqrt repeatedly in this way demonstrates + // the benefit of using a direct SQRT instruction on systems + // that have one, whereas the obvious loop seems not to + // demonstrate such a benefit. + for j := 2; float64(j) <= Sqrt(float64(i)); j++ { + if i%j == 0 { + return false + } + } + return true +} + +func BenchmarkSqrtPrime(b *testing.B) { + any := false for i := 0; i < b.N; i++ { - SqrtGo(10) + if isPrime(100003) { + any = true + } + } + if any { + Global = 1 } } diff --git a/libgo/go/math/big/accuracy_string.go b/libgo/go/math/big/accuracy_string.go new file mode 100644 index 00000000000..24ef7f10770 --- /dev/null +++ b/libgo/go/math/big/accuracy_string.go @@ -0,0 +1,17 @@ +// generated by stringer -type=Accuracy; DO NOT EDIT + +package big + +import "fmt" + +const _Accuracy_name = "BelowExactAbove" + +var _Accuracy_index = [...]uint8{0, 5, 10, 15} + +func (i Accuracy) String() string { + i -= -1 + if i < 0 || i+1 >= Accuracy(len(_Accuracy_index)) { + return fmt.Sprintf("Accuracy(%d)", i+-1) + } + return _Accuracy_name[_Accuracy_index[i]:_Accuracy_index[i+1]] +} diff --git a/libgo/go/math/big/arith.go b/libgo/go/math/big/arith.go index c5ff4252d50..d7ea8381e7c 100644 --- a/libgo/go/math/big/arith.go +++ b/libgo/go/math/big/arith.go @@ -52,8 +52,6 @@ func subWW_g(x, y, c Word) (z1, z0 Word) { } // z1<<_W + z0 = x*y -func mulWW(x, y Word) (z1, z0 Word) { return mulWW_g(x, y) } - // Adapted from Warren, Hacker's Delight, p. 132. func mulWW_g(x, y Word) (z1, z0 Word) { x0 := x & _M2 @@ -72,7 +70,7 @@ func mulWW_g(x, y Word) (z1, z0 Word) { // z1<<_W + z0 = x*y + c func mulAddWWW_g(x, y, c Word) (z1, z0 Word) { - z1, zz0 := mulWW(x, y) + z1, zz0 := mulWW_g(x, y) if z0 = zz0 + c; z0 < zz0 { z1++ } @@ -80,7 +78,6 @@ func mulAddWWW_g(x, y, c Word) (z1, z0 Word) { } // Length of x in bits. -func bitLen(x Word) (n int) { return bitLen_g(x) } func bitLen_g(x Word) (n int) { for ; x >= 0x8000; x >>= 16 { n += 16 @@ -110,21 +107,34 @@ func log2(x Word) int { return bitLen(x) - 1 } -// Number of leading zeros in x. -func leadingZeros(x Word) uint { +// nlz returns the number of leading zeros in x. +func nlz(x Word) uint { return uint(_W - bitLen(x)) } -// q = (u1<<_W + u0 - r)/y -func divWW(x1, x0, y Word) (q, r Word) { return divWW_g(x1, x0, y) } +// nlz64 returns the number of leading zeros in x. +func nlz64(x uint64) uint { + switch _W { + case 32: + w := x >> 32 + if w == 0 { + return 32 + nlz(Word(x)) + } + return nlz(Word(w)) + case 64: + return nlz(Word(x)) + } + panic("unreachable") +} +// q = (u1<<_W + u0 - r)/y // Adapted from Warren, Hacker's Delight, p. 152. func divWW_g(u1, u0, v Word) (q, r Word) { if u1 >= v { return 1<<_W - 1, 1<<_W - 1 } - s := leadingZeros(v) + s := nlz(v) v <<= s vn1 := v >> _W2 @@ -159,41 +169,85 @@ func divWW_g(u1, u0, v Word) (q, r Word) { return q1*_B2 + q0, (un21*_B2 + un0 - q0*v) >> s } -func addVV(z, x, y []Word) (c Word) { return addVV_g(z, x, y) } +// Keep for performance debugging. +// Using addWW_g is likely slower. +const use_addWW_g = false + +// The resulting carry c is either 0 or 1. func addVV_g(z, x, y []Word) (c Word) { - for i := range z { - c, z[i] = addWW_g(x[i], y[i], c) + if use_addWW_g { + for i := range z { + c, z[i] = addWW_g(x[i], y[i], c) + } + return + } + + for i, xi := range x[:len(z)] { + yi := y[i] + zi := xi + yi + c + z[i] = zi + // see "Hacker's Delight", section 2-12 (overflow detection) + c = (xi&yi | (xi|yi)&^zi) >> (_W - 1) } return } -func subVV(z, x, y []Word) (c Word) { return subVV_g(z, x, y) } +// The resulting carry c is either 0 or 1. func subVV_g(z, x, y []Word) (c Word) { - for i := range z { - c, z[i] = subWW_g(x[i], y[i], c) + if use_addWW_g { + for i := range z { + c, z[i] = subWW_g(x[i], y[i], c) + } + return + } + + for i, xi := range x[:len(z)] { + yi := y[i] + zi := xi - yi - c + z[i] = zi + // see "Hacker's Delight", section 2-12 (overflow detection) + c = (yi&^xi | (yi|^xi)&zi) >> (_W - 1) } return } -func addVW(z, x []Word, y Word) (c Word) { return addVW_g(z, x, y) } +// The resulting carry c is either 0 or 1. func addVW_g(z, x []Word, y Word) (c Word) { + if use_addWW_g { + c = y + for i := range z { + c, z[i] = addWW_g(x[i], c, 0) + } + return + } + c = y - for i := range z { - c, z[i] = addWW_g(x[i], c, 0) + for i, xi := range x[:len(z)] { + zi := xi + c + z[i] = zi + c = xi &^ zi >> (_W - 1) } return } -func subVW(z, x []Word, y Word) (c Word) { return subVW_g(z, x, y) } func subVW_g(z, x []Word, y Word) (c Word) { + if use_addWW_g { + c = y + for i := range z { + c, z[i] = subWW_g(x[i], c, 0) + } + return + } + c = y - for i := range z { - c, z[i] = subWW_g(x[i], c, 0) + for i, xi := range x[:len(z)] { + zi := xi - c + z[i] = zi + c = (zi &^ xi) >> (_W - 1) } return } -func shlVU(z, x []Word, s uint) (c Word) { return shlVU_g(z, x, s) } func shlVU_g(z, x []Word, s uint) (c Word) { if n := len(z); n > 0 { ŝ := _W - s @@ -209,7 +263,6 @@ func shlVU_g(z, x []Word, s uint) (c Word) { return } -func shrVU(z, x []Word, s uint) (c Word) { return shrVU_g(z, x, s) } func shrVU_g(z, x []Word, s uint) (c Word) { if n := len(z); n > 0 { ŝ := _W - s @@ -225,7 +278,6 @@ func shrVU_g(z, x []Word, s uint) (c Word) { return } -func mulAddVWW(z, x []Word, y, r Word) (c Word) { return mulAddVWW_g(z, x, y, r) } func mulAddVWW_g(z, x []Word, y, r Word) (c Word) { c = r for i := range z { @@ -234,7 +286,7 @@ func mulAddVWW_g(z, x []Word, y, r Word) (c Word) { return } -func addMulVVW(z, x []Word, y Word) (c Word) { return addMulVVW_g(z, x, y) } +// TODO(gri) Remove use of addWW_g here and then we can remove addWW_g and subWW_g. func addMulVVW_g(z, x []Word, y Word) (c Word) { for i := range z { z1, z0 := mulAddWWW_g(x[i], y, z[i]) @@ -244,7 +296,6 @@ func addMulVVW_g(z, x []Word, y Word) (c Word) { return } -func divWVW(z []Word, xn Word, x []Word, y Word) (r Word) { return divWVW_g(z, xn, x, y) } func divWVW_g(z []Word, xn Word, x []Word, y Word) (r Word) { r = xn for i := len(z) - 1; i >= 0; i-- { diff --git a/libgo/go/math/big/arith_decl.go b/libgo/go/math/big/arith_decl.go index 068cc8d9388..1707aa4e209 100644 --- a/libgo/go/math/big/arith_decl.go +++ b/libgo/go/math/big/arith_decl.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// +build !math_big_pure_go + package big // implemented in arith_$GOARCH.s diff --git a/libgo/go/math/big/arith_decl_pure.go b/libgo/go/math/big/arith_decl_pure.go new file mode 100644 index 00000000000..e760a3816b3 --- /dev/null +++ b/libgo/go/math/big/arith_decl_pure.go @@ -0,0 +1,55 @@ +// Copyright 2015 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 math_big_pure_go + +package big + +func mulWW(x, y Word) (z1, z0 Word) { + return mulWW_g(x, y) +} + +func divWW(x1, x0, y Word) (q, r Word) { + return divWW_g(x1, x0, y) +} + +func addVV(z, x, y []Word) (c Word) { + return addVV_g(z, x, y) +} + +func subVV(z, x, y []Word) (c Word) { + return subVV_g(z, x, y) +} + +func addVW(z, x []Word, y Word) (c Word) { + return addVW_g(z, x, y) +} + +func subVW(z, x []Word, y Word) (c Word) { + return subVW_g(z, x, y) +} + +func shlVU(z, x []Word, s uint) (c Word) { + return shlVU_g(z, x, s) +} + +func shrVU(z, x []Word, s uint) (c Word) { + return shrVU_g(z, x, s) +} + +func mulAddVWW(z, x []Word, y, r Word) (c Word) { + return mulAddVWW_g(z, x, y, r) +} + +func addMulVVW(z, x []Word, y Word) (c Word) { + return addMulVVW_g(z, x, y) +} + +func divWVW(z []Word, xn Word, x []Word, y Word) (r Word) { + return divWVW_g(z, xn, x, y) +} + +func bitLen(x Word) (n int) { + return bitLen_g(x) +} diff --git a/libgo/go/math/big/arith_test.go b/libgo/go/math/big/arith_test.go index 3615a659c3b..f46a494f175 100644 --- a/libgo/go/math/big/arith_test.go +++ b/libgo/go/math/big/arith_test.go @@ -155,6 +155,7 @@ var sumVW = []argVW{ {nat{1}, nat{1}, 0, 0}, {nat{0}, nat{_M}, 1, 1}, {nat{0, 0, 0, 0}, nat{_M, _M, _M, _M}, 1, 1}, + {nat{585}, nat{314}, 271, 0}, } var prodVW = []argVW{ @@ -254,7 +255,7 @@ func benchmarkFunVW(b *testing.B, f funVW, n int) { x := rndV(n) y := rndW() z := make([]Word, n) - b.SetBytes(int64(n * _W)) + b.SetBytes(int64(n * _S)) b.ResetTimer() for i := 0; i < b.N; i++ { f(z, x, y) diff --git a/libgo/go/math/big/bits_test.go b/libgo/go/math/big/bits_test.go new file mode 100644 index 00000000000..985b60bd4b7 --- /dev/null +++ b/libgo/go/math/big/bits_test.go @@ -0,0 +1,224 @@ +// Copyright 2015 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 Bits type used for testing Float operations +// via an independent (albeit slower) representations for floating-point +// numbers. + +package big + +import ( + "fmt" + "sort" + "testing" +) + +// A Bits value b represents a finite floating-point number x of the form +// +// x = 2**b[0] + 2**b[1] + ... 2**b[len(b)-1] +// +// The order of slice elements is not significant. Negative elements may be +// used to form fractions. A Bits value is normalized if each b[i] occurs at +// most once. For instance Bits{0, 0, 1} is not normalized but represents the +// same floating-point number as Bits{2}, which is normalized. The zero (nil) +// value of Bits is a ready to use Bits value and represents the value 0. +type Bits []int + +func (x Bits) add(y Bits) Bits { + return append(x, y...) +} + +func (x Bits) mul(y Bits) Bits { + var p Bits + for _, x := range x { + for _, y := range y { + p = append(p, x+y) + } + } + return p +} + +func TestMulBits(t *testing.T) { + for _, test := range []struct { + x, y, want Bits + }{ + {nil, nil, nil}, + {Bits{}, Bits{}, nil}, + {Bits{0}, Bits{0}, Bits{0}}, + {Bits{0}, Bits{1}, Bits{1}}, + {Bits{1}, Bits{1, 2, 3}, Bits{2, 3, 4}}, + {Bits{-1}, Bits{1}, Bits{0}}, + {Bits{-10, -1, 0, 1, 10}, Bits{1, 2, 3}, Bits{-9, -8, -7, 0, 1, 2, 1, 2, 3, 2, 3, 4, 11, 12, 13}}, + } { + got := fmt.Sprintf("%v", test.x.mul(test.y)) + want := fmt.Sprintf("%v", test.want) + if got != want { + t.Errorf("%v * %v = %s; want %s", test.x, test.y, got, want) + } + + } +} + +// norm returns the normalized bits for x: It removes multiple equal entries +// by treating them as an addition (e.g., Bits{5, 5} => Bits{6}), and it sorts +// the result list for reproducible results. +func (x Bits) norm() Bits { + m := make(map[int]bool) + for _, b := range x { + for m[b] { + m[b] = false + b++ + } + m[b] = true + } + var z Bits + for b, set := range m { + if set { + z = append(z, b) + } + } + sort.Ints([]int(z)) + return z +} + +func TestNormBits(t *testing.T) { + for _, test := range []struct { + x, want Bits + }{ + {nil, nil}, + {Bits{}, Bits{}}, + {Bits{0}, Bits{0}}, + {Bits{0, 0}, Bits{1}}, + {Bits{3, 1, 1}, Bits{2, 3}}, + {Bits{10, 9, 8, 7, 6, 6}, Bits{11}}, + } { + got := fmt.Sprintf("%v", test.x.norm()) + want := fmt.Sprintf("%v", test.want) + if got != want { + t.Errorf("normBits(%v) = %s; want %s", test.x, got, want) + } + + } +} + +// round returns the Float value corresponding to x after rounding x +// to prec bits according to mode. +func (x Bits) round(prec uint, mode RoundingMode) *Float { + x = x.norm() + + // determine range + var min, max int + for i, b := range x { + if i == 0 || b < min { + min = b + } + if i == 0 || b > max { + max = b + } + } + prec0 := uint(max + 1 - min) + if prec >= prec0 { + return x.Float() + } + // prec < prec0 + + // determine bit 0, rounding, and sticky bit, and result bits z + var bit0, rbit, sbit uint + var z Bits + r := max - int(prec) + for _, b := range x { + switch { + case b == r: + rbit = 1 + case b < r: + sbit = 1 + default: + // b > r + if b == r+1 { + bit0 = 1 + } + z = append(z, b) + } + } + + // round + f := z.Float() // rounded to zero + if mode == ToNearestAway { + panic("not yet implemented") + } + if mode == ToNearestEven && rbit == 1 && (sbit == 1 || sbit == 0 && bit0 != 0) || mode == AwayFromZero { + // round away from zero + f.SetMode(ToZero).SetPrec(prec) + f.Add(f, Bits{int(r) + 1}.Float()) + } + return f +} + +// Float returns the *Float z of the smallest possible precision such that +// z = sum(2**bits[i]), with i = range bits. If multiple bits[i] are equal, +// they are added: Bits{0, 1, 0}.Float() == 2**0 + 2**1 + 2**0 = 4. +func (bits Bits) Float() *Float { + // handle 0 + if len(bits) == 0 { + return new(Float) + } + // len(bits) > 0 + + // determine lsb exponent + var min int + for i, b := range bits { + if i == 0 || b < min { + min = b + } + } + + // create bit pattern + x := NewInt(0) + for _, b := range bits { + badj := b - min + // propagate carry if necessary + for x.Bit(badj) != 0 { + x.SetBit(x, badj, 0) + badj++ + } + x.SetBit(x, badj, 1) + } + + // create corresponding float + z := new(Float).SetInt(x) // normalized + if e := int64(z.exp) + int64(min); MinExp <= e && e <= MaxExp { + z.exp = int32(e) + } else { + // this should never happen for our test cases + panic("exponent out of range") + } + return z +} + +func TestFromBits(t *testing.T) { + for _, test := range []struct { + bits Bits + want string + }{ + // all different bit numbers + {nil, "0"}, + {Bits{0}, "0x.8p+1"}, + {Bits{1}, "0x.8p+2"}, + {Bits{-1}, "0x.8p+0"}, + {Bits{63}, "0x.8p+64"}, + {Bits{33, -30}, "0x.8000000000000001p+34"}, + {Bits{255, 0}, "0x.8000000000000000000000000000000000000000000000000000000000000001p+256"}, + + // multiple equal bit numbers + {Bits{0, 0}, "0x.8p+2"}, + {Bits{0, 0, 0, 0}, "0x.8p+3"}, + {Bits{0, 1, 0}, "0x.8p+3"}, + {append(Bits{2, 1, 0} /* 7 */, Bits{3, 1} /* 10 */ ...), "0x.88p+5" /* 17 */}, + } { + f := test.bits.Float() + if got := f.Text('p', 0); got != test.want { + t.Errorf("setBits(%v) = %s; want %s", test.bits, got, test.want) + } + } +} diff --git a/libgo/go/math/big/decimal.go b/libgo/go/math/big/decimal.go new file mode 100644 index 00000000000..2595e5f8c12 --- /dev/null +++ b/libgo/go/math/big/decimal.go @@ -0,0 +1,264 @@ +// Copyright 2015 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 multi-precision decimal numbers. +// The implementation is for float to decimal conversion only; +// not general purpose use. +// The only operations are precise conversion from binary to +// decimal and rounding. +// +// The key observation and some code (shr) is borrowed from +// strconv/decimal.go: conversion of binary fractional values can be done +// precisely in multi-precision decimal because 2 divides 10 (required for +// >> of mantissa); but conversion of decimal floating-point values cannot +// be done precisely in binary representation. +// +// In contrast to strconv/decimal.go, only right shift is implemented in +// decimal format - left shift can be done precisely in binary format. + +package big + +// A decimal represents an unsigned floating-point number in decimal representation. +// The value of a non-zero decimal x is x.mant * 10 ** x.exp with 0.5 <= x.mant < 1, +// with the most-significant mantissa digit at index 0. For the zero decimal, the +// mantissa length and exponent are 0. +// The zero value for decimal represents a ready-to-use 0.0. +type decimal struct { + mant []byte // mantissa ASCII digits, big-endian + exp int // exponent +} + +// Maximum shift amount that can be done in one pass without overflow. +// A Word has _W bits and (1<= 0), or m >> -shift (for shift < 0). +func (x *decimal) init(m nat, shift int) { + // special case 0 + if len(m) == 0 { + x.mant = x.mant[:0] + x.exp = 0 + return + } + + // Optimization: If we need to shift right, first remove any trailing + // zero bits from m to reduce shift amount that needs to be done in + // decimal format (since that is likely slower). + if shift < 0 { + ntz := m.trailingZeroBits() + s := uint(-shift) + if s >= ntz { + s = ntz // shift at most ntz bits + } + m = nat(nil).shr(m, s) + shift += int(s) + } + + // Do any shift left in binary representation. + if shift > 0 { + m = nat(nil).shl(m, uint(shift)) + shift = 0 + } + + // Convert mantissa into decimal representation. + s := m.decimalString() // TODO(gri) avoid string conversion here + n := len(s) + x.exp = n + // Trim trailing zeros; instead the exponent is tracking + // the decimal point independent of the number of digits. + for n > 0 && s[n-1] == '0' { + n-- + } + x.mant = append(x.mant[:0], s[:n]...) + + // Do any (remaining) shift right in decimal representation. + if shift < 0 { + for shift < -maxShift { + shr(x, maxShift) + shift += maxShift + } + shr(x, uint(-shift)) + } +} + +// Possibly optimization: The current implementation of nat.string takes +// a charset argument. When a right shift is needed, we could provide +// "\x00\x01...\x09" instead of "012..9" (as in nat.decimalString) and +// avoid the repeated +'0' and -'0' operations in decimal.shr (and do a +// single +'0' pass at the end). + +// shr implements x >> s, for s <= maxShift. +func shr(x *decimal, s uint) { + // Division by 1<>s == 0 && r < len(x.mant) { + ch := Word(x.mant[r]) + r++ + n = n*10 + ch - '0' + } + if n == 0 { + // x == 0; shouldn't get here, but handle anyway + x.mant = x.mant[:0] + return + } + for n>>s == 0 { + r++ + n *= 10 + } + x.exp += 1 - r + + // read a digit, write a digit + w := 0 // write index + for r < len(x.mant) { + ch := Word(x.mant[r]) + r++ + d := n >> s + n -= d << s + x.mant[w] = byte(d + '0') + w++ + n = n*10 + ch - '0' + } + + // write extra digits that still fit + for n > 0 && w < len(x.mant) { + d := n >> s + n -= d << s + x.mant[w] = byte(d + '0') + w++ + n = n * 10 + } + x.mant = x.mant[:w] // the number may be shorter (e.g. 1024 >> 10) + + // append additional digits that didn't fit + for n > 0 { + d := n >> s + n -= d << s + x.mant = append(x.mant, byte(d+'0')) + n = n * 10 + } + + trim(x) +} + +func (x *decimal) String() string { + if len(x.mant) == 0 { + return "0" + } + + var buf []byte + switch { + case x.exp <= 0: + // 0.00ddd + buf = append(buf, "0."...) + buf = appendZeros(buf, -x.exp) + buf = append(buf, x.mant...) + + case /* 0 < */ x.exp < len(x.mant): + // dd.ddd + buf = append(buf, x.mant[:x.exp]...) + buf = append(buf, '.') + buf = append(buf, x.mant[x.exp:]...) + + default: // len(x.mant) <= x.exp + // ddd00 + buf = append(buf, x.mant...) + buf = appendZeros(buf, x.exp-len(x.mant)) + } + + return string(buf) +} + +// appendZeros appends n 0 digits to buf and returns buf. +func appendZeros(buf []byte, n int) []byte { + for ; n > 0; n-- { + buf = append(buf, '0') + } + return buf +} + +// shouldRoundUp reports if x should be rounded up +// if shortened to n digits. n must be a valid index +// for x.mant. +func shouldRoundUp(x *decimal, n int) bool { + if x.mant[n] == '5' && n+1 == len(x.mant) { + // exactly halfway - round to even + return n > 0 && (x.mant[n-1]-'0')&1 != 0 + } + // not halfway - digit tells all (x.mant has no trailing zeros) + return x.mant[n] >= '5' +} + +// round sets x to (at most) n mantissa digits by rounding it +// to the nearest even value with n (or fever) mantissa digits. +// If n < 0, x remains unchanged. +func (x *decimal) round(n int) { + if n < 0 || n >= len(x.mant) { + return // nothing to do + } + + if shouldRoundUp(x, n) { + x.roundUp(n) + } else { + x.roundDown(n) + } +} + +func (x *decimal) roundUp(n int) { + if n < 0 || n >= len(x.mant) { + return // nothing to do + } + // 0 <= n < len(x.mant) + + // find first digit < '9' + for n > 0 && x.mant[n-1] >= '9' { + n-- + } + + if n == 0 { + // all digits are '9's => round up to '1' and update exponent + x.mant[0] = '1' // ok since len(x.mant) > n + x.mant = x.mant[:1] + x.exp++ + return + } + + // n > 0 && x.mant[n-1] < '9' + x.mant[n-1]++ + x.mant = x.mant[:n] + // x already trimmed +} + +func (x *decimal) roundDown(n int) { + if n < 0 || n >= len(x.mant) { + return // nothing to do + } + x.mant = x.mant[:n] + trim(x) +} + +// trim cuts off any trailing zeros from x's mantissa; +// they are meaningless for the value of x. +func trim(x *decimal) { + i := len(x.mant) + for i > 0 && x.mant[i-1] == '0' { + i-- + } + x.mant = x.mant[:i] + if i == 0 { + x.exp = 0 + } +} diff --git a/libgo/go/math/big/decimal_test.go b/libgo/go/math/big/decimal_test.go new file mode 100644 index 00000000000..81e022a47dd --- /dev/null +++ b/libgo/go/math/big/decimal_test.go @@ -0,0 +1,106 @@ +// Copyright 2015 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 big + +import "testing" + +func TestDecimalString(t *testing.T) { + for _, test := range []struct { + x decimal + want string + }{ + {want: "0"}, + {decimal{nil, 1000}, "0"}, // exponent of 0 is ignored + {decimal{[]byte("12345"), 0}, "0.12345"}, + {decimal{[]byte("12345"), -3}, "0.00012345"}, + {decimal{[]byte("12345"), +3}, "123.45"}, + {decimal{[]byte("12345"), +10}, "1234500000"}, + } { + if got := test.x.String(); got != test.want { + t.Errorf("%v == %s; want %s", test.x, got, test.want) + } + } +} + +func TestDecimalInit(t *testing.T) { + for _, test := range []struct { + x Word + shift int + want string + }{ + {0, 0, "0"}, + {0, -100, "0"}, + {0, 100, "0"}, + {1, 0, "1"}, + {1, 10, "1024"}, + {1, 100, "1267650600228229401496703205376"}, + {1, -100, "0.0000000000000000000000000000007888609052210118054117285652827862296732064351090230047702789306640625"}, + {12345678, 8, "3160493568"}, + {12345678, -8, "48225.3046875"}, + {195312, 9, "99999744"}, + {1953125, 9, "1000000000"}, + } { + var d decimal + d.init(nat{test.x}.norm(), test.shift) + if got := d.String(); got != test.want { + t.Errorf("%d << %d == %s; want %s", test.x, test.shift, got, test.want) + } + } +} + +func TestDecimalRounding(t *testing.T) { + for _, test := range []struct { + x uint64 + n int + down, even, up string + }{ + {0, 0, "0", "0", "0"}, + {0, 1, "0", "0", "0"}, + + {1, 0, "0", "0", "10"}, + {5, 0, "0", "0", "10"}, + {9, 0, "0", "10", "10"}, + + {15, 1, "10", "20", "20"}, + {45, 1, "40", "40", "50"}, + {95, 1, "90", "100", "100"}, + + {12344999, 4, "12340000", "12340000", "12350000"}, + {12345000, 4, "12340000", "12340000", "12350000"}, + {12345001, 4, "12340000", "12350000", "12350000"}, + {23454999, 4, "23450000", "23450000", "23460000"}, + {23455000, 4, "23450000", "23460000", "23460000"}, + {23455001, 4, "23450000", "23460000", "23460000"}, + + {99994999, 4, "99990000", "99990000", "100000000"}, + {99995000, 4, "99990000", "100000000", "100000000"}, + {99999999, 4, "99990000", "100000000", "100000000"}, + + {12994999, 4, "12990000", "12990000", "13000000"}, + {12995000, 4, "12990000", "13000000", "13000000"}, + {12999999, 4, "12990000", "13000000", "13000000"}, + } { + x := nat(nil).setUint64(test.x) + + var d decimal + d.init(x, 0) + d.roundDown(test.n) + if got := d.String(); got != test.down { + t.Errorf("roundDown(%d, %d) = %s; want %s", test.x, test.n, got, test.down) + } + + d.init(x, 0) + d.round(test.n) + if got := d.String(); got != test.even { + t.Errorf("round(%d, %d) = %s; want %s", test.x, test.n, got, test.even) + } + + d.init(x, 0) + d.roundUp(test.n) + if got := d.String(); got != test.up { + t.Errorf("roundUp(%d, %d) = %s; want %s", test.x, test.n, got, test.up) + } + } +} diff --git a/libgo/go/math/big/float.go b/libgo/go/math/big/float.go new file mode 100644 index 00000000000..d7aa8953c43 --- /dev/null +++ b/libgo/go/math/big/float.go @@ -0,0 +1,1693 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// This file implements multi-precision floating-point numbers. +// Like in the GNU MPFR library (http://www.mpfr.org/), operands +// can be of mixed precision. Unlike MPFR, the rounding mode is +// not specified with each operation, but with each operand. The +// rounding mode of the result operand determines the rounding +// mode of an operation. This is a from-scratch implementation. + +package big + +import ( + "fmt" + "math" +) + +const debugFloat = false // enable for debugging + +// A nonzero finite Float represents a multi-precision floating point number +// +// sign × mantissa × 2**exponent +// +// with 0.5 <= mantissa < 1.0, and MinExp <= exponent <= MaxExp. +// A Float may also be zero (+0, -0) or infinite (+Inf, -Inf). +// All Floats are ordered, and the ordering of two Floats x and y +// is defined by x.Cmp(y). +// +// Each Float value also has a precision, rounding mode, and accuracy. +// The precision is the maximum number of mantissa bits available to +// represent the value. The rounding mode specifies how a result should +// be rounded to fit into the mantissa bits, and accuracy describes the +// rounding error with respect to the exact result. +// +// Unless specified otherwise, all operations (including setters) that +// specify a *Float variable for the result (usually via the receiver +// with the exception of MantExp), round the numeric result according +// to the precision and rounding mode of the result variable. +// +// If the provided result precision is 0 (see below), it is set to the +// precision of the argument with the largest precision value before any +// rounding takes place, and the rounding mode remains unchanged. Thus, +// uninitialized Floats provided as result arguments will have their +// precision set to a reasonable value determined by the operands and +// their mode is the zero value for RoundingMode (ToNearestEven). +// +// By setting the desired precision to 24 or 53 and using matching rounding +// mode (typically ToNearestEven), Float operations produce the same results +// as the corresponding float32 or float64 IEEE-754 arithmetic for operands +// that correspond to normal (i.e., not denormal) float32 or float64 numbers. +// Exponent underflow and overflow lead to a 0 or an Infinity for different +// values than IEEE-754 because Float exponents have a much larger range. +// +// The zero (uninitialized) value for a Float is ready to use and represents +// the number +0.0 exactly, with precision 0 and rounding mode ToNearestEven. +// +type Float struct { + prec uint32 + mode RoundingMode + acc Accuracy + form form + neg bool + mant nat + exp int32 +} + +// An ErrNaN panic is raised by a Float operation that would lead to +// a NaN under IEEE-754 rules. An ErrNaN implements the error interface. +type ErrNaN struct { + msg string +} + +func (err ErrNaN) Error() string { + return err.msg +} + +// NewFloat allocates and returns a new Float set to x, +// with precision 53 and rounding mode ToNearestEven. +// NewFloat panics with ErrNaN if x is a NaN. +func NewFloat(x float64) *Float { + if math.IsNaN(x) { + panic(ErrNaN{"NewFloat(NaN)"}) + } + return new(Float).SetFloat64(x) +} + +// Exponent and precision limits. +const ( + MaxExp = math.MaxInt32 // largest supported exponent + MinExp = math.MinInt32 // smallest supported exponent + MaxPrec = math.MaxUint32 // largest (theoretically) supported precision; likely memory-limited +) + +// Internal representation: The mantissa bits x.mant of a nonzero finite +// Float x are stored in a nat slice long enough to hold up to x.prec bits; +// the slice may (but doesn't have to) be shorter if the mantissa contains +// trailing 0 bits. x.mant is normalized if the msb of x.mant == 1 (i.e., +// the msb is shifted all the way "to the left"). Thus, if the mantissa has +// trailing 0 bits or x.prec is not a multiple of the the Word size _W, +// x.mant[0] has trailing zero bits. The msb of the mantissa corresponds +// to the value 0.5; the exponent x.exp shifts the binary point as needed. +// +// A zero or non-finite Float x ignores x.mant and x.exp. +// +// x form neg mant exp +// ---------------------------------------------------------- +// ±0 zero sign - - +// 0 < |x| < +Inf finite sign mantissa exponent +// ±Inf inf sign - - + +// A form value describes the internal representation. +type form byte + +// The form value order is relevant - do not change! +const ( + zero form = iota + finite + inf +) + +// RoundingMode determines how a Float value is rounded to the +// desired precision. Rounding may change the Float value; the +// rounding error is described by the Float's Accuracy. +type RoundingMode byte + +// The following rounding modes are supported. +const ( + ToNearestEven RoundingMode = iota // == IEEE 754-2008 roundTiesToEven + ToNearestAway // == IEEE 754-2008 roundTiesToAway + ToZero // == IEEE 754-2008 roundTowardZero + AwayFromZero // no IEEE 754-2008 equivalent + ToNegativeInf // == IEEE 754-2008 roundTowardNegative + ToPositiveInf // == IEEE 754-2008 roundTowardPositive +) + +//go:generate stringer -type=RoundingMode + +// Accuracy describes the rounding error produced by the most recent +// operation that generated a Float value, relative to the exact value. +type Accuracy int8 + +// Constants describing the Accuracy of a Float. +const ( + Below Accuracy = -1 + Exact Accuracy = 0 + Above Accuracy = +1 +) + +//go:generate stringer -type=Accuracy + +// SetPrec sets z's precision to prec and returns the (possibly) rounded +// value of z. Rounding occurs according to z's rounding mode if the mantissa +// cannot be represented in prec bits without loss of precision. +// SetPrec(0) maps all finite values to ±0; infinite values remain unchanged. +// If prec > MaxPrec, it is set to MaxPrec. +func (z *Float) SetPrec(prec uint) *Float { + z.acc = Exact // optimistically assume no rounding is needed + + // special case + if prec == 0 { + z.prec = 0 + if z.form == finite { + // truncate z to 0 + z.acc = makeAcc(z.neg) + z.form = zero + } + return z + } + + // general case + if prec > MaxPrec { + prec = MaxPrec + } + old := z.prec + z.prec = uint32(prec) + if z.prec < old { + z.round(0) + } + return z +} + +func makeAcc(above bool) Accuracy { + if above { + return Above + } + return Below +} + +// SetMode sets z's rounding mode to mode and returns an exact z. +// z remains unchanged otherwise. +// z.SetMode(z.Mode()) is a cheap way to set z's accuracy to Exact. +func (z *Float) SetMode(mode RoundingMode) *Float { + z.mode = mode + z.acc = Exact + return z +} + +// Prec returns the mantissa precision of x in bits. +// The result may be 0 for |x| == 0 and |x| == Inf. +func (x *Float) Prec() uint { + return uint(x.prec) +} + +// MinPrec returns the minimum precision required to represent x exactly +// (i.e., the smallest prec before x.SetPrec(prec) would start rounding x). +// The result is 0 for |x| == 0 and |x| == Inf. +func (x *Float) MinPrec() uint { + if x.form != finite { + return 0 + } + return uint(len(x.mant))*_W - x.mant.trailingZeroBits() +} + +// Mode returns the rounding mode of x. +func (x *Float) Mode() RoundingMode { + return x.mode +} + +// Acc returns the accuracy of x produced by the most recent operation. +func (x *Float) Acc() Accuracy { + return x.acc +} + +// Sign returns: +// +// -1 if x < 0 +// 0 if x is ±0 +// +1 if x > 0 +// +func (x *Float) Sign() int { + if debugFloat { + x.validate() + } + if x.form == zero { + return 0 + } + if x.neg { + return -1 + } + return 1 +} + +// MantExp breaks x into its mantissa and exponent components +// and returns the exponent. If a non-nil mant argument is +// provided its value is set to the mantissa of x, with the +// same precision and rounding mode as x. The components +// satisfy x == mant × 2**exp, with 0.5 <= |mant| < 1.0. +// Calling MantExp with a nil argument is an efficient way to +// get the exponent of the receiver. +// +// Special cases are: +// +// ( ±0).MantExp(mant) = 0, with mant set to ±0 +// (±Inf).MantExp(mant) = 0, with mant set to ±Inf +// +// x and mant may be the same in which case x is set to its +// mantissa value. +func (x *Float) MantExp(mant *Float) (exp int) { + if debugFloat { + x.validate() + } + if x.form == finite { + exp = int(x.exp) + } + if mant != nil { + mant.Copy(x) + if mant.form == finite { + mant.exp = 0 + } + } + return +} + +func (z *Float) setExpAndRound(exp int64, sbit uint) { + if exp < MinExp { + // underflow + z.acc = makeAcc(z.neg) + z.form = zero + return + } + + if exp > MaxExp { + // overflow + z.acc = makeAcc(!z.neg) + z.form = inf + return + } + + z.form = finite + z.exp = int32(exp) + z.round(sbit) +} + +// SetMantExp sets z to mant × 2**exp and and returns z. +// The result z has the same precision and rounding mode +// as mant. SetMantExp is an inverse of MantExp but does +// not require 0.5 <= |mant| < 1.0. Specifically: +// +// mant := new(Float) +// new(Float).SetMantExp(mant, x.SetMantExp(mant)).Cmp(x).Eql() is true +// +// Special cases are: +// +// z.SetMantExp( ±0, exp) = ±0 +// z.SetMantExp(±Inf, exp) = ±Inf +// +// z and mant may be the same in which case z's exponent +// is set to exp. +func (z *Float) SetMantExp(mant *Float, exp int) *Float { + if debugFloat { + z.validate() + mant.validate() + } + z.Copy(mant) + if z.form != finite { + return z + } + z.setExpAndRound(int64(z.exp)+int64(exp), 0) + return z +} + +// Signbit returns true if x is negative or negative zero. +func (x *Float) Signbit() bool { + return x.neg +} + +// IsInf reports whether x is +Inf or -Inf. +func (x *Float) IsInf() bool { + return x.form == inf +} + +// IsInt reports whether x is an integer. +// ±Inf values are not integers. +func (x *Float) IsInt() bool { + if debugFloat { + x.validate() + } + // special cases + if x.form != finite { + return x.form == zero + } + // x.form == finite + if x.exp <= 0 { + return false + } + // x.exp > 0 + return x.prec <= uint32(x.exp) || x.MinPrec() <= uint(x.exp) // not enough bits for fractional mantissa +} + +// debugging support +func (x *Float) validate() { + if !debugFloat { + // avoid performance bugs + panic("validate called but debugFloat is not set") + } + if x.form != finite { + return + } + m := len(x.mant) + if m == 0 { + panic("nonzero finite number with empty mantissa") + } + const msb = 1 << (_W - 1) + if x.mant[m-1]&msb == 0 { + panic(fmt.Sprintf("msb not set in last word %#x of %s", x.mant[m-1], x.Text('p', 0))) + } + if x.prec == 0 { + panic("zero precision finite number") + } +} + +// round rounds z according to z.mode to z.prec bits and sets z.acc accordingly. +// sbit must be 0 or 1 and summarizes any "sticky bit" information one might +// have before calling round. z's mantissa must be normalized (with the msb set) +// or empty. +// +// CAUTION: The rounding modes ToNegativeInf, ToPositiveInf are affected by the +// sign of z. For correct rounding, the sign of z must be set correctly before +// calling round. +func (z *Float) round(sbit uint) { + if debugFloat { + z.validate() + } + + z.acc = Exact + if z.form != finite { + // ±0 or ±Inf => nothing left to do + return + } + // z.form == finite && len(z.mant) > 0 + // m > 0 implies z.prec > 0 (checked by validate) + + m := uint32(len(z.mant)) // present mantissa length in words + bits := m * _W // present mantissa bits + if bits <= z.prec { + // mantissa fits => nothing to do + return + } + // bits > z.prec + + n := (z.prec + (_W - 1)) / _W // mantissa length in words for desired precision + + // Rounding is based on two bits: the rounding bit (rbit) and the + // sticky bit (sbit). The rbit is the bit immediately before the + // z.prec leading mantissa bits (the "0.5"). The sbit is set if any + // of the bits before the rbit are set (the "0.25", "0.125", etc.): + // + // rbit sbit => "fractional part" + // + // 0 0 == 0 + // 0 1 > 0 , < 0.5 + // 1 0 == 0.5 + // 1 1 > 0.5, < 1.0 + + // bits > z.prec: mantissa too large => round + r := uint(bits - z.prec - 1) // rounding bit position; r >= 0 + rbit := z.mant.bit(r) // rounding bit + if sbit == 0 { + sbit = z.mant.sticky(r) + } + if debugFloat && sbit&^1 != 0 { + panic(fmt.Sprintf("invalid sbit %#x", sbit)) + } + + // convert ToXInf rounding modes + mode := z.mode + switch mode { + case ToNegativeInf: + mode = ToZero + if z.neg { + mode = AwayFromZero + } + case ToPositiveInf: + mode = AwayFromZero + if z.neg { + mode = ToZero + } + } + + // cut off extra words + if m > n { + copy(z.mant, z.mant[m-n:]) // move n last words to front + z.mant = z.mant[:n] + } + + // determine number of trailing zero bits t + t := n*_W - z.prec // 0 <= t < _W + lsb := Word(1) << t + + // make rounding decision + // TODO(gri) This can be simplified (see Bits.round in bits_test.go). + switch mode { + case ToZero: + // nothing to do + case ToNearestEven, ToNearestAway: + if rbit == 0 { + // rounding bits == 0b0x + mode = ToZero + } else if sbit == 1 { + // rounding bits == 0b11 + mode = AwayFromZero + } + case AwayFromZero: + if rbit|sbit == 0 { + mode = ToZero + } + default: + // ToXInf modes have been converted to ToZero or AwayFromZero + panic("unreachable") + } + + // round and determine accuracy + switch mode { + case ToZero: + if rbit|sbit != 0 { + z.acc = Below + } + + case ToNearestEven, ToNearestAway: + if debugFloat && rbit != 1 { + panic("internal error in rounding") + } + if mode == ToNearestEven && sbit == 0 && z.mant[0]&lsb == 0 { + z.acc = Below + break + } + // mode == ToNearestAway || sbit == 1 || z.mant[0]&lsb != 0 + fallthrough + + case AwayFromZero: + // add 1 to mantissa + if addVW(z.mant, z.mant, lsb) != 0 { + // overflow => shift mantissa right by 1 and add msb + shrVU(z.mant, z.mant, 1) + z.mant[n-1] |= 1 << (_W - 1) + // adjust exponent + if z.exp < MaxExp { + z.exp++ + } else { + // exponent overflow + z.acc = makeAcc(!z.neg) + z.form = inf + return + } + } + z.acc = Above + } + + // zero out trailing bits in least-significant word + z.mant[0] &^= lsb - 1 + + // update accuracy + if z.acc != Exact && z.neg { + z.acc = -z.acc + } + + if debugFloat { + z.validate() + } + + return +} + +func (z *Float) setBits64(neg bool, x uint64) *Float { + if z.prec == 0 { + z.prec = 64 + } + z.acc = Exact + z.neg = neg + if x == 0 { + z.form = zero + return z + } + // x != 0 + z.form = finite + s := nlz64(x) + z.mant = z.mant.setUint64(x << s) + z.exp = int32(64 - s) // always fits + if z.prec < 64 { + z.round(0) + } + return z +} + +// SetUint64 sets z to the (possibly rounded) value of x and returns z. +// If z's precision is 0, it is changed to 64 (and rounding will have +// no effect). +func (z *Float) SetUint64(x uint64) *Float { + return z.setBits64(false, x) +} + +// SetInt64 sets z to the (possibly rounded) value of x and returns z. +// If z's precision is 0, it is changed to 64 (and rounding will have +// no effect). +func (z *Float) SetInt64(x int64) *Float { + u := x + if u < 0 { + u = -u + } + // We cannot simply call z.SetUint64(uint64(u)) and change + // the sign afterwards because the sign affects rounding. + return z.setBits64(x < 0, uint64(u)) +} + +// SetFloat64 sets z to the (possibly rounded) value of x and returns z. +// If z's precision is 0, it is changed to 53 (and rounding will have +// no effect). SetFloat64 panics with ErrNaN if x is a NaN. +func (z *Float) SetFloat64(x float64) *Float { + if z.prec == 0 { + z.prec = 53 + } + if math.IsNaN(x) { + panic(ErrNaN{"Float.SetFloat64(NaN)"}) + } + z.acc = Exact + z.neg = math.Signbit(x) // handle -0, -Inf correctly + if x == 0 { + z.form = zero + return z + } + if math.IsInf(x, 0) { + z.form = inf + return z + } + // normalized x != 0 + z.form = finite + fmant, exp := math.Frexp(x) // get normalized mantissa + z.mant = z.mant.setUint64(1<<63 | math.Float64bits(fmant)<<11) + z.exp = int32(exp) // always fits + if z.prec < 53 { + z.round(0) + } + return z +} + +// fnorm normalizes mantissa m by shifting it to the left +// such that the msb of the most-significant word (msw) is 1. +// It returns the shift amount. It assumes that len(m) != 0. +func fnorm(m nat) int64 { + if debugFloat && (len(m) == 0 || m[len(m)-1] == 0) { + panic("msw of mantissa is 0") + } + s := nlz(m[len(m)-1]) + if s > 0 { + c := shlVU(m, m, s) + if debugFloat && c != 0 { + panic("nlz or shlVU incorrect") + } + } + return int64(s) +} + +// SetInt sets z to the (possibly rounded) value of x and returns z. +// If z's precision is 0, it is changed to the larger of x.BitLen() +// or 64 (and rounding will have no effect). +func (z *Float) SetInt(x *Int) *Float { + // TODO(gri) can be more efficient if z.prec > 0 + // but small compared to the size of x, or if there + // are many trailing 0's. + bits := uint32(x.BitLen()) + if z.prec == 0 { + z.prec = umax32(bits, 64) + } + z.acc = Exact + z.neg = x.neg + if len(x.abs) == 0 { + z.form = zero + return z + } + // x != 0 + z.mant = z.mant.set(x.abs) + fnorm(z.mant) + z.setExpAndRound(int64(bits), 0) + return z +} + +// SetRat sets z to the (possibly rounded) value of x and returns z. +// If z's precision is 0, it is changed to the largest of a.BitLen(), +// b.BitLen(), or 64; with x = a/b. +func (z *Float) SetRat(x *Rat) *Float { + if x.IsInt() { + return z.SetInt(x.Num()) + } + var a, b Float + a.SetInt(x.Num()) + b.SetInt(x.Denom()) + if z.prec == 0 { + z.prec = umax32(a.prec, b.prec) + } + return z.Quo(&a, &b) +} + +// SetInf sets z to the infinite Float -Inf if signbit is +// set, or +Inf if signbit is not set, and returns z. The +// precision of z is unchanged and the result is always +// Exact. +func (z *Float) SetInf(signbit bool) *Float { + z.acc = Exact + z.form = inf + z.neg = signbit + return z +} + +// Set sets z to the (possibly rounded) value of x and returns z. +// If z's precision is 0, it is changed to the precision of x +// before setting z (and rounding will have no effect). +// Rounding is performed according to z's precision and rounding +// mode; and z's accuracy reports the result error relative to the +// exact (not rounded) result. +func (z *Float) Set(x *Float) *Float { + if debugFloat { + x.validate() + } + z.acc = Exact + if z != x { + z.form = x.form + z.neg = x.neg + if x.form == finite { + z.exp = x.exp + z.mant = z.mant.set(x.mant) + } + if z.prec == 0 { + z.prec = x.prec + } else if z.prec < x.prec { + z.round(0) + } + } + return z +} + +// Copy sets z to x, with the same precision, rounding mode, and +// accuracy as x, and returns z. x is not changed even if z and +// x are the same. +func (z *Float) Copy(x *Float) *Float { + if debugFloat { + x.validate() + } + if z != x { + z.prec = x.prec + z.mode = x.mode + z.acc = x.acc + z.form = x.form + z.neg = x.neg + if z.form == finite { + z.mant = z.mant.set(x.mant) + z.exp = x.exp + } + } + return z +} + +// msb32 returns the 32 most significant bits of x. +func msb32(x nat) uint32 { + i := len(x) - 1 + if i < 0 { + return 0 + } + if debugFloat && x[i]&(1<<(_W-1)) == 0 { + panic("x not normalized") + } + switch _W { + case 32: + return uint32(x[i]) + case 64: + return uint32(x[i] >> 32) + } + panic("unreachable") +} + +// msb64 returns the 64 most significant bits of x. +func msb64(x nat) uint64 { + i := len(x) - 1 + if i < 0 { + return 0 + } + if debugFloat && x[i]&(1<<(_W-1)) == 0 { + panic("x not normalized") + } + switch _W { + case 32: + v := uint64(x[i]) << 32 + if i > 0 { + v |= uint64(x[i-1]) + } + return v + case 64: + return uint64(x[i]) + } + panic("unreachable") +} + +// Uint64 returns the unsigned integer resulting from truncating x +// towards zero. If 0 <= x <= math.MaxUint64, the result is Exact +// if x is an integer and Below otherwise. +// The result is (0, Above) for x < 0, and (math.MaxUint64, Below) +// for x > math.MaxUint64. +func (x *Float) Uint64() (uint64, Accuracy) { + if debugFloat { + x.validate() + } + + switch x.form { + case finite: + if x.neg { + return 0, Above + } + // 0 < x < +Inf + if x.exp <= 0 { + // 0 < x < 1 + return 0, Below + } + // 1 <= x < Inf + if x.exp <= 64 { + // u = trunc(x) fits into a uint64 + u := msb64(x.mant) >> (64 - uint32(x.exp)) + if x.MinPrec() <= 64 { + return u, Exact + } + return u, Below // x truncated + } + // x too large + return math.MaxUint64, Below + + case zero: + return 0, Exact + + case inf: + if x.neg { + return 0, Above + } + return math.MaxUint64, Below + } + + panic("unreachable") +} + +// Int64 returns the integer resulting from truncating x towards zero. +// If math.MinInt64 <= x <= math.MaxInt64, the result is Exact if x is +// an integer, and Above (x < 0) or Below (x > 0) otherwise. +// The result is (math.MinInt64, Above) for x < math.MinInt64, +// and (math.MaxInt64, Below) for x > math.MaxInt64. +func (x *Float) Int64() (int64, Accuracy) { + if debugFloat { + x.validate() + } + + switch x.form { + case finite: + // 0 < |x| < +Inf + acc := makeAcc(x.neg) + if x.exp <= 0 { + // 0 < |x| < 1 + return 0, acc + } + // x.exp > 0 + + // 1 <= |x| < +Inf + if x.exp <= 63 { + // i = trunc(x) fits into an int64 (excluding math.MinInt64) + i := int64(msb64(x.mant) >> (64 - uint32(x.exp))) + if x.neg { + i = -i + } + if x.MinPrec() <= uint(x.exp) { + return i, Exact + } + return i, acc // x truncated + } + if x.neg { + // check for special case x == math.MinInt64 (i.e., x == -(0.5 << 64)) + if x.exp == 64 && x.MinPrec() == 1 { + acc = Exact + } + return math.MinInt64, acc + } + // x too large + return math.MaxInt64, Below + + case zero: + return 0, Exact + + case inf: + if x.neg { + return math.MinInt64, Above + } + return math.MaxInt64, Below + } + + panic("unreachable") +} + +// Float32 returns the float32 value nearest to x. If x is too small to be +// represented by a float32 (|x| < math.SmallestNonzeroFloat32), the result +// is (0, Below) or (-0, Above), respectively, depending on the sign of x. +// If x is too large to be represented by a float32 (|x| > math.MaxFloat32), +// the result is (+Inf, Above) or (-Inf, Below), depending on the sign of x. +func (x *Float) Float32() (float32, Accuracy) { + if debugFloat { + x.validate() + } + + switch x.form { + case finite: + // 0 < |x| < +Inf + + const ( + fbits = 32 // float size + mbits = 23 // mantissa size (excluding implicit msb) + ebits = fbits - mbits - 1 // 8 exponent size + bias = 1<<(ebits-1) - 1 // 127 exponent bias + dmin = 1 - bias - mbits // -149 smallest unbiased exponent (denormal) + emin = 1 - bias // -126 smallest unbiased exponent (normal) + emax = bias // 127 largest unbiased exponent (normal) + ) + + // Float mantissa m is 0.5 <= m < 1.0; compute exponent for floatxx mantissa. + e := x.exp - 1 // exponent for mantissa m with 1.0 <= m < 2.0 + p := mbits + 1 // precision of normal float + + // If the exponent is too small, we may have a denormal number + // in which case we have fewer mantissa bits available: reduce + // precision accordingly. + if e < emin { + p -= emin - int(e) + // Make sure we have at least 1 bit so that we don't + // lose numbers rounded up to the smallest denormal. + if p < 1 { + p = 1 + } + } + + // round + var r Float + r.prec = uint32(p) + r.Set(x) + e = r.exp - 1 + + // Rounding may have caused r to overflow to ±Inf + // (rounding never causes underflows to 0). + if r.form == inf { + e = emax + 1 // cause overflow below + } + + // If the exponent is too large, overflow to ±Inf. + if e > emax { + // overflow + if x.neg { + return float32(math.Inf(-1)), Below + } + return float32(math.Inf(+1)), Above + } + // e <= emax + + // Determine sign, biased exponent, and mantissa. + var sign, bexp, mant uint32 + if x.neg { + sign = 1 << (fbits - 1) + } + + // Rounding may have caused a denormal number to + // become normal. Check again. + if e < emin { + // denormal number + if e < dmin { + // underflow to ±0 + if x.neg { + var z float32 + return -z, Above + } + return 0.0, Below + } + // bexp = 0 + mant = msb32(r.mant) >> (fbits - r.prec) + } else { + // normal number: emin <= e <= emax + bexp = uint32(e+bias) << mbits + mant = msb32(r.mant) >> ebits & (1< math.MaxFloat64), +// the result is (+Inf, Above) or (-Inf, Below), depending on the sign of x. +func (x *Float) Float64() (float64, Accuracy) { + if debugFloat { + x.validate() + } + + switch x.form { + case finite: + // 0 < |x| < +Inf + + const ( + fbits = 64 // float size + mbits = 52 // mantissa size (excluding implicit msb) + ebits = fbits - mbits - 1 // 11 exponent size + bias = 1<<(ebits-1) - 1 // 1023 exponent bias + dmin = 1 - bias - mbits // -1074 smallest unbiased exponent (denormal) + emin = 1 - bias // -1022 smallest unbiased exponent (normal) + emax = bias // 1023 largest unbiased exponent (normal) + ) + + // Float mantissa m is 0.5 <= m < 1.0; compute exponent for floatxx mantissa. + e := x.exp - 1 // exponent for mantissa m with 1.0 <= m < 2.0 + p := mbits + 1 // precision of normal float + + // If the exponent is too small, we may have a denormal number + // in which case we have fewer mantissa bits available: reduce + // precision accordingly. + if e < emin { + p -= emin - int(e) + // Make sure we have at least 1 bit so that we don't + // lose numbers rounded up to the smallest denormal. + if p < 1 { + p = 1 + } + } + + // round + var r Float + r.prec = uint32(p) + r.Set(x) + e = r.exp - 1 + + // Rounding may have caused r to overflow to ±Inf + // (rounding never causes underflows to 0). + if r.form == inf { + e = emax + 1 // cause overflow below + } + + // If the exponent is too large, overflow to ±Inf. + if e > emax { + // overflow + if x.neg { + return math.Inf(-1), Below + } + return math.Inf(+1), Above + } + // e <= emax + + // Determine sign, biased exponent, and mantissa. + var sign, bexp, mant uint64 + if x.neg { + sign = 1 << (fbits - 1) + } + + // Rounding may have caused a denormal number to + // become normal. Check again. + if e < emin { + // denormal number + if e < dmin { + // underflow to ±0 + if x.neg { + var z float64 + return -z, Above + } + return 0.0, Below + } + // bexp = 0 + mant = msb64(r.mant) >> (fbits - r.prec) + } else { + // normal number: emin <= e <= emax + bexp = uint64(e+bias) << mbits + mant = msb64(r.mant) >> ebits & (1< 0, and Above for x < 0. +// If a non-nil *Int argument z is provided, Int stores +// the result in z instead of allocating a new Int. +func (x *Float) Int(z *Int) (*Int, Accuracy) { + if debugFloat { + x.validate() + } + + if z == nil && x.form <= finite { + z = new(Int) + } + + switch x.form { + case finite: + // 0 < |x| < +Inf + acc := makeAcc(x.neg) + if x.exp <= 0 { + // 0 < |x| < 1 + return z.SetInt64(0), acc + } + // x.exp > 0 + + // 1 <= |x| < +Inf + // determine minimum required precision for x + allBits := uint(len(x.mant)) * _W + exp := uint(x.exp) + if x.MinPrec() <= exp { + acc = Exact + } + // shift mantissa as needed + if z == nil { + z = new(Int) + } + z.neg = x.neg + switch { + case exp > allBits: + z.abs = z.abs.shl(x.mant, exp-allBits) + default: + z.abs = z.abs.set(x.mant) + case exp < allBits: + z.abs = z.abs.shr(x.mant, allBits-exp) + } + return z, acc + + case zero: + return z.SetInt64(0), Exact + + case inf: + return nil, makeAcc(x.neg) + } + + panic("unreachable") +} + +// Rat returns the rational number corresponding to x; +// or nil if x is an infinity. +// The result is Exact is x is not an Inf. +// If a non-nil *Rat argument z is provided, Rat stores +// the result in z instead of allocating a new Rat. +func (x *Float) Rat(z *Rat) (*Rat, Accuracy) { + if debugFloat { + x.validate() + } + + if z == nil && x.form <= finite { + z = new(Rat) + } + + switch x.form { + case finite: + // 0 < |x| < +Inf + allBits := int32(len(x.mant)) * _W + // build up numerator and denominator + z.a.neg = x.neg + switch { + case x.exp > allBits: + z.a.abs = z.a.abs.shl(x.mant, uint(x.exp-allBits)) + z.b.abs = z.b.abs[:0] // == 1 (see Rat) + // z already in normal form + default: + z.a.abs = z.a.abs.set(x.mant) + z.b.abs = z.b.abs[:0] // == 1 (see Rat) + // z already in normal form + case x.exp < allBits: + z.a.abs = z.a.abs.set(x.mant) + t := z.b.abs.setUint64(1) + z.b.abs = t.shl(t, uint(allBits-x.exp)) + z.norm() + } + return z, Exact + + case zero: + return z.SetInt64(0), Exact + + case inf: + return nil, makeAcc(x.neg) + } + + panic("unreachable") +} + +// Abs sets z to the (possibly rounded) value |x| (the absolute value of x) +// and returns z. +func (z *Float) Abs(x *Float) *Float { + z.Set(x) + z.neg = false + return z +} + +// Neg sets z to the (possibly rounded) value of x with its sign negated, +// and returns z. +func (z *Float) Neg(x *Float) *Float { + z.Set(x) + z.neg = !z.neg + return z +} + +func validateBinaryOperands(x, y *Float) { + if !debugFloat { + // avoid performance bugs + panic("validateBinaryOperands called but debugFloat is not set") + } + if len(x.mant) == 0 { + panic("empty mantissa for x") + } + if len(y.mant) == 0 { + panic("empty mantissa for y") + } +} + +// z = x + y, ignoring signs of x and y for the addition +// but using the sign of z for rounding the result. +// x and y must have a non-empty mantissa and valid exponent. +func (z *Float) uadd(x, y *Float) { + // Note: This implementation requires 2 shifts most of the + // time. It is also inefficient if exponents or precisions + // differ by wide margins. The following article describes + // an efficient (but much more complicated) implementation + // compatible with the internal representation used here: + // + // Vincent Lefèvre: "The Generic Multiple-Precision Floating- + // Point Addition With Exact Rounding (as in the MPFR Library)" + // http://www.vinc17.net/research/papers/rnc6.pdf + + if debugFloat { + validateBinaryOperands(x, y) + } + + // compute exponents ex, ey for mantissa with "binary point" + // on the right (mantissa.0) - use int64 to avoid overflow + ex := int64(x.exp) - int64(len(x.mant))*_W + ey := int64(y.exp) - int64(len(y.mant))*_W + + // TODO(gri) having a combined add-and-shift primitive + // could make this code significantly faster + switch { + case ex < ey: + // cannot re-use z.mant w/o testing for aliasing + t := nat(nil).shl(y.mant, uint(ey-ex)) + z.mant = z.mant.add(x.mant, t) + default: + // ex == ey, no shift needed + z.mant = z.mant.add(x.mant, y.mant) + case ex > ey: + // cannot re-use z.mant w/o testing for aliasing + t := nat(nil).shl(x.mant, uint(ex-ey)) + z.mant = z.mant.add(t, y.mant) + ex = ey + } + // len(z.mant) > 0 + + z.setExpAndRound(ex+int64(len(z.mant))*_W-fnorm(z.mant), 0) +} + +// z = x - y for |x| > |y|, ignoring signs of x and y for the subtraction +// but using the sign of z for rounding the result. +// x and y must have a non-empty mantissa and valid exponent. +func (z *Float) usub(x, y *Float) { + // This code is symmetric to uadd. + // We have not factored the common code out because + // eventually uadd (and usub) should be optimized + // by special-casing, and the code will diverge. + + if debugFloat { + validateBinaryOperands(x, y) + } + + ex := int64(x.exp) - int64(len(x.mant))*_W + ey := int64(y.exp) - int64(len(y.mant))*_W + + switch { + case ex < ey: + // cannot re-use z.mant w/o testing for aliasing + t := nat(nil).shl(y.mant, uint(ey-ex)) + z.mant = t.sub(x.mant, t) + default: + // ex == ey, no shift needed + z.mant = z.mant.sub(x.mant, y.mant) + case ex > ey: + // cannot re-use z.mant w/o testing for aliasing + t := nat(nil).shl(x.mant, uint(ex-ey)) + z.mant = t.sub(t, y.mant) + ex = ey + } + + // operands may have cancelled each other out + if len(z.mant) == 0 { + z.acc = Exact + z.form = zero + z.neg = false + return + } + // len(z.mant) > 0 + + z.setExpAndRound(ex+int64(len(z.mant))*_W-fnorm(z.mant), 0) +} + +// z = x * y, ignoring signs of x and y for the multiplication +// but using the sign of z for rounding the result. +// x and y must have a non-empty mantissa and valid exponent. +func (z *Float) umul(x, y *Float) { + if debugFloat { + validateBinaryOperands(x, y) + } + + // Note: This is doing too much work if the precision + // of z is less than the sum of the precisions of x + // and y which is often the case (e.g., if all floats + // have the same precision). + // TODO(gri) Optimize this for the common case. + + e := int64(x.exp) + int64(y.exp) + z.mant = z.mant.mul(x.mant, y.mant) + + z.setExpAndRound(e-fnorm(z.mant), 0) +} + +// z = x / y, ignoring signs of x and y for the division +// but using the sign of z for rounding the result. +// x and y must have a non-empty mantissa and valid exponent. +func (z *Float) uquo(x, y *Float) { + if debugFloat { + validateBinaryOperands(x, y) + } + + // mantissa length in words for desired result precision + 1 + // (at least one extra bit so we get the rounding bit after + // the division) + n := int(z.prec/_W) + 1 + + // compute adjusted x.mant such that we get enough result precision + xadj := x.mant + if d := n - len(x.mant) + len(y.mant); d > 0 { + // d extra words needed => add d "0 digits" to x + xadj = make(nat, len(x.mant)+d) + copy(xadj[d:], x.mant) + } + // TODO(gri): If we have too many digits (d < 0), we should be able + // to shorten x for faster division. But we must be extra careful + // with rounding in that case. + + // Compute d before division since there may be aliasing of x.mant + // (via xadj) or y.mant with z.mant. + d := len(xadj) - len(y.mant) + + // divide + var r nat + z.mant, r = z.mant.div(nil, xadj, y.mant) + e := int64(x.exp) - int64(y.exp) - int64(d-len(z.mant))*_W + + // The result is long enough to include (at least) the rounding bit. + // If there's a non-zero remainder, the corresponding fractional part + // (if it were computed), would have a non-zero sticky bit (if it were + // zero, it couldn't have a non-zero remainder). + var sbit uint + if len(r) > 0 { + sbit = 1 + } + + z.setExpAndRound(e-fnorm(z.mant), sbit) +} + +// ucmp returns -1, 0, or +1, depending on whether +// |x| < |y|, |x| == |y|, or |x| > |y|. +// x and y must have a non-empty mantissa and valid exponent. +func (x *Float) ucmp(y *Float) int { + if debugFloat { + validateBinaryOperands(x, y) + } + + switch { + case x.exp < y.exp: + return -1 + case x.exp > y.exp: + return +1 + } + // x.exp == y.exp + + // compare mantissas + i := len(x.mant) + j := len(y.mant) + for i > 0 || j > 0 { + var xm, ym Word + if i > 0 { + i-- + xm = x.mant[i] + } + if j > 0 { + j-- + ym = y.mant[j] + } + switch { + case xm < ym: + return -1 + case xm > ym: + return +1 + } + } + + return 0 +} + +// Handling of sign bit as defined by IEEE 754-2008, section 6.3: +// +// When neither the inputs nor result are NaN, the sign of a product or +// quotient is the exclusive OR of the operands’ signs; the sign of a sum, +// or of a difference x−y regarded as a sum x+(−y), differs from at most +// one of the addends’ signs; and the sign of the result of conversions, +// the quantize operation, the roundToIntegral operations, and the +// roundToIntegralExact (see 5.3.1) is the sign of the first or only operand. +// These rules shall apply even when operands or results are zero or infinite. +// +// When the sum of two operands with opposite signs (or the difference of +// two operands with like signs) is exactly zero, the sign of that sum (or +// difference) shall be +0 in all rounding-direction attributes except +// roundTowardNegative; under that attribute, the sign of an exact zero +// sum (or difference) shall be −0. However, x+x = x−(−x) retains the same +// sign as x even when x is zero. +// +// See also: https://play.golang.org/p/RtH3UCt5IH + +// Add sets z to the rounded sum x+y and returns z. If z's precision is 0, +// it is changed to the larger of x's or y's precision before the operation. +// Rounding is performed according to z's precision and rounding mode; and +// z's accuracy reports the result error relative to the exact (not rounded) +// result. Add panics with ErrNaN if x and y are infinities with opposite +// signs. The value of z is undefined in that case. +// +// BUG(gri) When rounding ToNegativeInf, the sign of Float values rounded to 0 is incorrect. +func (z *Float) Add(x, y *Float) *Float { + if debugFloat { + x.validate() + y.validate() + } + + if z.prec == 0 { + z.prec = umax32(x.prec, y.prec) + } + + if x.form == finite && y.form == finite { + // x + y (commom case) + z.neg = x.neg + if x.neg == y.neg { + // x + y == x + y + // (-x) + (-y) == -(x + y) + z.uadd(x, y) + } else { + // x + (-y) == x - y == -(y - x) + // (-x) + y == y - x == -(x - y) + if x.ucmp(y) > 0 { + z.usub(x, y) + } else { + z.neg = !z.neg + z.usub(y, x) + } + } + return z + } + + if x.form == inf && y.form == inf && x.neg != y.neg { + // +Inf + -Inf + // -Inf + +Inf + // value of z is undefined but make sure it's valid + z.acc = Exact + z.form = zero + z.neg = false + panic(ErrNaN{"addition of infinities with opposite signs"}) + } + + if x.form == zero && y.form == zero { + // ±0 + ±0 + z.acc = Exact + z.form = zero + z.neg = x.neg && y.neg // -0 + -0 == -0 + return z + } + + if x.form == inf || y.form == zero { + // ±Inf + y + // x + ±0 + return z.Set(x) + } + + // ±0 + y + // x + ±Inf + return z.Set(y) +} + +// Sub sets z to the rounded difference x-y and returns z. +// Precision, rounding, and accuracy reporting are as for Add. +// Sub panics with ErrNaN if x and y are infinities with equal +// signs. The value of z is undefined in that case. +func (z *Float) Sub(x, y *Float) *Float { + if debugFloat { + x.validate() + y.validate() + } + + if z.prec == 0 { + z.prec = umax32(x.prec, y.prec) + } + + if x.form == finite && y.form == finite { + // x - y (common case) + z.neg = x.neg + if x.neg != y.neg { + // x - (-y) == x + y + // (-x) - y == -(x + y) + z.uadd(x, y) + } else { + // x - y == x - y == -(y - x) + // (-x) - (-y) == y - x == -(x - y) + if x.ucmp(y) > 0 { + z.usub(x, y) + } else { + z.neg = !z.neg + z.usub(y, x) + } + } + return z + } + + if x.form == inf && y.form == inf && x.neg == y.neg { + // +Inf - +Inf + // -Inf - -Inf + // value of z is undefined but make sure it's valid + z.acc = Exact + z.form = zero + z.neg = false + panic(ErrNaN{"subtraction of infinities with equal signs"}) + } + + if x.form == zero && y.form == zero { + // ±0 - ±0 + z.acc = Exact + z.form = zero + z.neg = x.neg && !y.neg // -0 - +0 == -0 + return z + } + + if x.form == inf || y.form == zero { + // ±Inf - y + // x - ±0 + return z.Set(x) + } + + // ±0 - y + // x - ±Inf + return z.Neg(y) +} + +// Mul sets z to the rounded product x*y and returns z. +// Precision, rounding, and accuracy reporting are as for Add. +// Mul panics with ErrNaN if one operand is zero and the other +// operand an infinity. The value of z is undefined in that case. +func (z *Float) Mul(x, y *Float) *Float { + if debugFloat { + x.validate() + y.validate() + } + + if z.prec == 0 { + z.prec = umax32(x.prec, y.prec) + } + + z.neg = x.neg != y.neg + + if x.form == finite && y.form == finite { + // x * y (common case) + z.umul(x, y) + return z + } + + z.acc = Exact + if x.form == zero && y.form == inf || x.form == inf && y.form == zero { + // ±0 * ±Inf + // ±Inf * ±0 + // value of z is undefined but make sure it's valid + z.form = zero + z.neg = false + panic(ErrNaN{"multiplication of zero with infinity"}) + } + + if x.form == inf || y.form == inf { + // ±Inf * y + // x * ±Inf + z.form = inf + return z + } + + // ±0 * y + // x * ±0 + z.form = zero + return z +} + +// Quo sets z to the rounded quotient x/y and returns z. +// Precision, rounding, and accuracy reporting are as for Add. +// Quo panics with ErrNaN if both operands are zero or infinities. +// The value of z is undefined in that case. +func (z *Float) Quo(x, y *Float) *Float { + if debugFloat { + x.validate() + y.validate() + } + + if z.prec == 0 { + z.prec = umax32(x.prec, y.prec) + } + + z.neg = x.neg != y.neg + + if x.form == finite && y.form == finite { + // x / y (common case) + z.uquo(x, y) + return z + } + + z.acc = Exact + if x.form == zero && y.form == zero || x.form == inf && y.form == inf { + // ±0 / ±0 + // ±Inf / ±Inf + // value of z is undefined but make sure it's valid + z.form = zero + z.neg = false + panic(ErrNaN{"division of zero by zero or infinity by infinity"}) + } + + if x.form == zero || y.form == inf { + // ±0 / y + // x / ±Inf + z.form = zero + return z + } + + // x / ±0 + // ±Inf / y + z.form = inf + return z +} + +// Cmp compares x and y and returns: +// +// -1 if x < y +// 0 if x == y (incl. -0 == 0, -Inf == -Inf, and +Inf == +Inf) +// +1 if x > y +// +func (x *Float) Cmp(y *Float) int { + if debugFloat { + x.validate() + y.validate() + } + + mx := x.ord() + my := y.ord() + switch { + case mx < my: + return -1 + case mx > my: + return +1 + } + // mx == my + + // only if |mx| == 1 we have to compare the mantissae + switch mx { + case -1: + return y.ucmp(x) + case +1: + return x.ucmp(y) + } + + return 0 +} + +// ord classifies x and returns: +// +// -2 if -Inf == x +// -1 if -Inf < x < 0 +// 0 if x == 0 (signed or unsigned) +// +1 if 0 < x < +Inf +// +2 if x == +Inf +// +func (x *Float) ord() int { + var m int + switch x.form { + case finite: + m = 1 + case zero: + return 0 + case inf: + m = 2 + } + if x.neg { + m = -m + } + return m +} + +func umax32(x, y uint32) uint32 { + if x > y { + return x + } + return y +} diff --git a/libgo/go/math/big/float_test.go b/libgo/go/math/big/float_test.go new file mode 100644 index 00000000000..d3b214b631d --- /dev/null +++ b/libgo/go/math/big/float_test.go @@ -0,0 +1,1694 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package big + +import ( + "fmt" + "math" + "strconv" + "strings" + "testing" +) + +// Verify that ErrNaN implements the error interface. +var _ error = ErrNaN{} + +func (x *Float) uint64() uint64 { + u, acc := x.Uint64() + if acc != Exact { + panic(fmt.Sprintf("%s is not a uint64", x.Text('g', 10))) + } + return u +} + +func (x *Float) int64() int64 { + i, acc := x.Int64() + if acc != Exact { + panic(fmt.Sprintf("%s is not an int64", x.Text('g', 10))) + } + return i +} + +func TestFloatZeroValue(t *testing.T) { + // zero (uninitialized) value is a ready-to-use 0.0 + var x Float + if s := x.Text('f', 1); s != "0.0" { + t.Errorf("zero value = %s; want 0.0", s) + } + + // zero value has precision 0 + if prec := x.Prec(); prec != 0 { + t.Errorf("prec = %d; want 0", prec) + } + + // zero value can be used in any and all positions of binary operations + make := func(x int) *Float { + var f Float + if x != 0 { + f.SetInt64(int64(x)) + } + // x == 0 translates into the zero value + return &f + } + for _, test := range []struct { + z, x, y, want int + opname rune + op func(z, x, y *Float) *Float + }{ + {0, 0, 0, 0, '+', (*Float).Add}, + {0, 1, 2, 3, '+', (*Float).Add}, + {1, 2, 0, 2, '+', (*Float).Add}, + {2, 0, 1, 1, '+', (*Float).Add}, + + {0, 0, 0, 0, '-', (*Float).Sub}, + {0, 1, 2, -1, '-', (*Float).Sub}, + {1, 2, 0, 2, '-', (*Float).Sub}, + {2, 0, 1, -1, '-', (*Float).Sub}, + + {0, 0, 0, 0, '*', (*Float).Mul}, + {0, 1, 2, 2, '*', (*Float).Mul}, + {1, 2, 0, 0, '*', (*Float).Mul}, + {2, 0, 1, 0, '*', (*Float).Mul}, + + // {0, 0, 0, 0, '/', (*Float).Quo}, // panics + {0, 2, 1, 2, '/', (*Float).Quo}, + {1, 2, 0, 0, '/', (*Float).Quo}, // = +Inf + {2, 0, 1, 0, '/', (*Float).Quo}, + } { + z := make(test.z) + test.op(z, make(test.x), make(test.y)) + got := 0 + if !z.IsInf() { + got = int(z.int64()) + } + if got != test.want { + t.Errorf("%d %c %d = %d; want %d", test.x, test.opname, test.y, got, test.want) + } + } + + // TODO(gri) test how precision is set for zero value results +} + +func makeFloat(s string) *Float { + x, _, err := ParseFloat(s, 0, 1000, ToNearestEven) + if err != nil { + panic(err) + } + return x +} + +func TestFloatSetPrec(t *testing.T) { + for _, test := range []struct { + x string + prec uint + want string + acc Accuracy + }{ + // prec 0 + {"0", 0, "0", Exact}, + {"-0", 0, "-0", Exact}, + {"-Inf", 0, "-Inf", Exact}, + {"+Inf", 0, "+Inf", Exact}, + {"123", 0, "0", Below}, + {"-123", 0, "-0", Above}, + + // prec at upper limit + {"0", MaxPrec, "0", Exact}, + {"-0", MaxPrec, "-0", Exact}, + {"-Inf", MaxPrec, "-Inf", Exact}, + {"+Inf", MaxPrec, "+Inf", Exact}, + + // just a few regular cases - general rounding is tested elsewhere + {"1.5", 1, "2", Above}, + {"-1.5", 1, "-2", Below}, + {"123", 1e6, "123", Exact}, + {"-123", 1e6, "-123", Exact}, + } { + x := makeFloat(test.x).SetPrec(test.prec) + prec := test.prec + if prec > MaxPrec { + prec = MaxPrec + } + if got := x.Prec(); got != prec { + t.Errorf("%s.SetPrec(%d).Prec() == %d; want %d", test.x, test.prec, got, prec) + } + if got, acc := x.String(), x.Acc(); got != test.want || acc != test.acc { + t.Errorf("%s.SetPrec(%d) = %s (%s); want %s (%s)", test.x, test.prec, got, acc, test.want, test.acc) + } + } +} + +func TestFloatMinPrec(t *testing.T) { + const max = 100 + for _, test := range []struct { + x string + want uint + }{ + {"0", 0}, + {"-0", 0}, + {"+Inf", 0}, + {"-Inf", 0}, + {"1", 1}, + {"2", 1}, + {"3", 2}, + {"0x8001", 16}, + {"0x8001p-1000", 16}, + {"0x8001p+1000", 16}, + {"0.1", max}, + } { + x := makeFloat(test.x).SetPrec(max) + if got := x.MinPrec(); got != test.want { + t.Errorf("%s.MinPrec() = %d; want %d", test.x, got, test.want) + } + } +} + +func TestFloatSign(t *testing.T) { + for _, test := range []struct { + x string + s int + }{ + {"-Inf", -1}, + {"-1", -1}, + {"-0", 0}, + {"+0", 0}, + {"+1", +1}, + {"+Inf", +1}, + } { + x := makeFloat(test.x) + s := x.Sign() + if s != test.s { + t.Errorf("%s.Sign() = %d; want %d", test.x, s, test.s) + } + } +} + +// alike(x, y) is like x.Cmp(y) == 0 but also considers the sign of 0 (0 != -0). +func alike(x, y *Float) bool { + return x.Cmp(y) == 0 && x.Signbit() == y.Signbit() +} + +func alike32(x, y float32) bool { + // we can ignore NaNs + return x == y && math.Signbit(float64(x)) == math.Signbit(float64(y)) + +} + +func alike64(x, y float64) bool { + // we can ignore NaNs + return x == y && math.Signbit(x) == math.Signbit(y) + +} + +func TestFloatMantExp(t *testing.T) { + for _, test := range []struct { + x string + mant string + exp int + }{ + {"0", "0", 0}, + {"+0", "0", 0}, + {"-0", "-0", 0}, + {"Inf", "+Inf", 0}, + {"+Inf", "+Inf", 0}, + {"-Inf", "-Inf", 0}, + {"1.5", "0.75", 1}, + {"1.024e3", "0.5", 11}, + {"-0.125", "-0.5", -2}, + } { + x := makeFloat(test.x) + mant := makeFloat(test.mant) + m := new(Float) + e := x.MantExp(m) + if !alike(m, mant) || e != test.exp { + t.Errorf("%s.MantExp() = %s, %d; want %s, %d", test.x, m.Text('g', 10), e, test.mant, test.exp) + } + } +} + +func TestFloatMantExpAliasing(t *testing.T) { + x := makeFloat("0.5p10") + if e := x.MantExp(x); e != 10 { + t.Fatalf("Float.MantExp aliasing error: got %d; want 10", e) + } + if want := makeFloat("0.5"); !alike(x, want) { + t.Fatalf("Float.MantExp aliasing error: got %s; want %s", x.Text('g', 10), want.Text('g', 10)) + } +} + +func TestFloatSetMantExp(t *testing.T) { + for _, test := range []struct { + frac string + exp int + z string + }{ + {"0", 0, "0"}, + {"+0", 0, "0"}, + {"-0", 0, "-0"}, + {"Inf", 1234, "+Inf"}, + {"+Inf", -1234, "+Inf"}, + {"-Inf", -1234, "-Inf"}, + {"0", MinExp, "0"}, + {"0.25", MinExp, "+0"}, // exponent underflow + {"-0.25", MinExp, "-0"}, // exponent underflow + {"1", MaxExp, "+Inf"}, // exponent overflow + {"2", MaxExp - 1, "+Inf"}, // exponent overflow + {"0.75", 1, "1.5"}, + {"0.5", 11, "1024"}, + {"-0.5", -2, "-0.125"}, + {"32", 5, "1024"}, + {"1024", -10, "1"}, + } { + frac := makeFloat(test.frac) + want := makeFloat(test.z) + var z Float + z.SetMantExp(frac, test.exp) + if !alike(&z, want) { + t.Errorf("SetMantExp(%s, %d) = %s; want %s", test.frac, test.exp, z.Text('g', 10), test.z) + } + // test inverse property + mant := new(Float) + if z.SetMantExp(mant, want.MantExp(mant)).Cmp(want) != 0 { + t.Errorf("Inverse property not satisfied: got %s; want %s", z.Text('g', 10), test.z) + } + } +} + +func TestFloatPredicates(t *testing.T) { + for _, test := range []struct { + x string + sign int + signbit, inf bool + }{ + {x: "-Inf", sign: -1, signbit: true, inf: true}, + {x: "-1", sign: -1, signbit: true}, + {x: "-0", signbit: true}, + {x: "0"}, + {x: "1", sign: 1}, + {x: "+Inf", sign: 1, inf: true}, + } { + x := makeFloat(test.x) + if got := x.Signbit(); got != test.signbit { + t.Errorf("(%s).Signbit() = %v; want %v", test.x, got, test.signbit) + } + if got := x.Sign(); got != test.sign { + t.Errorf("(%s).Sign() = %d; want %d", test.x, got, test.sign) + } + if got := x.IsInf(); got != test.inf { + t.Errorf("(%s).IsInf() = %v; want %v", test.x, got, test.inf) + } + } +} + +func TestFloatIsInt(t *testing.T) { + for _, test := range []string{ + "0 int", + "-0 int", + "1 int", + "-1 int", + "0.5", + "1.23", + "1.23e1", + "1.23e2 int", + "0.000000001e+8", + "0.000000001e+9 int", + "1.2345e200 int", + "Inf", + "+Inf", + "-Inf", + } { + s := strings.TrimSuffix(test, " int") + want := s != test + if got := makeFloat(s).IsInt(); got != want { + t.Errorf("%s.IsInt() == %t", s, got) + } + } +} + +func fromBinary(s string) int64 { + x, err := strconv.ParseInt(s, 2, 64) + if err != nil { + panic(err) + } + return x +} + +func toBinary(x int64) string { + return strconv.FormatInt(x, 2) +} + +func testFloatRound(t *testing.T, x, r int64, prec uint, mode RoundingMode) { + // verify test data + var ok bool + switch mode { + case ToNearestEven, ToNearestAway: + ok = true // nothing to do for now + case ToZero: + if x < 0 { + ok = r >= x + } else { + ok = r <= x + } + case AwayFromZero: + if x < 0 { + ok = r <= x + } else { + ok = r >= x + } + case ToNegativeInf: + ok = r <= x + case ToPositiveInf: + ok = r >= x + default: + panic("unreachable") + } + if !ok { + t.Fatalf("incorrect test data for prec = %d, %s: x = %s, r = %s", prec, mode, toBinary(x), toBinary(r)) + } + + // compute expected accuracy + a := Exact + switch { + case r < x: + a = Below + case r > x: + a = Above + } + + // round + f := new(Float).SetMode(mode).SetInt64(x).SetPrec(prec) + + // check result + r1 := f.int64() + p1 := f.Prec() + a1 := f.Acc() + if r1 != r || p1 != prec || a1 != a { + t.Errorf("round %s (%d bits, %s) incorrect: got %s (%d bits, %s); want %s (%d bits, %s)", + toBinary(x), prec, mode, + toBinary(r1), p1, a1, + toBinary(r), prec, a) + return + } + + // g and f should be the same + // (rounding by SetPrec after SetInt64 using default precision + // should be the same as rounding by SetInt64 after setting the + // precision) + g := new(Float).SetMode(mode).SetPrec(prec).SetInt64(x) + if !alike(g, f) { + t.Errorf("round %s (%d bits, %s) not symmetric: got %s and %s; want %s", + toBinary(x), prec, mode, + toBinary(g.int64()), + toBinary(r1), + toBinary(r), + ) + return + } + + // h and f should be the same + // (repeated rounding should be idempotent) + h := new(Float).SetMode(mode).SetPrec(prec).Set(f) + if !alike(h, f) { + t.Errorf("round %s (%d bits, %s) not idempotent: got %s and %s; want %s", + toBinary(x), prec, mode, + toBinary(h.int64()), + toBinary(r1), + toBinary(r), + ) + return + } +} + +// TestFloatRound tests basic rounding. +func TestFloatRound(t *testing.T) { + for _, test := range []struct { + prec uint + x, zero, neven, naway, away string // input, results rounded to prec bits + }{ + {5, "1000", "1000", "1000", "1000", "1000"}, + {5, "1001", "1001", "1001", "1001", "1001"}, + {5, "1010", "1010", "1010", "1010", "1010"}, + {5, "1011", "1011", "1011", "1011", "1011"}, + {5, "1100", "1100", "1100", "1100", "1100"}, + {5, "1101", "1101", "1101", "1101", "1101"}, + {5, "1110", "1110", "1110", "1110", "1110"}, + {5, "1111", "1111", "1111", "1111", "1111"}, + + {4, "1000", "1000", "1000", "1000", "1000"}, + {4, "1001", "1001", "1001", "1001", "1001"}, + {4, "1010", "1010", "1010", "1010", "1010"}, + {4, "1011", "1011", "1011", "1011", "1011"}, + {4, "1100", "1100", "1100", "1100", "1100"}, + {4, "1101", "1101", "1101", "1101", "1101"}, + {4, "1110", "1110", "1110", "1110", "1110"}, + {4, "1111", "1111", "1111", "1111", "1111"}, + + {3, "1000", "1000", "1000", "1000", "1000"}, + {3, "1001", "1000", "1000", "1010", "1010"}, + {3, "1010", "1010", "1010", "1010", "1010"}, + {3, "1011", "1010", "1100", "1100", "1100"}, + {3, "1100", "1100", "1100", "1100", "1100"}, + {3, "1101", "1100", "1100", "1110", "1110"}, + {3, "1110", "1110", "1110", "1110", "1110"}, + {3, "1111", "1110", "10000", "10000", "10000"}, + + {3, "1000001", "1000000", "1000000", "1000000", "1010000"}, + {3, "1001001", "1000000", "1010000", "1010000", "1010000"}, + {3, "1010001", "1010000", "1010000", "1010000", "1100000"}, + {3, "1011001", "1010000", "1100000", "1100000", "1100000"}, + {3, "1100001", "1100000", "1100000", "1100000", "1110000"}, + {3, "1101001", "1100000", "1110000", "1110000", "1110000"}, + {3, "1110001", "1110000", "1110000", "1110000", "10000000"}, + {3, "1111001", "1110000", "10000000", "10000000", "10000000"}, + + {2, "1000", "1000", "1000", "1000", "1000"}, + {2, "1001", "1000", "1000", "1000", "1100"}, + {2, "1010", "1000", "1000", "1100", "1100"}, + {2, "1011", "1000", "1100", "1100", "1100"}, + {2, "1100", "1100", "1100", "1100", "1100"}, + {2, "1101", "1100", "1100", "1100", "10000"}, + {2, "1110", "1100", "10000", "10000", "10000"}, + {2, "1111", "1100", "10000", "10000", "10000"}, + + {2, "1000001", "1000000", "1000000", "1000000", "1100000"}, + {2, "1001001", "1000000", "1000000", "1000000", "1100000"}, + {2, "1010001", "1000000", "1100000", "1100000", "1100000"}, + {2, "1011001", "1000000", "1100000", "1100000", "1100000"}, + {2, "1100001", "1100000", "1100000", "1100000", "10000000"}, + {2, "1101001", "1100000", "1100000", "1100000", "10000000"}, + {2, "1110001", "1100000", "10000000", "10000000", "10000000"}, + {2, "1111001", "1100000", "10000000", "10000000", "10000000"}, + + {1, "1000", "1000", "1000", "1000", "1000"}, + {1, "1001", "1000", "1000", "1000", "10000"}, + {1, "1010", "1000", "1000", "1000", "10000"}, + {1, "1011", "1000", "1000", "1000", "10000"}, + {1, "1100", "1000", "10000", "10000", "10000"}, + {1, "1101", "1000", "10000", "10000", "10000"}, + {1, "1110", "1000", "10000", "10000", "10000"}, + {1, "1111", "1000", "10000", "10000", "10000"}, + + {1, "1000001", "1000000", "1000000", "1000000", "10000000"}, + {1, "1001001", "1000000", "1000000", "1000000", "10000000"}, + {1, "1010001", "1000000", "1000000", "1000000", "10000000"}, + {1, "1011001", "1000000", "1000000", "1000000", "10000000"}, + {1, "1100001", "1000000", "10000000", "10000000", "10000000"}, + {1, "1101001", "1000000", "10000000", "10000000", "10000000"}, + {1, "1110001", "1000000", "10000000", "10000000", "10000000"}, + {1, "1111001", "1000000", "10000000", "10000000", "10000000"}, + } { + x := fromBinary(test.x) + z := fromBinary(test.zero) + e := fromBinary(test.neven) + n := fromBinary(test.naway) + a := fromBinary(test.away) + prec := test.prec + + testFloatRound(t, x, z, prec, ToZero) + testFloatRound(t, x, e, prec, ToNearestEven) + testFloatRound(t, x, n, prec, ToNearestAway) + testFloatRound(t, x, a, prec, AwayFromZero) + + testFloatRound(t, x, z, prec, ToNegativeInf) + testFloatRound(t, x, a, prec, ToPositiveInf) + + testFloatRound(t, -x, -a, prec, ToNegativeInf) + testFloatRound(t, -x, -z, prec, ToPositiveInf) + } +} + +// TestFloatRound24 tests that rounding a float64 to 24 bits +// matches IEEE-754 rounding to nearest when converting a +// float64 to a float32 (excluding denormal numbers). +func TestFloatRound24(t *testing.T) { + const x0 = 1<<26 - 0x10 // 11...110000 (26 bits) + for d := 0; d <= 0x10; d++ { + x := float64(x0 + d) + f := new(Float).SetPrec(24).SetFloat64(x) + got, _ := f.Float32() + want := float32(x) + if got != want { + t.Errorf("Round(%g, 24) = %g; want %g", x, got, want) + } + } +} + +func TestFloatSetUint64(t *testing.T) { + for _, want := range []uint64{ + 0, + 1, + 2, + 10, + 100, + 1<<32 - 1, + 1 << 32, + 1<<64 - 1, + } { + var f Float + f.SetUint64(want) + if got := f.uint64(); got != want { + t.Errorf("got %#x (%s); want %#x", got, f.Text('p', 0), want) + } + } + + // test basic rounding behavior (exhaustive rounding testing is done elsewhere) + const x uint64 = 0x8765432187654321 // 64 bits needed + for prec := uint(1); prec <= 64; prec++ { + f := new(Float).SetPrec(prec).SetMode(ToZero).SetUint64(x) + got := f.uint64() + want := x &^ (1<<(64-prec) - 1) // cut off (round to zero) low 64-prec bits + if got != want { + t.Errorf("got %#x (%s); want %#x", got, f.Text('p', 0), want) + } + } +} + +func TestFloatSetInt64(t *testing.T) { + for _, want := range []int64{ + 0, + 1, + 2, + 10, + 100, + 1<<32 - 1, + 1 << 32, + 1<<63 - 1, + } { + for i := range [2]int{} { + if i&1 != 0 { + want = -want + } + var f Float + f.SetInt64(want) + if got := f.int64(); got != want { + t.Errorf("got %#x (%s); want %#x", got, f.Text('p', 0), want) + } + } + } + + // test basic rounding behavior (exhaustive rounding testing is done elsewhere) + const x int64 = 0x7654321076543210 // 63 bits needed + for prec := uint(1); prec <= 63; prec++ { + f := new(Float).SetPrec(prec).SetMode(ToZero).SetInt64(x) + got := f.int64() + want := x &^ (1<<(63-prec) - 1) // cut off (round to zero) low 63-prec bits + if got != want { + t.Errorf("got %#x (%s); want %#x", got, f.Text('p', 0), want) + } + } +} + +func TestFloatSetFloat64(t *testing.T) { + for _, want := range []float64{ + 0, + 1, + 2, + 12345, + 1e10, + 1e100, + 3.14159265e10, + 2.718281828e-123, + 1.0 / 3, + math.MaxFloat32, + math.MaxFloat64, + math.SmallestNonzeroFloat32, + math.SmallestNonzeroFloat64, + math.Inf(-1), + math.Inf(0), + -math.Inf(1), + } { + for i := range [2]int{} { + if i&1 != 0 { + want = -want + } + var f Float + f.SetFloat64(want) + if got, acc := f.Float64(); got != want || acc != Exact { + t.Errorf("got %g (%s, %s); want %g (Exact)", got, f.Text('p', 0), acc, want) + } + } + } + + // test basic rounding behavior (exhaustive rounding testing is done elsewhere) + const x uint64 = 0x8765432143218 // 53 bits needed + for prec := uint(1); prec <= 52; prec++ { + f := new(Float).SetPrec(prec).SetMode(ToZero).SetFloat64(float64(x)) + got, _ := f.Float64() + want := float64(x &^ (1<<(52-prec) - 1)) // cut off (round to zero) low 53-prec bits + if got != want { + t.Errorf("got %g (%s); want %g", got, f.Text('p', 0), want) + } + } + + // test NaN + defer func() { + if p, ok := recover().(ErrNaN); !ok { + t.Errorf("got %v; want ErrNaN panic", p) + } + }() + var f Float + f.SetFloat64(math.NaN()) + // should not reach here + t.Errorf("got %s; want ErrNaN panic", f.Text('p', 0)) +} + +func TestFloatSetInt(t *testing.T) { + for _, want := range []string{ + "0", + "1", + "-1", + "1234567890", + "123456789012345678901234567890", + "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", + } { + var x Int + _, ok := x.SetString(want, 0) + if !ok { + t.Errorf("invalid integer %s", want) + continue + } + n := x.BitLen() + + var f Float + f.SetInt(&x) + + // check precision + if n < 64 { + n = 64 + } + if prec := f.Prec(); prec != uint(n) { + t.Errorf("got prec = %d; want %d", prec, n) + } + + // check value + got := f.Text('g', 100) + if got != want { + t.Errorf("got %s (%s); want %s", got, f.Text('p', 0), want) + } + } + + // TODO(gri) test basic rounding behavior +} + +func TestFloatSetRat(t *testing.T) { + for _, want := range []string{ + "0", + "1", + "-1", + "1234567890", + "123456789012345678901234567890", + "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", + "1.2", + "3.14159265", + // TODO(gri) expand + } { + var x Rat + _, ok := x.SetString(want) + if !ok { + t.Errorf("invalid fraction %s", want) + continue + } + n := max(x.Num().BitLen(), x.Denom().BitLen()) + + var f1, f2 Float + f2.SetPrec(1000) + f1.SetRat(&x) + f2.SetRat(&x) + + // check precision when set automatically + if n < 64 { + n = 64 + } + if prec := f1.Prec(); prec != uint(n) { + t.Errorf("got prec = %d; want %d", prec, n) + } + + got := f2.Text('g', 100) + if got != want { + t.Errorf("got %s (%s); want %s", got, f2.Text('p', 0), want) + } + } +} + +func TestFloatSetInf(t *testing.T) { + var f Float + for _, test := range []struct { + signbit bool + prec uint + want string + }{ + {false, 0, "+Inf"}, + {true, 0, "-Inf"}, + {false, 10, "+Inf"}, + {true, 30, "-Inf"}, + } { + x := f.SetPrec(test.prec).SetInf(test.signbit) + if got := x.String(); got != test.want || x.Prec() != test.prec { + t.Errorf("SetInf(%v) = %s (prec = %d); want %s (prec = %d)", test.signbit, got, x.Prec(), test.want, test.prec) + } + } +} + +func TestFloatUint64(t *testing.T) { + for _, test := range []struct { + x string + out uint64 + acc Accuracy + }{ + {"-Inf", 0, Above}, + {"-1", 0, Above}, + {"-1e-1000", 0, Above}, + {"-0", 0, Exact}, + {"0", 0, Exact}, + {"1e-1000", 0, Below}, + {"1", 1, Exact}, + {"1.000000000000000000001", 1, Below}, + {"12345.0", 12345, Exact}, + {"12345.000000000000000000001", 12345, Below}, + {"18446744073709551615", 18446744073709551615, Exact}, + {"18446744073709551615.000000000000000000001", math.MaxUint64, Below}, + {"18446744073709551616", math.MaxUint64, Below}, + {"1e10000", math.MaxUint64, Below}, + {"+Inf", math.MaxUint64, Below}, + } { + x := makeFloat(test.x) + out, acc := x.Uint64() + if out != test.out || acc != test.acc { + t.Errorf("%s: got %d (%s); want %d (%s)", test.x, out, acc, test.out, test.acc) + } + } +} + +func TestFloatInt64(t *testing.T) { + for _, test := range []struct { + x string + out int64 + acc Accuracy + }{ + {"-Inf", math.MinInt64, Above}, + {"-1e10000", math.MinInt64, Above}, + {"-9223372036854775809", math.MinInt64, Above}, + {"-9223372036854775808.000000000000000000001", math.MinInt64, Above}, + {"-9223372036854775808", -9223372036854775808, Exact}, + {"-9223372036854775807.000000000000000000001", -9223372036854775807, Above}, + {"-9223372036854775807", -9223372036854775807, Exact}, + {"-12345.000000000000000000001", -12345, Above}, + {"-12345.0", -12345, Exact}, + {"-1.000000000000000000001", -1, Above}, + {"-1.5", -1, Above}, + {"-1", -1, Exact}, + {"-1e-1000", 0, Above}, + {"0", 0, Exact}, + {"1e-1000", 0, Below}, + {"1", 1, Exact}, + {"1.000000000000000000001", 1, Below}, + {"1.5", 1, Below}, + {"12345.0", 12345, Exact}, + {"12345.000000000000000000001", 12345, Below}, + {"9223372036854775807", 9223372036854775807, Exact}, + {"9223372036854775807.000000000000000000001", math.MaxInt64, Below}, + {"9223372036854775808", math.MaxInt64, Below}, + {"1e10000", math.MaxInt64, Below}, + {"+Inf", math.MaxInt64, Below}, + } { + x := makeFloat(test.x) + out, acc := x.Int64() + if out != test.out || acc != test.acc { + t.Errorf("%s: got %d (%s); want %d (%s)", test.x, out, acc, test.out, test.acc) + } + } +} + +func TestFloatFloat32(t *testing.T) { + for _, test := range []struct { + x string + out float32 + acc Accuracy + }{ + {"0", 0, Exact}, + + // underflow + {"1e-1000", 0, Below}, + {"0x0.000002p-127", 0, Below}, + {"0x.0000010p-126", 0, Below}, + + // denormals + {"1.401298464e-45", math.SmallestNonzeroFloat32, Above}, // rounded up to smallest denormal + {"0x.ffffff8p-149", math.SmallestNonzeroFloat32, Above}, // rounded up to smallest denormal + {"0x.0000018p-126", math.SmallestNonzeroFloat32, Above}, // rounded up to smallest denormal + {"0x.0000020p-126", math.SmallestNonzeroFloat32, Exact}, + {"0x.8p-148", math.SmallestNonzeroFloat32, Exact}, + {"1p-149", math.SmallestNonzeroFloat32, Exact}, + {"0x.fffffep-126", math.Float32frombits(0x7fffff), Exact}, // largest denormal + + // normals + {"0x.ffffffp-126", math.Float32frombits(0x00800000), Above}, // rounded up to smallest normal + {"1p-126", math.Float32frombits(0x00800000), Exact}, // smallest normal + {"0x1.fffffep-126", math.Float32frombits(0x00ffffff), Exact}, + {"0x1.ffffffp-126", math.Float32frombits(0x01000000), Above}, // rounded up + {"1", 1, Exact}, + {"1.000000000000000000001", 1, Below}, + {"12345.0", 12345, Exact}, + {"12345.000000000000000000001", 12345, Below}, + {"0x1.fffffe0p127", math.MaxFloat32, Exact}, + {"0x1.fffffe8p127", math.MaxFloat32, Below}, + + // overflow + {"0x1.ffffff0p127", float32(math.Inf(+1)), Above}, + {"0x1p128", float32(math.Inf(+1)), Above}, + {"1e10000", float32(math.Inf(+1)), Above}, + {"0x1.ffffff0p2147483646", float32(math.Inf(+1)), Above}, // overflow in rounding + + // inf + {"Inf", float32(math.Inf(+1)), Exact}, + } { + for i := 0; i < 2; i++ { + // test both signs + tx, tout, tacc := test.x, test.out, test.acc + if i != 0 { + tx = "-" + tx + tout = -tout + tacc = -tacc + } + + // conversion should match strconv where syntax is agreeable + if f, err := strconv.ParseFloat(tx, 32); err == nil && !alike32(float32(f), tout) { + t.Errorf("%s: got %g; want %g (incorrect test data)", tx, f, tout) + } + + x := makeFloat(tx) + out, acc := x.Float32() + if !alike32(out, tout) || acc != tacc { + t.Errorf("%s: got %g (%#x, %s); want %g (%#x, %s)", tx, out, math.Float32bits(out), acc, test.out, math.Float32bits(test.out), tacc) + } + + // test that x.SetFloat64(float64(f)).Float32() == f + var x2 Float + out2, acc2 := x2.SetFloat64(float64(out)).Float32() + if !alike32(out2, out) || acc2 != Exact { + t.Errorf("idempotency test: got %g (%s); want %g (Exact)", out2, acc2, out) + } + } + } +} + +func TestFloatFloat64(t *testing.T) { + const smallestNormalFloat64 = 2.2250738585072014e-308 // 1p-1022 + for _, test := range []struct { + x string + out float64 + acc Accuracy + }{ + {"0", 0, Exact}, + + // underflow + {"1e-1000", 0, Below}, + {"0x0.0000000000001p-1023", 0, Below}, + {"0x0.00000000000008p-1022", 0, Below}, + + // denormals + {"0x0.0000000000000cp-1022", math.SmallestNonzeroFloat64, Above}, // rounded up to smallest denormal + {"0x0.0000000000001p-1022", math.SmallestNonzeroFloat64, Exact}, // smallest denormal + {"0x.8p-1073", math.SmallestNonzeroFloat64, Exact}, + {"1p-1074", math.SmallestNonzeroFloat64, Exact}, + {"0x.fffffffffffffp-1022", math.Float64frombits(0x000fffffffffffff), Exact}, // largest denormal + + // normals + {"0x.fffffffffffff8p-1022", math.Float64frombits(0x0010000000000000), Above}, // rounded up to smallest normal + {"1p-1022", math.Float64frombits(0x0010000000000000), Exact}, // smallest normal + {"1", 1, Exact}, + {"1.000000000000000000001", 1, Below}, + {"12345.0", 12345, Exact}, + {"12345.000000000000000000001", 12345, Below}, + {"0x1.fffffffffffff0p1023", math.MaxFloat64, Exact}, + {"0x1.fffffffffffff4p1023", math.MaxFloat64, Below}, + + // overflow + {"0x1.fffffffffffff8p1023", math.Inf(+1), Above}, + {"0x1p1024", math.Inf(+1), Above}, + {"1e10000", math.Inf(+1), Above}, + {"0x1.fffffffffffff8p2147483646", math.Inf(+1), Above}, // overflow in rounding + {"Inf", math.Inf(+1), Exact}, + + // selected denormalized values that were handled incorrectly in the past + {"0x.fffffffffffffp-1022", smallestNormalFloat64 - math.SmallestNonzeroFloat64, Exact}, + {"4503599627370495p-1074", smallestNormalFloat64 - math.SmallestNonzeroFloat64, Exact}, + + // http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/ + {"2.2250738585072011e-308", 2.225073858507201e-308, Below}, + // http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/ + {"2.2250738585072012e-308", 2.2250738585072014e-308, Above}, + } { + for i := 0; i < 2; i++ { + // test both signs + tx, tout, tacc := test.x, test.out, test.acc + if i != 0 { + tx = "-" + tx + tout = -tout + tacc = -tacc + } + + // conversion should match strconv where syntax is agreeable + if f, err := strconv.ParseFloat(tx, 64); err == nil && !alike64(f, tout) { + t.Errorf("%s: got %g; want %g (incorrect test data)", tx, f, tout) + } + + x := makeFloat(tx) + out, acc := x.Float64() + if !alike64(out, tout) || acc != tacc { + t.Errorf("%s: got %g (%#x, %s); want %g (%#x, %s)", tx, out, math.Float64bits(out), acc, test.out, math.Float64bits(test.out), tacc) + } + + // test that x.SetFloat64(f).Float64() == f + var x2 Float + out2, acc2 := x2.SetFloat64(out).Float64() + if !alike64(out2, out) || acc2 != Exact { + t.Errorf("idempotency test: got %g (%s); want %g (Exact)", out2, acc2, out) + } + } + } +} + +func TestFloatInt(t *testing.T) { + for _, test := range []struct { + x string + want string + acc Accuracy + }{ + {"0", "0", Exact}, + {"+0", "0", Exact}, + {"-0", "0", Exact}, + {"Inf", "nil", Below}, + {"+Inf", "nil", Below}, + {"-Inf", "nil", Above}, + {"1", "1", Exact}, + {"-1", "-1", Exact}, + {"1.23", "1", Below}, + {"-1.23", "-1", Above}, + {"123e-2", "1", Below}, + {"123e-3", "0", Below}, + {"123e-4", "0", Below}, + {"1e-1000", "0", Below}, + {"-1e-1000", "0", Above}, + {"1e+10", "10000000000", Exact}, + {"1e+100", "10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", Exact}, + } { + x := makeFloat(test.x) + res, acc := x.Int(nil) + got := "nil" + if res != nil { + got = res.String() + } + if got != test.want || acc != test.acc { + t.Errorf("%s: got %s (%s); want %s (%s)", test.x, got, acc, test.want, test.acc) + } + } + + // check that supplied *Int is used + for _, f := range []string{"0", "1", "-1", "1234"} { + x := makeFloat(f) + i := new(Int) + if res, _ := x.Int(i); res != i { + t.Errorf("(%s).Int is not using supplied *Int", f) + } + } +} + +func TestFloatRat(t *testing.T) { + for _, test := range []struct { + x, want string + acc Accuracy + }{ + {"0", "0/1", Exact}, + {"+0", "0/1", Exact}, + {"-0", "0/1", Exact}, + {"Inf", "nil", Below}, + {"+Inf", "nil", Below}, + {"-Inf", "nil", Above}, + {"1", "1/1", Exact}, + {"-1", "-1/1", Exact}, + {"1.25", "5/4", Exact}, + {"-1.25", "-5/4", Exact}, + {"1e10", "10000000000/1", Exact}, + {"1p10", "1024/1", Exact}, + {"-1p-10", "-1/1024", Exact}, + {"3.14159265", "7244019449799623199/2305843009213693952", Exact}, + } { + x := makeFloat(test.x).SetPrec(64) + res, acc := x.Rat(nil) + got := "nil" + if res != nil { + got = res.String() + } + if got != test.want { + t.Errorf("%s: got %s; want %s", test.x, got, test.want) + continue + } + if acc != test.acc { + t.Errorf("%s: got %s; want %s", test.x, acc, test.acc) + continue + } + + // inverse conversion + if res != nil { + got := new(Float).SetPrec(64).SetRat(res) + if got.Cmp(x) != 0 { + t.Errorf("%s: got %s; want %s", test.x, got, x) + } + } + } + + // check that supplied *Rat is used + for _, f := range []string{"0", "1", "-1", "1234"} { + x := makeFloat(f) + r := new(Rat) + if res, _ := x.Rat(r); res != r { + t.Errorf("(%s).Rat is not using supplied *Rat", f) + } + } +} + +func TestFloatAbs(t *testing.T) { + for _, test := range []string{ + "0", + "1", + "1234", + "1.23e-2", + "1e-1000", + "1e1000", + "Inf", + } { + p := makeFloat(test) + a := new(Float).Abs(p) + if !alike(a, p) { + t.Errorf("%s: got %s; want %s", test, a.Text('g', 10), test) + } + + n := makeFloat("-" + test) + a.Abs(n) + if !alike(a, p) { + t.Errorf("-%s: got %s; want %s", test, a.Text('g', 10), test) + } + } +} + +func TestFloatNeg(t *testing.T) { + for _, test := range []string{ + "0", + "1", + "1234", + "1.23e-2", + "1e-1000", + "1e1000", + "Inf", + } { + p1 := makeFloat(test) + n1 := makeFloat("-" + test) + n2 := new(Float).Neg(p1) + p2 := new(Float).Neg(n2) + if !alike(n2, n1) { + t.Errorf("%s: got %s; want %s", test, n2.Text('g', 10), n1.Text('g', 10)) + } + if !alike(p2, p1) { + t.Errorf("%s: got %s; want %s", test, p2.Text('g', 10), p1.Text('g', 10)) + } + } +} + +func TestFloatInc(t *testing.T) { + const n = 10 + for _, prec := range precList { + if 1< y: + want = +1 + } + if got != want { + t.Errorf("(%g).Cmp(%g) = %v; want %v", x, y, got, want) + } + } + } + } +} diff --git a/libgo/go/math/big/floatconv.go b/libgo/go/math/big/floatconv.go new file mode 100644 index 00000000000..4a070ca64d4 --- /dev/null +++ b/libgo/go/math/big/floatconv.go @@ -0,0 +1,239 @@ +// Copyright 2015 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 string-to-Float conversion functions. + +package big + +import ( + "fmt" + "io" + "strings" +) + +// SetString sets z to the value of s and returns z and a boolean indicating +// success. s must be a floating-point number of the same format as accepted +// by Parse, with base argument 0. +func (z *Float) SetString(s string) (*Float, bool) { + if f, _, err := z.Parse(s, 0); err == nil { + return f, true + } + return nil, false +} + +// scan is like Parse but reads the longest possible prefix representing a valid +// floating point number from an io.ByteScanner rather than a string. It serves +// as the implementation of Parse. It does not recognize ±Inf and does not expect +// EOF at the end. +func (z *Float) scan(r io.ByteScanner, base int) (f *Float, b int, err error) { + prec := z.prec + if prec == 0 { + prec = 64 + } + + // A reasonable value in case of an error. + z.form = zero + + // sign + z.neg, err = scanSign(r) + if err != nil { + return + } + + // mantissa + var fcount int // fractional digit count; valid if <= 0 + z.mant, b, fcount, err = z.mant.scan(r, base, true) + if err != nil { + return + } + + // exponent + var exp int64 + var ebase int + exp, ebase, err = scanExponent(r, true) + if err != nil { + return + } + + // special-case 0 + if len(z.mant) == 0 { + z.prec = prec + z.acc = Exact + z.form = zero + f = z + return + } + // len(z.mant) > 0 + + // The mantissa may have a decimal point (fcount <= 0) and there + // may be a nonzero exponent exp. The decimal point amounts to a + // division by b**(-fcount). An exponent means multiplication by + // ebase**exp. Finally, mantissa normalization (shift left) requires + // a correcting multiplication by 2**(-shiftcount). Multiplications + // are commutative, so we can apply them in any order as long as there + // is no loss of precision. We only have powers of 2 and 10; keep + // track via separate exponents exp2 and exp10. + + // normalize mantissa and get initial binary exponent + var exp2 = int64(len(z.mant))*_W - fnorm(z.mant) + + // determine binary or decimal exponent contribution of decimal point + var exp10 int64 + if fcount < 0 { + // The mantissa has a "decimal" point ddd.dddd; and + // -fcount is the number of digits to the right of '.'. + // Adjust relevant exponent accodingly. + switch b { + case 16: + fcount *= 4 // hexadecimal digits are 4 bits each + fallthrough + case 2: + exp2 += int64(fcount) + default: // b == 10 + exp10 = int64(fcount) + } + // we don't need fcount anymore + } + + // take actual exponent into account + if ebase == 2 { + exp2 += exp + } else { // ebase == 10 + exp10 += exp + } + // we don't need exp anymore + + // apply 2**exp2 + if MinExp <= exp2 && exp2 <= MaxExp { + z.prec = prec + z.form = finite + z.exp = int32(exp2) + f = z + } else { + err = fmt.Errorf("exponent overflow") + return + } + + if exp10 == 0 { + // no decimal exponent to consider + z.round(0) + return + } + // exp10 != 0 + + // apply 10**exp10 + p := new(Float).SetPrec(z.Prec() + 64) // use more bits for p -- TODO(gri) what is the right number? + if exp10 < 0 { + z.uquo(z, p.pow10(-exp10)) + } else { + z.umul(z, p.pow10(exp10)) + } + + return +} + +// These powers of 10 can be represented exactly as a float64. +var pow10tab = [...]float64{ + 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, + 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, +} + +// pow10 sets z to 10**n and returns z. +// n must not be negative. +func (z *Float) pow10(n int64) *Float { + if n < 0 { + panic("pow10 called with negative argument") + } + + const m = int64(len(pow10tab) - 1) + if n <= m { + return z.SetFloat64(pow10tab[n]) + } + // n > m + + z.SetFloat64(pow10tab[m]) + n -= m + + // use more bits for f than for z + // TODO(gri) what is the right number? + f := new(Float).SetPrec(z.Prec() + 64).SetInt64(10) + + for n > 0 { + if n&1 != 0 { + z.Mul(z, f) + } + f.Mul(f, f) + n >>= 1 + } + + return z +} + +// Parse parses s which must contain a text representation of a floating- +// point number with a mantissa in the given conversion base (the exponent +// is always a decimal number), or a string representing an infinite value. +// +// It sets z to the (possibly rounded) value of the corresponding floating- +// point value, and returns z, the actual base b, and an error err, if any. +// If z's precision is 0, it is changed to 64 before rounding takes effect. +// The number must be of the form: +// +// number = [ sign ] [ prefix ] mantissa [ exponent ] | infinity . +// sign = "+" | "-" . +// prefix = "0" ( "x" | "X" | "b" | "B" ) . +// mantissa = digits | digits "." [ digits ] | "." digits . +// exponent = ( "E" | "e" | "p" ) [ sign ] digits . +// digits = digit { digit } . +// digit = "0" ... "9" | "a" ... "z" | "A" ... "Z" . +// infinity = [ sign ] ( "inf" | "Inf" ) . +// +// The base argument must be 0, 2, 10, or 16. Providing an invalid base +// argument will lead to a run-time panic. +// +// For base 0, the number prefix determines the actual base: A prefix of +// "0x" or "0X" selects base 16, and a "0b" or "0B" prefix selects +// base 2; otherwise, the actual base is 10 and no prefix is accepted. +// The octal prefix "0" is not supported (a leading "0" is simply +// considered a "0"). +// +// A "p" exponent indicates a binary (rather then decimal) exponent; +// for instance "0x1.fffffffffffffp1023" (using base 0) represents the +// maximum float64 value. For hexadecimal mantissae, the exponent must +// be binary, if present (an "e" or "E" exponent indicator cannot be +// distinguished from a mantissa digit). +// +// The returned *Float f is nil and the value of z is valid but not +// defined if an error is reported. +// +func (z *Float) Parse(s string, base int) (f *Float, b int, err error) { + // scan doesn't handle ±Inf + if len(s) == 3 && (s == "Inf" || s == "inf") { + f = z.SetInf(false) + return + } + if len(s) == 4 && (s[0] == '+' || s[0] == '-') && (s[1:] == "Inf" || s[1:] == "inf") { + f = z.SetInf(s[0] == '-') + return + } + + r := strings.NewReader(s) + if f, b, err = z.scan(r, base); err != nil { + return + } + + // entire string must have been consumed + if ch, err2 := r.ReadByte(); err2 == nil { + err = fmt.Errorf("expected end of string, found %q", ch) + } else if err2 != io.EOF { + err = err2 + } + + return +} + +// ParseFloat is like f.Parse(s, base) with f set to the given precision +// and rounding mode. +func ParseFloat(s string, base int, prec uint, mode RoundingMode) (f *Float, b int, err error) { + return new(Float).SetPrec(prec).SetMode(mode).Parse(s, base) +} diff --git a/libgo/go/math/big/floatconv_test.go b/libgo/go/math/big/floatconv_test.go new file mode 100644 index 00000000000..4f239534a14 --- /dev/null +++ b/libgo/go/math/big/floatconv_test.go @@ -0,0 +1,573 @@ +// Copyright 2015 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 big + +import ( + "fmt" + "math" + "strconv" + "testing" +) + +func TestFloatSetFloat64String(t *testing.T) { + inf := math.Inf(0) + nan := math.NaN() + + for _, test := range []struct { + s string + x float64 // NaNs represent invalid inputs + }{ + // basics + {"0", 0}, + {"-0", -0}, + {"+0", 0}, + {"1", 1}, + {"-1", -1}, + {"+1", 1}, + {"1.234", 1.234}, + {"-1.234", -1.234}, + {"+1.234", 1.234}, + {".1", 0.1}, + {"1.", 1}, + {"+1.", 1}, + + // various zeros + {"0e100", 0}, + {"-0e+100", 0}, + {"+0e-100", 0}, + {"0E100", 0}, + {"-0E+100", 0}, + {"+0E-100", 0}, + + // various decimal exponent formats + {"1.e10", 1e10}, + {"1e+10", 1e10}, + {"+1e-10", 1e-10}, + {"1E10", 1e10}, + {"1.E+10", 1e10}, + {"+1E-10", 1e-10}, + + // infinities + {"Inf", inf}, + {"+Inf", inf}, + {"-Inf", -inf}, + {"inf", inf}, + {"+inf", inf}, + {"-inf", -inf}, + + // invalid numbers + {"", nan}, + {"-", nan}, + {"0x", nan}, + {"0e", nan}, + {"1.2ef", nan}, + {"2..3", nan}, + {"123..", nan}, + {"infinity", nan}, + {"foobar", nan}, + + // misc decimal values + {"3.14159265", 3.14159265}, + {"-687436.79457e-245", -687436.79457e-245}, + {"-687436.79457E245", -687436.79457e245}, + {".0000000000000000000000000000000000000001", 1e-40}, + {"+10000000000000000000000000000000000000000e-0", 1e40}, + + // decimal mantissa, binary exponent + {"0p0", 0}, + {"-0p0", -0}, + {"1p10", 1 << 10}, + {"1p+10", 1 << 10}, + {"+1p-10", 1.0 / (1 << 10)}, + {"1024p-12", 0.25}, + {"-1p10", -1024}, + {"1.5p1", 3}, + + // binary mantissa, decimal exponent + {"0b0", 0}, + {"-0b0", -0}, + {"0b0e+10", 0}, + {"-0b0e-10", -0}, + {"0b1010", 10}, + {"0B1010E2", 1000}, + {"0b.1", 0.5}, + {"0b.001", 0.125}, + {"0b.001e3", 125}, + + // binary mantissa, binary exponent + {"0b0p+10", 0}, + {"-0b0p-10", -0}, + {"0b.1010p4", 10}, + {"0b1p-1", 0.5}, + {"0b001p-3", 0.125}, + {"0b.001p3", 1}, + {"0b0.01p2", 1}, + + // hexadecimal mantissa and exponent + {"0x0", 0}, + {"-0x0", -0}, + {"0x0p+10", 0}, + {"-0x0p-10", -0}, + {"0xff", 255}, + {"0X.8p1", 1}, + {"-0X0.00008p16", -0.5}, + {"0x0.0000000000001p-1022", math.SmallestNonzeroFloat64}, + {"0x1.fffffffffffffp1023", math.MaxFloat64}, + } { + var x Float + x.SetPrec(53) + _, ok := x.SetString(test.s) + if math.IsNaN(test.x) { + // test.s is invalid + if ok { + t.Errorf("%s: want parse error", test.s) + } + continue + } + // test.s is valid + if !ok { + t.Errorf("%s: got parse error", test.s) + continue + } + f, _ := x.Float64() + want := new(Float).SetFloat64(test.x) + if x.Cmp(want) != 0 { + t.Errorf("%s: got %s (%v); want %v", test.s, &x, f, test.x) + } + } +} + +const ( + below1e23 = 99999999999999974834176 + above1e23 = 100000000000000008388608 +) + +func TestFloat64Text(t *testing.T) { + for _, test := range []struct { + x float64 + format byte + prec int + want string + }{ + {0, 'f', 0, "0"}, + {math.Copysign(0, -1), 'f', 0, "-0"}, + {1, 'f', 0, "1"}, + {-1, 'f', 0, "-1"}, + + {0.001, 'e', 0, "1e-03"}, + {0.459, 'e', 0, "5e-01"}, + {1.459, 'e', 0, "1e+00"}, + {2.459, 'e', 1, "2.5e+00"}, + {3.459, 'e', 2, "3.46e+00"}, + {4.459, 'e', 3, "4.459e+00"}, + {5.459, 'e', 4, "5.4590e+00"}, + + {0.001, 'f', 0, "0"}, + {0.459, 'f', 0, "0"}, + {1.459, 'f', 0, "1"}, + {2.459, 'f', 1, "2.5"}, + {3.459, 'f', 2, "3.46"}, + {4.459, 'f', 3, "4.459"}, + {5.459, 'f', 4, "5.4590"}, + + {0, 'b', 0, "0"}, + {math.Copysign(0, -1), 'b', 0, "-0"}, + {1.0, 'b', 0, "4503599627370496p-52"}, + {-1.0, 'b', 0, "-4503599627370496p-52"}, + {4503599627370496, 'b', 0, "4503599627370496p+0"}, + + {0, 'p', 0, "0"}, + {math.Copysign(0, -1), 'p', 0, "-0"}, + {1024.0, 'p', 0, "0x.8p+11"}, + {-1024.0, 'p', 0, "-0x.8p+11"}, + + // all test cases below from strconv/ftoa_test.go + {1, 'e', 5, "1.00000e+00"}, + {1, 'f', 5, "1.00000"}, + {1, 'g', 5, "1"}, + // {1, 'g', -1, "1"}, + // {20, 'g', -1, "20"}, + // {1234567.8, 'g', -1, "1.2345678e+06"}, + // {200000, 'g', -1, "200000"}, + // {2000000, 'g', -1, "2e+06"}, + + // g conversion and zero suppression + {400, 'g', 2, "4e+02"}, + {40, 'g', 2, "40"}, + {4, 'g', 2, "4"}, + {.4, 'g', 2, "0.4"}, + {.04, 'g', 2, "0.04"}, + {.004, 'g', 2, "0.004"}, + {.0004, 'g', 2, "0.0004"}, + {.00004, 'g', 2, "4e-05"}, + {.000004, 'g', 2, "4e-06"}, + + {0, 'e', 5, "0.00000e+00"}, + {0, 'f', 5, "0.00000"}, + {0, 'g', 5, "0"}, + // {0, 'g', -1, "0"}, + + {-1, 'e', 5, "-1.00000e+00"}, + {-1, 'f', 5, "-1.00000"}, + {-1, 'g', 5, "-1"}, + // {-1, 'g', -1, "-1"}, + + {12, 'e', 5, "1.20000e+01"}, + {12, 'f', 5, "12.00000"}, + {12, 'g', 5, "12"}, + // {12, 'g', -1, "12"}, + + {123456700, 'e', 5, "1.23457e+08"}, + {123456700, 'f', 5, "123456700.00000"}, + {123456700, 'g', 5, "1.2346e+08"}, + // {123456700, 'g', -1, "1.234567e+08"}, + + {1.2345e6, 'e', 5, "1.23450e+06"}, + {1.2345e6, 'f', 5, "1234500.00000"}, + {1.2345e6, 'g', 5, "1.2345e+06"}, + + {1e23, 'e', 17, "9.99999999999999916e+22"}, + {1e23, 'f', 17, "99999999999999991611392.00000000000000000"}, + {1e23, 'g', 17, "9.9999999999999992e+22"}, + + // {1e23, 'e', -1, "1e+23"}, + // {1e23, 'f', -1, "100000000000000000000000"}, + // {1e23, 'g', -1, "1e+23"}, + + {below1e23, 'e', 17, "9.99999999999999748e+22"}, + {below1e23, 'f', 17, "99999999999999974834176.00000000000000000"}, + {below1e23, 'g', 17, "9.9999999999999975e+22"}, + + // {below1e23, 'e', -1, "9.999999999999997e+22"}, + // {below1e23, 'f', -1, "99999999999999970000000"}, + // {below1e23, 'g', -1, "9.999999999999997e+22"}, + + {above1e23, 'e', 17, "1.00000000000000008e+23"}, + {above1e23, 'f', 17, "100000000000000008388608.00000000000000000"}, + // {above1e23, 'g', 17, "1.0000000000000001e+23"}, + + // {above1e23, 'e', -1, "1.0000000000000001e+23"}, + // {above1e23, 'f', -1, "100000000000000010000000"}, + // {above1e23, 'g', -1, "1.0000000000000001e+23"}, + + // {fdiv(5e-304, 1e20), 'g', -1, "5e-324"}, + // {fdiv(-5e-304, 1e20), 'g', -1, "-5e-324"}, + + // {32, 'g', -1, "32"}, + // {32, 'g', 0, "3e+01"}, + + // {100, 'x', -1, "%x"}, + + // {math.NaN(), 'g', -1, "NaN"}, + // {-math.NaN(), 'g', -1, "NaN"}, + {math.Inf(0), 'g', -1, "+Inf"}, + {math.Inf(-1), 'g', -1, "-Inf"}, + {-math.Inf(0), 'g', -1, "-Inf"}, + + {-1, 'b', -1, "-4503599627370496p-52"}, + + // fixed bugs + {0.9, 'f', 1, "0.9"}, + {0.09, 'f', 1, "0.1"}, + {0.0999, 'f', 1, "0.1"}, + {0.05, 'f', 1, "0.1"}, + {0.05, 'f', 0, "0"}, + {0.5, 'f', 1, "0.5"}, + {0.5, 'f', 0, "0"}, + {1.5, 'f', 0, "2"}, + + // http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/ + // {2.2250738585072012e-308, 'g', -1, "2.2250738585072014e-308"}, + // http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/ + // {2.2250738585072011e-308, 'g', -1, "2.225073858507201e-308"}, + + // Issue 2625. + {383260575764816448, 'f', 0, "383260575764816448"}, + // {383260575764816448, 'g', -1, "3.8326057576481645e+17"}, + } { + f := new(Float).SetFloat64(test.x) + got := f.Text(test.format, test.prec) + if got != test.want { + t.Errorf("%v: got %s; want %s", test, got, test.want) + } + + if test.format == 'b' && test.x == 0 { + continue // 'b' format in strconv.Float requires knowledge of bias for 0.0 + } + if test.format == 'p' { + continue // 'p' format not supported in strconv.Format + } + + // verify that Float format matches strconv format + want := strconv.FormatFloat(test.x, test.format, test.prec, 64) + if got != want { + t.Errorf("%v: got %s; want %s (strconv)", test, got, want) + } + } +} + +func TestFloatText(t *testing.T) { + for _, test := range []struct { + x string + prec uint + format byte + digits int + want string + }{ + {"0", 10, 'f', 0, "0"}, + {"-0", 10, 'f', 0, "-0"}, + {"1", 10, 'f', 0, "1"}, + {"-1", 10, 'f', 0, "-1"}, + + {"1.459", 100, 'e', 0, "1e+00"}, + {"2.459", 100, 'e', 1, "2.5e+00"}, + {"3.459", 100, 'e', 2, "3.46e+00"}, + {"4.459", 100, 'e', 3, "4.459e+00"}, + {"5.459", 100, 'e', 4, "5.4590e+00"}, + + {"1.459", 100, 'E', 0, "1E+00"}, + {"2.459", 100, 'E', 1, "2.5E+00"}, + {"3.459", 100, 'E', 2, "3.46E+00"}, + {"4.459", 100, 'E', 3, "4.459E+00"}, + {"5.459", 100, 'E', 4, "5.4590E+00"}, + + {"1.459", 100, 'f', 0, "1"}, + {"2.459", 100, 'f', 1, "2.5"}, + {"3.459", 100, 'f', 2, "3.46"}, + {"4.459", 100, 'f', 3, "4.459"}, + {"5.459", 100, 'f', 4, "5.4590"}, + + {"1.459", 100, 'g', 0, "1"}, + {"2.459", 100, 'g', 1, "2"}, + {"3.459", 100, 'g', 2, "3.5"}, + {"4.459", 100, 'g', 3, "4.46"}, + {"5.459", 100, 'g', 4, "5.459"}, + + {"1459", 53, 'g', 0, "1e+03"}, + {"2459", 53, 'g', 1, "2e+03"}, + {"3459", 53, 'g', 2, "3.5e+03"}, + {"4459", 53, 'g', 3, "4.46e+03"}, + {"5459", 53, 'g', 4, "5459"}, + + {"1459", 53, 'G', 0, "1E+03"}, + {"2459", 53, 'G', 1, "2E+03"}, + {"3459", 53, 'G', 2, "3.5E+03"}, + {"4459", 53, 'G', 3, "4.46E+03"}, + {"5459", 53, 'G', 4, "5459"}, + + {"3", 10, 'e', 40, "3.0000000000000000000000000000000000000000e+00"}, + {"3", 10, 'f', 40, "3.0000000000000000000000000000000000000000"}, + {"3", 10, 'g', 40, "3"}, + + {"3e40", 100, 'e', 40, "3.0000000000000000000000000000000000000000e+40"}, + {"3e40", 100, 'f', 4, "30000000000000000000000000000000000000000.0000"}, + {"3e40", 100, 'g', 40, "3e+40"}, + + // make sure "stupid" exponents don't stall the machine + {"1e1000000", 64, 'p', 0, "0x.88b3a28a05eade3ap+3321929"}, + {"1e1000000000", 64, 'p', 0, "0x.ecc5f45aa573d3p+1538481529"}, + {"1e-1000000", 64, 'p', 0, "0x.efb4542cc8ca418ap-3321928"}, + {"1e-1000000000", 64, 'p', 0, "0x.8a64dd983a4c7dabp-1538481528"}, + + // TODO(gri) need tests for actual large Floats + + {"0", 53, 'b', 0, "0"}, + {"-0", 53, 'b', 0, "-0"}, + {"1.0", 53, 'b', 0, "4503599627370496p-52"}, + {"-1.0", 53, 'b', 0, "-4503599627370496p-52"}, + {"4503599627370496", 53, 'b', 0, "4503599627370496p+0"}, + + // issue 9939 + {"3", 350, 'b', 0, "1720123961992553633708115671476565205597423741876210842803191629540192157066363606052513914832594264915968p-348"}, + {"03", 350, 'b', 0, "1720123961992553633708115671476565205597423741876210842803191629540192157066363606052513914832594264915968p-348"}, + {"3.", 350, 'b', 0, "1720123961992553633708115671476565205597423741876210842803191629540192157066363606052513914832594264915968p-348"}, + {"3.0", 350, 'b', 0, "1720123961992553633708115671476565205597423741876210842803191629540192157066363606052513914832594264915968p-348"}, + {"3.00", 350, 'b', 0, "1720123961992553633708115671476565205597423741876210842803191629540192157066363606052513914832594264915968p-348"}, + {"3.000", 350, 'b', 0, "1720123961992553633708115671476565205597423741876210842803191629540192157066363606052513914832594264915968p-348"}, + + {"3", 350, 'p', 0, "0x.cp+2"}, + {"03", 350, 'p', 0, "0x.cp+2"}, + {"3.", 350, 'p', 0, "0x.cp+2"}, + {"3.0", 350, 'p', 0, "0x.cp+2"}, + {"3.00", 350, 'p', 0, "0x.cp+2"}, + {"3.000", 350, 'p', 0, "0x.cp+2"}, + + {"0", 64, 'p', 0, "0"}, + {"-0", 64, 'p', 0, "-0"}, + {"1024.0", 64, 'p', 0, "0x.8p+11"}, + {"-1024.0", 64, 'p', 0, "-0x.8p+11"}, + + // unsupported format + {"3.14", 64, 'x', 0, "%x"}, + {"-3.14", 64, 'x', 0, "%x"}, + } { + f, _, err := ParseFloat(test.x, 0, test.prec, ToNearestEven) + if err != nil { + t.Errorf("%v: %s", test, err) + continue + } + + got := f.Text(test.format, test.digits) + if got != test.want { + t.Errorf("%v: got %s; want %s", test, got, test.want) + } + + // compare with strconv.FormatFloat output if possible + // ('p' format is not supported by strconv.FormatFloat, + // and its output for 0.0 prints a biased exponent value + // as in 0p-1074 which makes no sense to emulate here) + if test.prec == 53 && test.format != 'p' && f.Sign() != 0 { + f64, acc := f.Float64() + if acc != Exact { + t.Errorf("%v: expected exact conversion to float64", test) + continue + } + got := strconv.FormatFloat(f64, test.format, test.digits, 64) + if got != test.want { + t.Errorf("%v: got %s; want %s", test, got, test.want) + } + } + } +} + +func TestFloatFormat(t *testing.T) { + for _, test := range []struct { + format string + value interface{} // float32, float64, or string (== 512bit *Float) + want string + }{ + // TODO(gri) uncomment the disabled 'g'/'G' formats + // below once (*Float).Text supports prec < 0 + + // from fmt/fmt_test.go + {"%+.3e", 0.0, "+0.000e+00"}, + {"%+.3e", 1.0, "+1.000e+00"}, + {"%+.3f", -1.0, "-1.000"}, + {"%+.3F", -1.0, "-1.000"}, + {"%+.3F", float32(-1.0), "-1.000"}, + {"%+07.2f", 1.0, "+001.00"}, + {"%+07.2f", -1.0, "-001.00"}, + {"%+10.2f", +1.0, " +1.00"}, + {"%+10.2f", -1.0, " -1.00"}, + {"% .3E", -1.0, "-1.000E+00"}, + {"% .3e", 1.0, " 1.000e+00"}, + {"%+.3g", 0.0, "+0"}, + {"%+.3g", 1.0, "+1"}, + {"%+.3g", -1.0, "-1"}, + {"% .3g", -1.0, "-1"}, + {"% .3g", 1.0, " 1"}, + {"%b", float32(1.0), "8388608p-23"}, + {"%b", 1.0, "4503599627370496p-52"}, + + // from fmt/fmt_test.go: old test/fmt_test.go + {"%e", 1.0, "1.000000e+00"}, + {"%e", 1234.5678e3, "1.234568e+06"}, + {"%e", 1234.5678e-8, "1.234568e-05"}, + {"%e", -7.0, "-7.000000e+00"}, + {"%e", -1e-9, "-1.000000e-09"}, + {"%f", 1234.5678e3, "1234567.800000"}, + {"%f", 1234.5678e-8, "0.000012"}, + {"%f", -7.0, "-7.000000"}, + {"%f", -1e-9, "-0.000000"}, + // {"%g", 1234.5678e3, "1.2345678e+06"}, + // {"%g", float32(1234.5678e3), "1.2345678e+06"}, + // {"%g", 1234.5678e-8, "1.2345678e-05"}, + {"%g", -7.0, "-7"}, + {"%g", -1e-9, "-1e-09"}, + {"%g", float32(-1e-9), "-1e-09"}, + {"%E", 1.0, "1.000000E+00"}, + {"%E", 1234.5678e3, "1.234568E+06"}, + {"%E", 1234.5678e-8, "1.234568E-05"}, + {"%E", -7.0, "-7.000000E+00"}, + {"%E", -1e-9, "-1.000000E-09"}, + // {"%G", 1234.5678e3, "1.2345678E+06"}, + // {"%G", float32(1234.5678e3), "1.2345678E+06"}, + // {"%G", 1234.5678e-8, "1.2345678E-05"}, + {"%G", -7.0, "-7"}, + {"%G", -1e-9, "-1E-09"}, + {"%G", float32(-1e-9), "-1E-09"}, + + {"%20.6e", 1.2345e3, " 1.234500e+03"}, + {"%20.6e", 1.2345e-3, " 1.234500e-03"}, + {"%20e", 1.2345e3, " 1.234500e+03"}, + {"%20e", 1.2345e-3, " 1.234500e-03"}, + {"%20.8e", 1.2345e3, " 1.23450000e+03"}, + {"%20f", 1.23456789e3, " 1234.567890"}, + {"%20f", 1.23456789e-3, " 0.001235"}, + {"%20f", 12345678901.23456789, " 12345678901.234568"}, + {"%-20f", 1.23456789e3, "1234.567890 "}, + {"%20.8f", 1.23456789e3, " 1234.56789000"}, + {"%20.8f", 1.23456789e-3, " 0.00123457"}, + // {"%g", 1.23456789e3, "1234.56789"}, + // {"%g", 1.23456789e-3, "0.00123456789"}, + // {"%g", 1.23456789e20, "1.23456789e+20"}, + {"%20e", math.Inf(1), " +Inf"}, + {"%-20f", math.Inf(-1), "-Inf "}, + + // from fmt/fmt_test.go: comparison of padding rules with C printf + {"%.2f", 1.0, "1.00"}, + {"%.2f", -1.0, "-1.00"}, + {"% .2f", 1.0, " 1.00"}, + {"% .2f", -1.0, "-1.00"}, + {"%+.2f", 1.0, "+1.00"}, + {"%+.2f", -1.0, "-1.00"}, + {"%7.2f", 1.0, " 1.00"}, + {"%7.2f", -1.0, " -1.00"}, + {"% 7.2f", 1.0, " 1.00"}, + {"% 7.2f", -1.0, " -1.00"}, + {"%+7.2f", 1.0, " +1.00"}, + {"%+7.2f", -1.0, " -1.00"}, + {"%07.2f", 1.0, "0001.00"}, + {"%07.2f", -1.0, "-001.00"}, + {"% 07.2f", 1.0, " 001.00"}, + {"% 07.2f", -1.0, "-001.00"}, + {"%+07.2f", 1.0, "+001.00"}, + {"%+07.2f", -1.0, "-001.00"}, + + // from fmt/fmt_test.go: zero padding does not apply to infinities + {"%020f", math.Inf(-1), " -Inf"}, + {"%020f", math.Inf(+1), " +Inf"}, + {"% 020f", math.Inf(-1), " -Inf"}, + {"% 020f", math.Inf(+1), " Inf"}, + {"%+020f", math.Inf(-1), " -Inf"}, + {"%+020f", math.Inf(+1), " +Inf"}, + {"%20f", -1.0, " -1.000000"}, + + // handle %v like %g + {"%v", 0.0, "0"}, + {"%v", -7.0, "-7"}, + {"%v", -1e-9, "-1e-09"}, + {"%v", float32(-1e-9), "-1e-09"}, + {"%010v", 0.0, "0000000000"}, + {"%010v", 0.0, "0000000000"}, + + // *Float cases + {"%.20f", "1e-20", "0.00000000000000000001"}, + {"%.20f", "-1e-20", "-0.00000000000000000001"}, + {"%30.20f", "-1e-20", " -0.00000000000000000001"}, + {"%030.20f", "-1e-20", "-00000000.00000000000000000001"}, + {"%030.20f", "+1e-20", "000000000.00000000000000000001"}, + {"% 030.20f", "+1e-20", " 00000000.00000000000000000001"}, + + // erroneous formats + {"%s", 1.0, "%!s(*big.Float=1)"}, + } { + value := new(Float) + switch v := test.value.(type) { + case float32: + value.SetPrec(24).SetFloat64(float64(v)) + case float64: + value.SetPrec(53).SetFloat64(v) + case string: + value.SetPrec(512).Parse(v, 0) + default: + t.Fatalf("unsupported test value: %v (%T)", v, v) + } + + if got := fmt.Sprintf(test.format, value); got != test.want { + t.Errorf("%v: got %q; want %q", test, got, test.want) + } + } +} diff --git a/libgo/go/math/big/floatexample_test.go b/libgo/go/math/big/floatexample_test.go new file mode 100644 index 00000000000..69686b7d16b --- /dev/null +++ b/libgo/go/math/big/floatexample_test.go @@ -0,0 +1,113 @@ +// Copyright 2015 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 + +package big_test + +import ( + "fmt" + "math" + "math/big" +) + +func ExampleFloat_Add() { + // Operating on numbers of different precision. + var x, y, z big.Float + x.SetInt64(1000) // x is automatically set to 64bit precision + y.SetFloat64(2.718281828) // y is automatically set to 53bit precision + z.SetPrec(32) + z.Add(&x, &y) + fmt.Printf("x = %.10g (%s, prec = %d, acc = %s)\n", &x, x.Text('p', 0), x.Prec(), x.Acc()) + fmt.Printf("y = %.10g (%s, prec = %d, acc = %s)\n", &y, y.Text('p', 0), y.Prec(), y.Acc()) + fmt.Printf("z = %.10g (%s, prec = %d, acc = %s)\n", &z, z.Text('p', 0), z.Prec(), z.Acc()) + // Output: + // x = 1000 (0x.fap+10, prec = 64, acc = Exact) + // y = 2.718281828 (0x.adf85458248cd8p+2, prec = 53, acc = Exact) + // z = 1002.718282 (0x.faadf854p+10, prec = 32, acc = Below) +} + +func Example_Shift() { + // Implementing Float "shift" by modifying the (binary) exponents directly. + for s := -5; s <= 5; s++ { + x := big.NewFloat(0.5) + x.SetMantExp(x, x.MantExp(nil)+s) // shift x by s + fmt.Println(x) + } + // Output: + // 0.015625 + // 0.03125 + // 0.0625 + // 0.125 + // 0.25 + // 0.5 + // 1 + // 2 + // 4 + // 8 + // 16 +} + +func ExampleFloat_Cmp() { + inf := math.Inf(1) + zero := 0.0 + + operands := []float64{-inf, -1.2, -zero, 0, +1.2, +inf} + + fmt.Println(" x y cmp") + fmt.Println("---------------") + for _, x64 := range operands { + x := big.NewFloat(x64) + for _, y64 := range operands { + y := big.NewFloat(y64) + fmt.Printf("%4g %4g %3d\n", x, y, x.Cmp(y)) + } + fmt.Println() + } + + // Output: + // x y cmp + // --------------- + // -Inf -Inf 0 + // -Inf -1.2 -1 + // -Inf -0 -1 + // -Inf 0 -1 + // -Inf 1.2 -1 + // -Inf +Inf -1 + // + // -1.2 -Inf 1 + // -1.2 -1.2 0 + // -1.2 -0 -1 + // -1.2 0 -1 + // -1.2 1.2 -1 + // -1.2 +Inf -1 + // + // -0 -Inf 1 + // -0 -1.2 1 + // -0 -0 0 + // -0 0 0 + // -0 1.2 -1 + // -0 +Inf -1 + // + // 0 -Inf 1 + // 0 -1.2 1 + // 0 -0 0 + // 0 0 0 + // 0 1.2 -1 + // 0 +Inf -1 + // + // 1.2 -Inf 1 + // 1.2 -1.2 1 + // 1.2 -0 1 + // 1.2 0 1 + // 1.2 1.2 0 + // 1.2 +Inf -1 + // + // +Inf -Inf 1 + // +Inf -1.2 1 + // +Inf -0 1 + // +Inf 0 1 + // +Inf 1.2 1 + // +Inf +Inf 0 +} diff --git a/libgo/go/math/big/ftoa.go b/libgo/go/math/big/ftoa.go new file mode 100644 index 00000000000..5c5f2cea460 --- /dev/null +++ b/libgo/go/math/big/ftoa.go @@ -0,0 +1,393 @@ +// Copyright 2015 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 Float-to-string conversion functions. +// It is closely following the corresponding implementation +// in strconv/ftoa.go, but modified and simplified for Float. + +package big + +import ( + "fmt" + "strconv" + "strings" +) + +// Text converts the floating-point number x to a string according +// to the given format and precision prec. The format is one of: +// +// 'e' -d.dddde±dd, decimal exponent, at least two (possibly 0) exponent digits +// 'E' -d.ddddE±dd, decimal exponent, at least two (possibly 0) exponent digits +// 'f' -ddddd.dddd, no exponent +// 'g' like 'e' for large exponents, like 'f' otherwise +// 'G' like 'E' for large exponents, like 'f' otherwise +// 'b' -ddddddp±dd, binary exponent +// 'p' -0x.dddp±dd, binary exponent, hexadecimal mantissa +// +// For the binary exponent formats, the mantissa is printed in normalized form: +// +// 'b' decimal integer mantissa using x.Prec() bits, or -0 +// 'p' hexadecimal fraction with 0.5 <= 0.mantissa < 1.0, or -0 +// +// If format is a different character, Text returns a "%" followed by the +// unrecognized format character. +// +// The precision prec controls the number of digits (excluding the exponent) +// printed by the 'e', 'E', 'f', 'g', and 'G' formats. For 'e', 'E', and 'f' +// it is the number of digits after the decimal point. For 'g' and 'G' it is +// the total number of digits. A negative precision selects the smallest +// number of digits necessary to identify the value x uniquely. +// The prec value is ignored for the 'b' or 'p' format. +// +// BUG(gri) Float.Text does not accept negative precisions (issue #10991). +func (x *Float) Text(format byte, prec int) string { + const extra = 10 // TODO(gri) determine a good/better value here + return string(x.Append(make([]byte, 0, prec+extra), format, prec)) +} + +// String formats x like x.Text('g', 10). +func (x *Float) String() string { + return x.Text('g', 10) +} + +// Append appends to buf the string form of the floating-point number x, +// as generated by x.Text, and returns the extended buffer. +func (x *Float) Append(buf []byte, fmt byte, prec int) []byte { + // sign + if x.neg { + buf = append(buf, '-') + } + + // Inf + if x.form == inf { + if !x.neg { + buf = append(buf, '+') + } + return append(buf, "Inf"...) + } + + // pick off easy formats + switch fmt { + case 'b': + return x.fmtB(buf) + case 'p': + return x.fmtP(buf) + } + + // Algorithm: + // 1) convert Float to multiprecision decimal + // 2) round to desired precision + // 3) read digits out and format + + // 1) convert Float to multiprecision decimal + var d decimal // == 0.0 + if x.form == finite { + d.init(x.mant, int(x.exp)-x.mant.bitLen()) + } + + // 2) round to desired precision + shortest := false + if prec < 0 { + shortest = true + panic("unimplemented") + // TODO(gri) complete this + // roundShortest(&d, f.mant, int(f.exp)) + // Precision for shortest representation mode. + switch fmt { + case 'e', 'E': + prec = len(d.mant) - 1 + case 'f': + prec = max(len(d.mant)-d.exp, 0) + case 'g', 'G': + prec = len(d.mant) + } + } else { + // round appropriately + switch fmt { + case 'e', 'E': + // one digit before and number of digits after decimal point + d.round(1 + prec) + case 'f': + // number of digits before and after decimal point + d.round(d.exp + prec) + case 'g', 'G': + if prec == 0 { + prec = 1 + } + d.round(prec) + } + } + + // 3) read digits out and format + switch fmt { + case 'e', 'E': + return fmtE(buf, fmt, prec, d) + case 'f': + return fmtF(buf, prec, d) + case 'g', 'G': + // trim trailing fractional zeros in %e format + eprec := prec + if eprec > len(d.mant) && len(d.mant) >= d.exp { + eprec = len(d.mant) + } + // %e is used if the exponent from the conversion + // is less than -4 or greater than or equal to the precision. + // If precision was the shortest possible, use eprec = 6 for + // this decision. + if shortest { + eprec = 6 + } + exp := d.exp - 1 + if exp < -4 || exp >= eprec { + if prec > len(d.mant) { + prec = len(d.mant) + } + return fmtE(buf, fmt+'e'-'g', prec-1, d) + } + if prec > d.exp { + prec = len(d.mant) + } + return fmtF(buf, max(prec-d.exp, 0), d) + } + + // unknown format + if x.neg { + buf = buf[:len(buf)-1] // sign was added prematurely - remove it again + } + return append(buf, '%', fmt) +} + +// %e: d.ddddde±dd +func fmtE(buf []byte, fmt byte, prec int, d decimal) []byte { + // first digit + ch := byte('0') + if len(d.mant) > 0 { + ch = d.mant[0] + } + buf = append(buf, ch) + + // .moredigits + if prec > 0 { + buf = append(buf, '.') + i := 1 + m := min(len(d.mant), prec+1) + if i < m { + buf = append(buf, d.mant[i:m]...) + i = m + } + for ; i <= prec; i++ { + buf = append(buf, '0') + } + } + + // e± + buf = append(buf, fmt) + var exp int64 + if len(d.mant) > 0 { + exp = int64(d.exp) - 1 // -1 because first digit was printed before '.' + } + if exp < 0 { + ch = '-' + exp = -exp + } else { + ch = '+' + } + buf = append(buf, ch) + + // dd...d + if exp < 10 { + buf = append(buf, '0') // at least 2 exponent digits + } + return strconv.AppendInt(buf, exp, 10) +} + +// %f: ddddddd.ddddd +func fmtF(buf []byte, prec int, d decimal) []byte { + // integer, padded with zeros as needed + if d.exp > 0 { + m := min(len(d.mant), d.exp) + buf = append(buf, d.mant[:m]...) + for ; m < d.exp; m++ { + buf = append(buf, '0') + } + } else { + buf = append(buf, '0') + } + + // fraction + if prec > 0 { + buf = append(buf, '.') + for i := 0; i < prec; i++ { + ch := byte('0') + if j := d.exp + i; 0 <= j && j < len(d.mant) { + ch = d.mant[j] + } + buf = append(buf, ch) + } + } + + return buf +} + +// fmtB appends the string of x in the format mantissa "p" exponent +// with a decimal mantissa and a binary exponent, or 0" if x is zero, +// and returns the extended buffer. +// The mantissa is normalized such that is uses x.Prec() bits in binary +// representation. +// The sign of x is ignored, and x must not be an Inf. +func (x *Float) fmtB(buf []byte) []byte { + if x.form == zero { + return append(buf, '0') + } + + if debugFloat && x.form != finite { + panic("non-finite float") + } + // x != 0 + + // adjust mantissa to use exactly x.prec bits + m := x.mant + switch w := uint32(len(x.mant)) * _W; { + case w < x.prec: + m = nat(nil).shl(m, uint(x.prec-w)) + case w > x.prec: + m = nat(nil).shr(m, uint(w-x.prec)) + } + + buf = append(buf, m.decimalString()...) + buf = append(buf, 'p') + e := int64(x.exp) - int64(x.prec) + if e >= 0 { + buf = append(buf, '+') + } + return strconv.AppendInt(buf, e, 10) +} + +// fmtP appends the string of x in the format 0x." mantissa "p" exponent +// with a hexadecimal mantissa and a binary exponent, or 0" if x is zero, +// ad returns the extended buffer. +// The mantissa is normalized such that 0.5 <= 0.mantissa < 1.0. +// The sign of x is ignored, and x must not be an Inf. +func (x *Float) fmtP(buf []byte) []byte { + if x.form == zero { + return append(buf, '0') + } + + if debugFloat && x.form != finite { + panic("non-finite float") + } + // x != 0 + + // remove trailing 0 words early + // (no need to convert to hex 0's and trim later) + m := x.mant + i := 0 + for i < len(m) && m[i] == 0 { + i++ + } + m = m[i:] + + buf = append(buf, "0x."...) + buf = append(buf, strings.TrimRight(m.hexString(), "0")...) + buf = append(buf, 'p') + if x.exp >= 0 { + buf = append(buf, '+') + } + return strconv.AppendInt(buf, int64(x.exp), 10) +} + +func min(x, y int) int { + if x < y { + return x + } + return y +} + +// Format implements fmt.Formatter. It accepts all the regular +// formats for floating-point numbers ('e', 'E', 'f', 'F', 'g', +// 'G') as well as 'b', 'p', and 'v'. See (*Float).Text for the +// interpretation of 'b' and 'p'. The 'v' format is handled like +// 'g'. +// Format also supports specification of the minimum precision +// in digits, the output field width, as well as the format verbs +// '+' and ' ' for sign control, '0' for space or zero padding, +// and '-' for left or right justification. See the fmt package +// for details. +// +// BUG(gri) A missing precision for the 'g' format, or a negative +// (via '*') precision is not yet supported. Instead the +// default precision (6) is used in that case (issue #10991). +func (x *Float) Format(s fmt.State, format rune) { + prec, hasPrec := s.Precision() + if !hasPrec { + prec = 6 // default precision for 'e', 'f' + } + + switch format { + case 'e', 'E', 'f', 'b', 'p': + // nothing to do + case 'F': + // (*Float).Text doesn't support 'F'; handle like 'f' + format = 'f' + case 'v': + // handle like 'g' + format = 'g' + fallthrough + case 'g', 'G': + if !hasPrec { + // TODO(gri) uncomment once (*Float).Text handles prec < 0 + // prec = -1 // default precision for 'g', 'G' + } + default: + fmt.Fprintf(s, "%%!%c(*big.Float=%s)", format, x.String()) + return + } + var buf []byte + buf = x.Append(buf, byte(format), prec) + if len(buf) == 0 { + buf = []byte("?") // should never happen, but don't crash + } + // len(buf) > 0 + + var sign string + switch { + case buf[0] == '-': + sign = "-" + buf = buf[1:] + case buf[0] == '+': + // +Inf + sign = "+" + if s.Flag(' ') { + sign = " " + } + buf = buf[1:] + case s.Flag('+'): + sign = "+" + case s.Flag(' '): + sign = " " + } + + var padding int + if width, hasWidth := s.Width(); hasWidth && width > len(sign)+len(buf) { + padding = width - len(sign) - len(buf) + } + + switch { + case s.Flag('0') && !x.IsInf(): + // 0-padding on left + writeMultiple(s, sign, 1) + writeMultiple(s, "0", padding) + s.Write(buf) + case s.Flag('-'): + // padding on right + writeMultiple(s, sign, 1) + s.Write(buf) + writeMultiple(s, " ", padding) + default: + // padding on left + writeMultiple(s, " ", padding) + writeMultiple(s, sign, 1) + s.Write(buf) + } +} diff --git a/libgo/go/math/big/int.go b/libgo/go/math/big/int.go index ade5c2fc8cd..65334e0ef55 100644 --- a/libgo/go/math/big/int.go +++ b/libgo/go/math/big/int.go @@ -7,7 +7,6 @@ package big import ( - "errors" "fmt" "io" "math/rand" @@ -184,6 +183,10 @@ func (z *Int) MulRange(a, b int64) *Int { // Binomial sets z to the binomial coefficient of (n, k) and returns z. func (z *Int) Binomial(n, k int64) *Int { + // reduce the number of multiplications by reducing k + if n/2 < k && k <= n { + k = n - k // Binomial(n, k) == Binomial(n, n-k) + } var a, b Int a.MulRange(n-k+1, n) b.MulRange(1, k) @@ -321,195 +324,6 @@ func (x *Int) Cmp(y *Int) (r int) { return } -func (x *Int) String() string { - switch { - case x == nil: - return "" - case x.neg: - return "-" + x.abs.decimalString() - } - return x.abs.decimalString() -} - -func charset(ch rune) string { - switch ch { - case 'b': - return lowercaseDigits[0:2] - case 'o': - return lowercaseDigits[0:8] - case 'd', 's', 'v': - return lowercaseDigits[0:10] - case 'x': - return lowercaseDigits[0:16] - case 'X': - return uppercaseDigits[0:16] - } - return "" // unknown format -} - -// write count copies of text to s -func writeMultiple(s fmt.State, text string, count int) { - if len(text) > 0 { - b := []byte(text) - for ; count > 0; count-- { - s.Write(b) - } - } -} - -// Format is a support routine for fmt.Formatter. It accepts -// the formats 'b' (binary), 'o' (octal), 'd' (decimal), 'x' -// (lowercase hexadecimal), and 'X' (uppercase hexadecimal). -// Also supported are the full suite of package fmt's format -// verbs for integral types, including '+', '-', and ' ' -// for sign control, '#' for leading zero in octal and for -// hexadecimal, a leading "0x" or "0X" for "%#x" and "%#X" -// respectively, specification of minimum digits precision, -// output field width, space or zero padding, and left or -// right justification. -// -func (x *Int) Format(s fmt.State, ch rune) { - cs := charset(ch) - - // special cases - switch { - case cs == "": - // unknown format - fmt.Fprintf(s, "%%!%c(big.Int=%s)", ch, x.String()) - return - case x == nil: - fmt.Fprint(s, "") - return - } - - // determine sign character - sign := "" - switch { - case x.neg: - sign = "-" - case s.Flag('+'): // supersedes ' ' when both specified - sign = "+" - case s.Flag(' '): - sign = " " - } - - // determine prefix characters for indicating output base - prefix := "" - if s.Flag('#') { - switch ch { - case 'o': // octal - prefix = "0" - case 'x': // hexadecimal - prefix = "0x" - case 'X': - prefix = "0X" - } - } - - // determine digits with base set by len(cs) and digit characters from cs - digits := x.abs.string(cs) - - // number of characters for the three classes of number padding - var left int // space characters to left of digits for right justification ("%8d") - var zeroes int // zero characters (actually cs[0]) as left-most digits ("%.8d") - var right int // space characters to right of digits for left justification ("%-8d") - - // determine number padding from precision: the least number of digits to output - precision, precisionSet := s.Precision() - if precisionSet { - switch { - case len(digits) < precision: - zeroes = precision - len(digits) // count of zero padding - case digits == "0" && precision == 0: - return // print nothing if zero value (x == 0) and zero precision ("." or ".0") - } - } - - // determine field pad from width: the least number of characters to output - length := len(sign) + len(prefix) + zeroes + len(digits) - if width, widthSet := s.Width(); widthSet && length < width { // pad as specified - switch d := width - length; { - case s.Flag('-'): - // pad on the right with spaces; supersedes '0' when both specified - right = d - case s.Flag('0') && !precisionSet: - // pad with zeroes unless precision also specified - zeroes = d - default: - // pad on the left with spaces - left = d - } - } - - // print number as [left pad][sign][prefix][zero pad][digits][right pad] - writeMultiple(s, " ", left) - writeMultiple(s, sign, 1) - writeMultiple(s, prefix, 1) - writeMultiple(s, "0", zeroes) - writeMultiple(s, digits, 1) - writeMultiple(s, " ", right) -} - -// scan sets z to the integer value corresponding to the longest possible prefix -// read from r representing a signed integer number in a given conversion base. -// It returns z, the actual conversion base used, and an error, if any. In the -// error case, the value of z is undefined but the returned value is nil. The -// syntax follows the syntax of integer literals in Go. -// -// The base argument must be 0 or a value from 2 through MaxBase. If the base -// is 0, the string prefix determines the actual conversion base. A prefix of -// ``0x'' or ``0X'' selects base 16; the ``0'' prefix selects base 8, and a -// ``0b'' or ``0B'' prefix selects base 2. Otherwise the selected base is 10. -// -func (z *Int) scan(r io.RuneScanner, base int) (*Int, int, error) { - // determine sign - ch, _, err := r.ReadRune() - if err != nil { - return nil, 0, err - } - neg := false - switch ch { - case '-': - neg = true - case '+': // nothing to do - default: - r.UnreadRune() - } - - // determine mantissa - z.abs, base, err = z.abs.scan(r, base) - if err != nil { - return nil, base, err - } - z.neg = len(z.abs) > 0 && neg // 0 has no sign - - return z, base, nil -} - -// Scan is a support routine for fmt.Scanner; it sets z to the value of -// the scanned number. It accepts the formats 'b' (binary), 'o' (octal), -// 'd' (decimal), 'x' (lowercase hexadecimal), and 'X' (uppercase hexadecimal). -func (z *Int) Scan(s fmt.ScanState, ch rune) error { - s.SkipSpace() // skip leading space characters - base := 0 - switch ch { - case 'b': - base = 2 - case 'o': - base = 8 - case 'd': - base = 10 - case 'x', 'X': - base = 16 - case 's', 'v': - // let scan determine the base - default: - return errors.New("Int.Scan: invalid verb") - } - _, _, err := z.scan(s, base) - return err -} - // low32 returns the least significant 32 bits of z. func low32(z nat) uint32 { if len(z) == 0 { @@ -550,7 +364,7 @@ func (x *Int) Uint64() uint64 { // and returns z and a boolean indicating success. If SetString fails, // the value of z is undefined but the returned value is nil. // -// The base argument must be 0 or a value from 2 through MaxBase. If the base +// The base argument must be 0 or a value between 2 and MaxBase. If the base // is 0, the string prefix determines the actual conversion base. A prefix of // ``0x'' or ``0X'' selects base 16; the ``0'' prefix selects base 8, and a // ``0b'' or ``0B'' prefix selects base 2. Otherwise the selected base is 10. @@ -561,7 +375,7 @@ func (z *Int) SetString(s string, base int) (*Int, bool) { if err != nil { return nil, false } - _, _, err = r.ReadRune() + _, err = r.ReadByte() if err != io.EOF { return nil, false } @@ -686,15 +500,17 @@ func (z *Int) binaryGCD(a, b *Int) *Int { // use one Euclidean iteration to ensure that u and v are approx. the same size switch { case len(a.abs) > len(b.abs): - u.Set(b) + // must set v before u since u may be alias for a or b (was issue #11284) v.Rem(a, b) + u.Set(b) case len(a.abs) < len(b.abs): - u.Set(a) v.Rem(b, a) - default: u.Set(a) + default: v.Set(b) + u.Set(a) } + // a, b must not be used anymore (may be aliases with u) // v might be 0 now if len(v.abs) == 0 { @@ -736,8 +552,11 @@ func (z *Int) binaryGCD(a, b *Int) *Int { // ProbablyPrime performs n Miller-Rabin tests to check whether x is prime. // If it returns true, x is prime with probability 1 - 1/4^n. -// If it returns false, x is not prime. +// If it returns false, x is not prime. n must be > 0. func (x *Int) ProbablyPrime(n int) bool { + if n <= 0 { + panic("non-positive n for ProbablyPrime") + } return !x.neg && x.abs.probablyPrime(n) } @@ -766,6 +585,124 @@ func (z *Int) ModInverse(g, n *Int) *Int { return z } +// Jacobi returns the Jacobi symbol (x/y), either +1, -1, or 0. +// The y argument must be an odd integer. +func Jacobi(x, y *Int) int { + if len(y.abs) == 0 || y.abs[0]&1 == 0 { + panic(fmt.Sprintf("big: invalid 2nd argument to Int.Jacobi: need odd integer but got %s", y)) + } + + // We use the formulation described in chapter 2, section 2.4, + // "The Yacas Book of Algorithms": + // http://yacas.sourceforge.net/Algo.book.pdf + + var a, b, c Int + a.Set(x) + b.Set(y) + j := 1 + + if b.neg { + if a.neg { + j = -1 + } + b.neg = false + } + + for { + if b.Cmp(intOne) == 0 { + return j + } + if len(a.abs) == 0 { + return 0 + } + a.Mod(&a, &b) + if len(a.abs) == 0 { + return 0 + } + // a > 0 + + // handle factors of 2 in 'a' + s := a.abs.trailingZeroBits() + if s&1 != 0 { + bmod8 := b.abs[0] & 7 + if bmod8 == 3 || bmod8 == 5 { + j = -j + } + } + c.Rsh(&a, s) // a = 2^s*c + + // swap numerator and denominator + if b.abs[0]&3 == 3 && c.abs[0]&3 == 3 { + j = -j + } + a.Set(&b) + b.Set(&c) + } +} + +// ModSqrt sets z to a square root of x mod p if such a square root exists, and +// returns z. The modulus p must be an odd prime. If x is not a square mod p, +// ModSqrt leaves z unchanged and returns nil. This function panics if p is +// not an odd integer. +func (z *Int) ModSqrt(x, p *Int) *Int { + switch Jacobi(x, p) { + case -1: + return nil // x is not a square mod p + case 0: + return z.SetInt64(0) // sqrt(0) mod p = 0 + case 1: + break + } + if x.neg || x.Cmp(p) >= 0 { // ensure 0 <= x < p + x = new(Int).Mod(x, p) + } + + // Break p-1 into s*2^e such that s is odd. + var s Int + s.Sub(p, intOne) + e := s.abs.trailingZeroBits() + s.Rsh(&s, e) + + // find some non-square n + var n Int + n.SetInt64(2) + for Jacobi(&n, p) != -1 { + n.Add(&n, intOne) + } + + // Core of the Tonelli-Shanks algorithm. Follows the description in + // section 6 of "Square roots from 1; 24, 51, 10 to Dan Shanks" by Ezra + // Brown: + // https://www.maa.org/sites/default/files/pdf/upload_library/22/Polya/07468342.di020786.02p0470a.pdf + var y, b, g, t Int + y.Add(&s, intOne) + y.Rsh(&y, 1) + y.Exp(x, &y, p) // y = x^((s+1)/2) + b.Exp(x, &s, p) // b = x^s + g.Exp(&n, &s, p) // g = n^s + r := e + for { + // find the least m such that ord_p(b) = 2^m + var m uint + t.Set(&b) + for t.Cmp(intOne) != 0 { + t.Mul(&t, &t).Mod(&t, p) + m++ + } + + if m == 0 { + return z.Set(&y) + } + + t.SetInt64(0).SetBit(&t, int(r-m-1), 1).Exp(&g, &t, p) + // t = g^(2^(r-m-1)) mod p + g.Mul(&t, &t).Mod(&g, p) // g = g^(2^(r-m)) mod p + y.Mul(&y, &t).Mod(&y, p) + b.Mul(&b, &g).Mod(&b, p) + r = m + } +} + // Lsh sets z = x << n and returns z. func (z *Int) Lsh(x *Int, n uint) *Int { z.abs = z.abs.shl(x.abs, n) @@ -995,7 +932,7 @@ func (z *Int) GobDecode(buf []byte) error { } b := buf[0] if b>>1 != intGobVersion { - return errors.New(fmt.Sprintf("Int.GobDecode: encoding version %d not supported", b>>1)) + return fmt.Errorf("Int.GobDecode: encoding version %d not supported", b>>1) } z.neg = b&1 != 0 z.abs = z.abs.setBytes(buf[1:]) diff --git a/libgo/go/math/big/int_test.go b/libgo/go/math/big/int_test.go index 2d762dbc89f..88c8c2bb641 100644 --- a/libgo/go/math/big/int_test.go +++ b/libgo/go/math/big/int_test.go @@ -219,334 +219,42 @@ func TestMulRangeZ(t *testing.T) { } } -var stringTests = []struct { - in string - out string - base int - val int64 - ok bool -}{ - {in: "", ok: false}, - {in: "a", ok: false}, - {in: "z", ok: false}, - {in: "+", ok: false}, - {in: "-", ok: false}, - {in: "0b", ok: false}, - {in: "0x", ok: false}, - {in: "2", base: 2, ok: false}, - {in: "0b2", base: 0, ok: false}, - {in: "08", ok: false}, - {in: "8", base: 8, ok: false}, - {in: "0xg", base: 0, ok: false}, - {in: "g", base: 16, ok: false}, - {"0", "0", 0, 0, true}, - {"0", "0", 10, 0, true}, - {"0", "0", 16, 0, true}, - {"+0", "0", 0, 0, true}, - {"-0", "0", 0, 0, true}, - {"10", "10", 0, 10, true}, - {"10", "10", 10, 10, true}, - {"10", "10", 16, 16, true}, - {"-10", "-10", 16, -16, true}, - {"+10", "10", 16, 16, true}, - {"0x10", "16", 0, 16, true}, - {in: "0x10", base: 16, ok: false}, - {"-0x10", "-16", 0, -16, true}, - {"+0x10", "16", 0, 16, true}, - {"00", "0", 0, 0, true}, - {"0", "0", 8, 0, true}, - {"07", "7", 0, 7, true}, - {"7", "7", 8, 7, true}, - {"023", "19", 0, 19, true}, - {"23", "23", 8, 19, true}, - {"cafebabe", "cafebabe", 16, 0xcafebabe, true}, - {"0b0", "0", 0, 0, true}, - {"-111", "-111", 2, -7, true}, - {"-0b111", "-7", 0, -7, true}, - {"0b1001010111", "599", 0, 0x257, true}, - {"1001010111", "1001010111", 2, 0x257, true}, -} - -func format(base int) string { - switch base { - case 2: - return "%b" - case 8: - return "%o" - case 16: - return "%x" - } - return "%d" -} - -func TestGetString(t *testing.T) { - z := new(Int) - for i, test := range stringTests { - if !test.ok { - continue - } - z.SetInt64(test.val) - - if test.base == 10 { - s := z.String() - if s != test.out { - t.Errorf("#%da got %s; want %s", i, s, test.out) - } - } - - s := fmt.Sprintf(format(test.base), z) - if s != test.out { - t.Errorf("#%db got %s; want %s", i, s, test.out) - } - } -} - -func TestSetString(t *testing.T) { - tmp := new(Int) - for i, test := range stringTests { - // initialize to a non-zero value so that issues with parsing - // 0 are detected - tmp.SetInt64(1234567890) - n1, ok1 := new(Int).SetString(test.in, test.base) - n2, ok2 := tmp.SetString(test.in, test.base) - expected := NewInt(test.val) - if ok1 != test.ok || ok2 != test.ok { - t.Errorf("#%d (input '%s') ok incorrect (should be %t)", i, test.in, test.ok) - continue - } - if !ok1 { - if n1 != nil { - t.Errorf("#%d (input '%s') n1 != nil", i, test.in) - } - continue - } - if !ok2 { - if n2 != nil { - t.Errorf("#%d (input '%s') n2 != nil", i, test.in) - } - continue - } - - if ok1 && !isNormalized(n1) { - t.Errorf("#%d (input '%s'): %v is not normalized", i, test.in, *n1) - } - if ok2 && !isNormalized(n2) { - t.Errorf("#%d (input '%s'): %v is not normalized", i, test.in, *n2) - } - - if n1.Cmp(expected) != 0 { - t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n1, test.val) - } - if n2.Cmp(expected) != 0 { - t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n2, test.val) - } - } -} - -var formatTests = []struct { - input string - format string - output string -}{ - {"", "%x", ""}, - {"", "%#x", ""}, - {"", "%#y", "%!y(big.Int=)"}, - - {"10", "%b", "1010"}, - {"10", "%o", "12"}, - {"10", "%d", "10"}, - {"10", "%v", "10"}, - {"10", "%x", "a"}, - {"10", "%X", "A"}, - {"-10", "%X", "-A"}, - {"10", "%y", "%!y(big.Int=10)"}, - {"-10", "%y", "%!y(big.Int=-10)"}, - - {"10", "%#b", "1010"}, - {"10", "%#o", "012"}, - {"10", "%#d", "10"}, - {"10", "%#v", "10"}, - {"10", "%#x", "0xa"}, - {"10", "%#X", "0XA"}, - {"-10", "%#X", "-0XA"}, - {"10", "%#y", "%!y(big.Int=10)"}, - {"-10", "%#y", "%!y(big.Int=-10)"}, - - {"1234", "%d", "1234"}, - {"1234", "%3d", "1234"}, - {"1234", "%4d", "1234"}, - {"-1234", "%d", "-1234"}, - {"1234", "% 5d", " 1234"}, - {"1234", "%+5d", "+1234"}, - {"1234", "%-5d", "1234 "}, - {"1234", "%x", "4d2"}, - {"1234", "%X", "4D2"}, - {"-1234", "%3x", "-4d2"}, - {"-1234", "%4x", "-4d2"}, - {"-1234", "%5x", " -4d2"}, - {"-1234", "%-5x", "-4d2 "}, - {"1234", "%03d", "1234"}, - {"1234", "%04d", "1234"}, - {"1234", "%05d", "01234"}, - {"1234", "%06d", "001234"}, - {"-1234", "%06d", "-01234"}, - {"1234", "%+06d", "+01234"}, - {"1234", "% 06d", " 01234"}, - {"1234", "%-6d", "1234 "}, - {"1234", "%-06d", "1234 "}, - {"-1234", "%-06d", "-1234 "}, - - {"1234", "%.3d", "1234"}, - {"1234", "%.4d", "1234"}, - {"1234", "%.5d", "01234"}, - {"1234", "%.6d", "001234"}, - {"-1234", "%.3d", "-1234"}, - {"-1234", "%.4d", "-1234"}, - {"-1234", "%.5d", "-01234"}, - {"-1234", "%.6d", "-001234"}, - - {"1234", "%8.3d", " 1234"}, - {"1234", "%8.4d", " 1234"}, - {"1234", "%8.5d", " 01234"}, - {"1234", "%8.6d", " 001234"}, - {"-1234", "%8.3d", " -1234"}, - {"-1234", "%8.4d", " -1234"}, - {"-1234", "%8.5d", " -01234"}, - {"-1234", "%8.6d", " -001234"}, - - {"1234", "%+8.3d", " +1234"}, - {"1234", "%+8.4d", " +1234"}, - {"1234", "%+8.5d", " +01234"}, - {"1234", "%+8.6d", " +001234"}, - {"-1234", "%+8.3d", " -1234"}, - {"-1234", "%+8.4d", " -1234"}, - {"-1234", "%+8.5d", " -01234"}, - {"-1234", "%+8.6d", " -001234"}, - - {"1234", "% 8.3d", " 1234"}, - {"1234", "% 8.4d", " 1234"}, - {"1234", "% 8.5d", " 01234"}, - {"1234", "% 8.6d", " 001234"}, - {"-1234", "% 8.3d", " -1234"}, - {"-1234", "% 8.4d", " -1234"}, - {"-1234", "% 8.5d", " -01234"}, - {"-1234", "% 8.6d", " -001234"}, - - {"1234", "%.3x", "4d2"}, - {"1234", "%.4x", "04d2"}, - {"1234", "%.5x", "004d2"}, - {"1234", "%.6x", "0004d2"}, - {"-1234", "%.3x", "-4d2"}, - {"-1234", "%.4x", "-04d2"}, - {"-1234", "%.5x", "-004d2"}, - {"-1234", "%.6x", "-0004d2"}, - - {"1234", "%8.3x", " 4d2"}, - {"1234", "%8.4x", " 04d2"}, - {"1234", "%8.5x", " 004d2"}, - {"1234", "%8.6x", " 0004d2"}, - {"-1234", "%8.3x", " -4d2"}, - {"-1234", "%8.4x", " -04d2"}, - {"-1234", "%8.5x", " -004d2"}, - {"-1234", "%8.6x", " -0004d2"}, - - {"1234", "%+8.3x", " +4d2"}, - {"1234", "%+8.4x", " +04d2"}, - {"1234", "%+8.5x", " +004d2"}, - {"1234", "%+8.6x", " +0004d2"}, - {"-1234", "%+8.3x", " -4d2"}, - {"-1234", "%+8.4x", " -04d2"}, - {"-1234", "%+8.5x", " -004d2"}, - {"-1234", "%+8.6x", " -0004d2"}, - - {"1234", "% 8.3x", " 4d2"}, - {"1234", "% 8.4x", " 04d2"}, - {"1234", "% 8.5x", " 004d2"}, - {"1234", "% 8.6x", " 0004d2"}, - {"1234", "% 8.7x", " 00004d2"}, - {"1234", "% 8.8x", " 000004d2"}, - {"-1234", "% 8.3x", " -4d2"}, - {"-1234", "% 8.4x", " -04d2"}, - {"-1234", "% 8.5x", " -004d2"}, - {"-1234", "% 8.6x", " -0004d2"}, - {"-1234", "% 8.7x", "-00004d2"}, - {"-1234", "% 8.8x", "-000004d2"}, - - {"1234", "%-8.3d", "1234 "}, - {"1234", "%-8.4d", "1234 "}, - {"1234", "%-8.5d", "01234 "}, - {"1234", "%-8.6d", "001234 "}, - {"1234", "%-8.7d", "0001234 "}, - {"1234", "%-8.8d", "00001234"}, - {"-1234", "%-8.3d", "-1234 "}, - {"-1234", "%-8.4d", "-1234 "}, - {"-1234", "%-8.5d", "-01234 "}, - {"-1234", "%-8.6d", "-001234 "}, - {"-1234", "%-8.7d", "-0001234"}, - {"-1234", "%-8.8d", "-00001234"}, - - {"16777215", "%b", "111111111111111111111111"}, // 2**24 - 1 - - {"0", "%.d", ""}, - {"0", "%.0d", ""}, - {"0", "%3.d", ""}, -} - -func TestFormat(t *testing.T) { - for i, test := range formatTests { - var x *Int - if test.input != "" { - var ok bool - x, ok = new(Int).SetString(test.input, 0) - if !ok { - t.Errorf("#%d failed reading input %s", i, test.input) - } - } - output := fmt.Sprintf(test.format, x) - if output != test.output { - t.Errorf("#%d got %q; want %q, {%q, %q, %q}", i, output, test.output, test.input, test.format, test.output) - } - } -} - -var scanTests = []struct { - input string - format string - output string - remaining int -}{ - {"1010", "%b", "10", 0}, - {"0b1010", "%v", "10", 0}, - {"12", "%o", "10", 0}, - {"012", "%v", "10", 0}, - {"10", "%d", "10", 0}, - {"10", "%v", "10", 0}, - {"a", "%x", "10", 0}, - {"0xa", "%v", "10", 0}, - {"A", "%X", "10", 0}, - {"-A", "%X", "-10", 0}, - {"+0b1011001", "%v", "89", 0}, - {"0xA", "%v", "10", 0}, - {"0 ", "%v", "0", 1}, - {"2+3", "%v", "2", 2}, - {"0XABC 12", "%v", "2748", 3}, -} - -func TestScan(t *testing.T) { - var buf bytes.Buffer - for i, test := range scanTests { - x := new(Int) - buf.Reset() - buf.WriteString(test.input) - if _, err := fmt.Fscanf(&buf, test.format, x); err != nil { - t.Errorf("#%d error: %s", i, err) - } - if x.String() != test.output { - t.Errorf("#%d got %s; want %s", i, x.String(), test.output) - } - if buf.Len() != test.remaining { - t.Errorf("#%d got %d bytes remaining; want %d", i, buf.Len(), test.remaining) - } +func TestBinomial(t *testing.T) { + var z Int + for _, test := range []struct { + n, k int64 + want string + }{ + {0, 0, "1"}, + {0, 1, "0"}, + {1, 0, "1"}, + {1, 1, "1"}, + {1, 10, "0"}, + {4, 0, "1"}, + {4, 1, "4"}, + {4, 2, "6"}, + {4, 3, "4"}, + {4, 4, "1"}, + {10, 1, "10"}, + {10, 9, "10"}, + {10, 5, "252"}, + {11, 5, "462"}, + {11, 6, "462"}, + {100, 10, "17310309456440"}, + {100, 90, "17310309456440"}, + {1000, 10, "263409560461970212832400"}, + {1000, 990, "263409560461970212832400"}, + } { + if got := z.Binomial(test.n, test.k).String(); got != test.want { + t.Errorf("Binomial(%d, %d) = %s; want %s", test.n, test.k, got, test.want) + } + } +} + +func BenchmarkBinomial(b *testing.B) { + var z Int + for i := b.N - 1; i >= 0; i-- { + z.Binomial(1000, 990) } } @@ -621,6 +329,42 @@ func TestDivisionSigns(t *testing.T) { } } +func norm(x nat) nat { + i := len(x) + for i > 0 && x[i-1] == 0 { + i-- + } + return x[:i] +} + +func TestBits(t *testing.T) { + for _, test := range []nat{ + nil, + {0}, + {1}, + {0, 1, 2, 3, 4}, + {4, 3, 2, 1, 0}, + {4, 3, 2, 1, 0, 0, 0, 0}, + } { + var z Int + z.neg = true + got := z.SetBits(test) + want := norm(test) + if got.abs.cmp(want) != 0 { + t.Errorf("SetBits(%v) = %v; want %v", test, got.abs, want) + } + + if got.neg { + t.Errorf("SetBits(%v): got negative result", test) + } + + bits := nat(z.Bits()) + if bits.cmp(want) != 0 { + t.Errorf("%v.Bits() = %v; want %v", z.abs, bits, want) + } + } +} + func checkSetBytes(b []byte) bool { hex1 := hex.EncodeToString(new(Int).SetBytes(b).Bytes()) hex2 := hex.EncodeToString(b) @@ -648,7 +392,7 @@ func checkBytes(b []byte) bool { } func TestBytes(t *testing.T) { - if err := quick.Check(checkSetBytes, nil); err != nil { + if err := quick.Check(checkBytes, nil); err != nil { t.Error(err) } } @@ -781,6 +525,7 @@ var expTests = []struct { {"1234", "-1", "1", "0"}, // misc + {"5", "1", "3", "2"}, {"5", "-7", "", "1"}, {"-5", "-7", "", "1"}, {"5", "0", "", "1"}, @@ -917,6 +662,21 @@ func testGcd(t *testing.T, d, x, y, a, b *Int) { if D.Cmp(d) != 0 { t.Errorf("binaryGcd(%s, %s): got d = %s, want %s", a, b, D, d) } + + // check results in presence of aliasing (issue #11284) + a2 := new(Int).Set(a) + b2 := new(Int).Set(b) + a2.binaryGCD(a2, b2) // result is same as 1st argument + if a2.Cmp(d) != 0 { + t.Errorf("binaryGcd(%s, %s): got d = %s, want %s", a, b, a2, d) + } + + a2 = new(Int).Set(a) + b2 = new(Int).Set(b) + b2.binaryGCD(a2, b2) // result is same as 2nd argument + if b2.Cmp(d) != 0 { + t.Errorf("binaryGcd(%s, %s): got d = %s, want %s", a, b, b2, d) + } } func TestGcd(t *testing.T) { @@ -948,7 +708,7 @@ var primes = []string{ "10953742525620032441", "17908251027575790097", - // http://code.google.com/p/go/issues/detail?id=638 + // https://golang.org/issue/638 "18699199384836356663", "98920366548084643601728869055592650835572950932266967461790948584315647051443", @@ -959,9 +719,18 @@ var primes = []string{ "230975859993204150666423538988557839555560243929065415434980904258310530753006723857139742334640122533598517597674807096648905501653461687601339782814316124971547968912893214002992086353183070342498989426570593", "5521712099665906221540423207019333379125265462121169655563495403888449493493629943498064604536961775110765377745550377067893607246020694972959780839151452457728855382113555867743022746090187341871655890805971735385789993", "203956878356401977405765866929034577280193993314348263094772646453283062722701277632936616063144088173312372882677123879538709400158306567338328279154499698366071906766440037074217117805690872792848149112022286332144876183376326512083574821647933992961249917319836219304274280243803104015000563790123", + + // ECC primes: http://tools.ietf.org/html/draft-ladd-safecurves-02 + "3618502788666131106986593281521497120414687020801267626233049500247285301239", // Curve1174: 2^251-9 + "57896044618658097711785492504343953926634992332820282019728792003956564819949", // Curve25519: 2^255-19 + "9850501549098619803069760025035903451269934817616361666987073351061430442874302652853566563721228910201656997576599", // E-382: 2^382-105 + "42307582002575910332922579714097346549017899709713998034217522897561970639123926132812109468141778230245837569601494931472367", // Curve41417: 2^414-17 + "6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151", // E-521: 2^521-1 } var composites = []string{ + "0", + "1", "21284175091214687912771199898307297748211672914763848041968395774954376176754", "6084766654921918907427900243509372380954290099172559290432744450051395395951", "84594350493221918389213352992032324280367711247940675652888030554255915464401", @@ -989,6 +758,21 @@ func TestProbablyPrime(t *testing.T) { break } } + + // check that ProbablyPrime panics if n <= 0 + c := NewInt(11) // a prime + for _, n := range []int{-1, 0, 1} { + func() { + defer func() { + if n <= 0 && recover() == nil { + t.Fatalf("expected panic from ProbablyPrime(%d)", n) + } + }() + if !c.ProbablyPrime(n) { + t.Fatalf("%v should be a prime", c) + } + }() + } } type intShiftTest struct { @@ -1487,6 +1271,136 @@ func TestModInverse(t *testing.T) { } } +// testModSqrt is a helper for TestModSqrt, +// which checks that ModSqrt can compute a square-root of elt^2. +func testModSqrt(t *testing.T, elt, mod, sq, sqrt *Int) bool { + var sqChk, sqrtChk, sqrtsq Int + sq.Mul(elt, elt) + sq.Mod(sq, mod) + z := sqrt.ModSqrt(sq, mod) + if z != sqrt { + t.Errorf("ModSqrt returned wrong value %s", z) + } + + // test ModSqrt arguments outside the range [0,mod) + sqChk.Add(sq, mod) + z = sqrtChk.ModSqrt(&sqChk, mod) + if z != &sqrtChk || z.Cmp(sqrt) != 0 { + t.Errorf("ModSqrt returned inconsistent value %s", z) + } + sqChk.Sub(sq, mod) + z = sqrtChk.ModSqrt(&sqChk, mod) + if z != &sqrtChk || z.Cmp(sqrt) != 0 { + t.Errorf("ModSqrt returned inconsistent value %s", z) + } + + // make sure we actually got a square root + if sqrt.Cmp(elt) == 0 { + return true // we found the "desired" square root + } + sqrtsq.Mul(sqrt, sqrt) // make sure we found the "other" one + sqrtsq.Mod(&sqrtsq, mod) + return sq.Cmp(&sqrtsq) == 0 +} + +func TestModSqrt(t *testing.T) { + var elt, mod, modx4, sq, sqrt Int + r := rand.New(rand.NewSource(9)) + for i, s := range primes[1:] { // skip 2, use only odd primes + mod.SetString(s, 10) + modx4.Lsh(&mod, 2) + + // test a few random elements per prime + for x := 1; x < 5; x++ { + elt.Rand(r, &modx4) + elt.Sub(&elt, &mod) // test range [-mod, 3*mod) + if !testModSqrt(t, &elt, &mod, &sq, &sqrt) { + t.Errorf("#%d: failed (sqrt(e) = %s)", i, &sqrt) + } + } + } + + // exhaustive test for small values + for n := 3; n < 100; n++ { + mod.SetInt64(int64(n)) + if !mod.ProbablyPrime(10) { + continue + } + isSquare := make([]bool, n) + + // test all the squares + for x := 1; x < n; x++ { + elt.SetInt64(int64(x)) + if !testModSqrt(t, &elt, &mod, &sq, &sqrt) { + t.Errorf("#%d: failed (sqrt(%d,%d) = %s)", x, &elt, &mod, &sqrt) + } + isSquare[sq.Uint64()] = true + } + + // test all non-squares + for x := 1; x < n; x++ { + sq.SetInt64(int64(x)) + z := sqrt.ModSqrt(&sq, &mod) + if !isSquare[x] && z != nil { + t.Errorf("#%d: failed (sqrt(%d,%d) = nil)", x, &sqrt, &mod) + } + } + } +} + +func TestJacobi(t *testing.T) { + testCases := []struct { + x, y int64 + result int + }{ + {0, 1, 1}, + {0, -1, 1}, + {1, 1, 1}, + {1, -1, 1}, + {0, 5, 0}, + {1, 5, 1}, + {2, 5, -1}, + {-2, 5, -1}, + {2, -5, -1}, + {-2, -5, 1}, + {3, 5, -1}, + {5, 5, 0}, + {-5, 5, 0}, + {6, 5, 1}, + {6, -5, 1}, + {-6, 5, 1}, + {-6, -5, -1}, + } + + var x, y Int + + for i, test := range testCases { + x.SetInt64(test.x) + y.SetInt64(test.y) + expected := test.result + actual := Jacobi(&x, &y) + if actual != expected { + t.Errorf("#%d: Jacobi(%d, %d) = %d, but expected %d", i, test.x, test.y, actual, expected) + } + } +} + +func TestJacobiPanic(t *testing.T) { + const failureMsg = "test failure" + defer func() { + msg := recover() + if msg == nil || msg == failureMsg { + panic(msg) + } + t.Log(msg) + }() + x := NewInt(1) + y := NewInt(2) + // Jacobi should panic when the second argument is even. + Jacobi(x, y) + panic(failureMsg) +} + var encodingTests = []string{ "-539345864568634858364538753846587364875430589374589", "-678645873", diff --git a/libgo/go/math/big/intconv.go b/libgo/go/math/big/intconv.go new file mode 100644 index 00000000000..9c68a22bed8 --- /dev/null +++ b/libgo/go/math/big/intconv.go @@ -0,0 +1,228 @@ +// Copyright 2015 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 int-to-string conversion functions. + +package big + +import ( + "errors" + "fmt" + "io" +) + +func (x *Int) String() string { + switch { + case x == nil: + return "" + case x.neg: + return "-" + x.abs.decimalString() + } + return x.abs.decimalString() +} + +func charset(ch rune) string { + switch ch { + case 'b': + return lowercaseDigits[0:2] + case 'o': + return lowercaseDigits[0:8] + case 'd', 's', 'v': + return lowercaseDigits[0:10] + case 'x': + return lowercaseDigits[0:16] + case 'X': + return uppercaseDigits[0:16] + } + return "" // unknown format +} + +// write count copies of text to s +func writeMultiple(s fmt.State, text string, count int) { + if len(text) > 0 { + b := []byte(text) + for ; count > 0; count-- { + s.Write(b) + } + } +} + +// Format is a support routine for fmt.Formatter. It accepts +// the formats 'b' (binary), 'o' (octal), 'd' (decimal), 'x' +// (lowercase hexadecimal), and 'X' (uppercase hexadecimal). +// Also supported are the full suite of package fmt's format +// verbs for integral types, including '+', '-', and ' ' +// for sign control, '#' for leading zero in octal and for +// hexadecimal, a leading "0x" or "0X" for "%#x" and "%#X" +// respectively, specification of minimum digits precision, +// output field width, space or zero padding, and left or +// right justification. +// +func (x *Int) Format(s fmt.State, ch rune) { + cs := charset(ch) + + // special cases + switch { + case cs == "": + // unknown format + fmt.Fprintf(s, "%%!%c(big.Int=%s)", ch, x.String()) + return + case x == nil: + fmt.Fprint(s, "") + return + } + + // determine sign character + sign := "" + switch { + case x.neg: + sign = "-" + case s.Flag('+'): // supersedes ' ' when both specified + sign = "+" + case s.Flag(' '): + sign = " " + } + + // determine prefix characters for indicating output base + prefix := "" + if s.Flag('#') { + switch ch { + case 'o': // octal + prefix = "0" + case 'x': // hexadecimal + prefix = "0x" + case 'X': + prefix = "0X" + } + } + + // determine digits with base set by len(cs) and digit characters from cs + digits := x.abs.string(cs) + + // number of characters for the three classes of number padding + var left int // space characters to left of digits for right justification ("%8d") + var zeroes int // zero characters (actually cs[0]) as left-most digits ("%.8d") + var right int // space characters to right of digits for left justification ("%-8d") + + // determine number padding from precision: the least number of digits to output + precision, precisionSet := s.Precision() + if precisionSet { + switch { + case len(digits) < precision: + zeroes = precision - len(digits) // count of zero padding + case digits == "0" && precision == 0: + return // print nothing if zero value (x == 0) and zero precision ("." or ".0") + } + } + + // determine field pad from width: the least number of characters to output + length := len(sign) + len(prefix) + zeroes + len(digits) + if width, widthSet := s.Width(); widthSet && length < width { // pad as specified + switch d := width - length; { + case s.Flag('-'): + // pad on the right with spaces; supersedes '0' when both specified + right = d + case s.Flag('0') && !precisionSet: + // pad with zeroes unless precision also specified + zeroes = d + default: + // pad on the left with spaces + left = d + } + } + + // print number as [left pad][sign][prefix][zero pad][digits][right pad] + writeMultiple(s, " ", left) + writeMultiple(s, sign, 1) + writeMultiple(s, prefix, 1) + writeMultiple(s, "0", zeroes) + writeMultiple(s, digits, 1) + writeMultiple(s, " ", right) +} + +// scan sets z to the integer value corresponding to the longest possible prefix +// read from r representing a signed integer number in a given conversion base. +// It returns z, the actual conversion base used, and an error, if any. In the +// error case, the value of z is undefined but the returned value is nil. The +// syntax follows the syntax of integer literals in Go. +// +// The base argument must be 0 or a value from 2 through MaxBase. If the base +// is 0, the string prefix determines the actual conversion base. A prefix of +// ``0x'' or ``0X'' selects base 16; the ``0'' prefix selects base 8, and a +// ``0b'' or ``0B'' prefix selects base 2. Otherwise the selected base is 10. +// +func (z *Int) scan(r io.ByteScanner, base int) (*Int, int, error) { + // determine sign + neg, err := scanSign(r) + if err != nil { + return nil, 0, err + } + + // determine mantissa + z.abs, base, _, err = z.abs.scan(r, base, false) + if err != nil { + return nil, base, err + } + z.neg = len(z.abs) > 0 && neg // 0 has no sign + + return z, base, nil +} + +func scanSign(r io.ByteScanner) (neg bool, err error) { + var ch byte + if ch, err = r.ReadByte(); err != nil { + return false, err + } + switch ch { + case '-': + neg = true + case '+': + // nothing to do + default: + r.UnreadByte() + } + return +} + +// byteReader is a local wrapper around fmt.ScanState; +// it implements the ByteReader interface. +type byteReader struct { + fmt.ScanState +} + +func (r byteReader) ReadByte() (byte, error) { + ch, size, err := r.ReadRune() + if size != 1 && err == nil { + err = fmt.Errorf("invalid rune %#U", ch) + } + return byte(ch), err +} + +func (r byteReader) UnreadByte() error { + return r.UnreadRune() +} + +// Scan is a support routine for fmt.Scanner; it sets z to the value of +// the scanned number. It accepts the formats 'b' (binary), 'o' (octal), +// 'd' (decimal), 'x' (lowercase hexadecimal), and 'X' (uppercase hexadecimal). +func (z *Int) Scan(s fmt.ScanState, ch rune) error { + s.SkipSpace() // skip leading space characters + base := 0 + switch ch { + case 'b': + base = 2 + case 'o': + base = 8 + case 'd': + base = 10 + case 'x', 'X': + base = 16 + case 's', 'v': + // let scan determine the base + default: + return errors.New("Int.Scan: invalid verb") + } + _, _, err := z.scan(byteReader{s}, base) + return err +} diff --git a/libgo/go/math/big/intconv_test.go b/libgo/go/math/big/intconv_test.go new file mode 100644 index 00000000000..2deb84b48f6 --- /dev/null +++ b/libgo/go/math/big/intconv_test.go @@ -0,0 +1,342 @@ +// Copyright 2015 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 big + +import ( + "bytes" + "fmt" + "testing" +) + +var stringTests = []struct { + in string + out string + base int + val int64 + ok bool +}{ + {in: "", ok: false}, + {in: "a", ok: false}, + {in: "z", ok: false}, + {in: "+", ok: false}, + {in: "-", ok: false}, + {in: "0b", ok: false}, + {in: "0x", ok: false}, + {in: "2", base: 2, ok: false}, + {in: "0b2", base: 0, ok: false}, + {in: "08", ok: false}, + {in: "8", base: 8, ok: false}, + {in: "0xg", base: 0, ok: false}, + {in: "g", base: 16, ok: false}, + {"0", "0", 0, 0, true}, + {"0", "0", 10, 0, true}, + {"0", "0", 16, 0, true}, + {"+0", "0", 0, 0, true}, + {"-0", "0", 0, 0, true}, + {"10", "10", 0, 10, true}, + {"10", "10", 10, 10, true}, + {"10", "10", 16, 16, true}, + {"-10", "-10", 16, -16, true}, + {"+10", "10", 16, 16, true}, + {"0x10", "16", 0, 16, true}, + {in: "0x10", base: 16, ok: false}, + {"-0x10", "-16", 0, -16, true}, + {"+0x10", "16", 0, 16, true}, + {"00", "0", 0, 0, true}, + {"0", "0", 8, 0, true}, + {"07", "7", 0, 7, true}, + {"7", "7", 8, 7, true}, + {"023", "19", 0, 19, true}, + {"23", "23", 8, 19, true}, + {"cafebabe", "cafebabe", 16, 0xcafebabe, true}, + {"0b0", "0", 0, 0, true}, + {"-111", "-111", 2, -7, true}, + {"-0b111", "-7", 0, -7, true}, + {"0b1001010111", "599", 0, 0x257, true}, + {"1001010111", "1001010111", 2, 0x257, true}, +} + +func format(base int) string { + switch base { + case 2: + return "%b" + case 8: + return "%o" + case 16: + return "%x" + } + return "%d" +} + +func TestGetString(t *testing.T) { + z := new(Int) + for i, test := range stringTests { + if !test.ok { + continue + } + z.SetInt64(test.val) + + if test.base == 10 { + s := z.String() + if s != test.out { + t.Errorf("#%da got %s; want %s", i, s, test.out) + } + } + + s := fmt.Sprintf(format(test.base), z) + if s != test.out { + t.Errorf("#%db got %s; want %s", i, s, test.out) + } + } +} + +func TestSetString(t *testing.T) { + tmp := new(Int) + for i, test := range stringTests { + // initialize to a non-zero value so that issues with parsing + // 0 are detected + tmp.SetInt64(1234567890) + n1, ok1 := new(Int).SetString(test.in, test.base) + n2, ok2 := tmp.SetString(test.in, test.base) + expected := NewInt(test.val) + if ok1 != test.ok || ok2 != test.ok { + t.Errorf("#%d (input '%s') ok incorrect (should be %t)", i, test.in, test.ok) + continue + } + if !ok1 { + if n1 != nil { + t.Errorf("#%d (input '%s') n1 != nil", i, test.in) + } + continue + } + if !ok2 { + if n2 != nil { + t.Errorf("#%d (input '%s') n2 != nil", i, test.in) + } + continue + } + + if ok1 && !isNormalized(n1) { + t.Errorf("#%d (input '%s'): %v is not normalized", i, test.in, *n1) + } + if ok2 && !isNormalized(n2) { + t.Errorf("#%d (input '%s'): %v is not normalized", i, test.in, *n2) + } + + if n1.Cmp(expected) != 0 { + t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n1, test.val) + } + if n2.Cmp(expected) != 0 { + t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n2, test.val) + } + } +} + +var formatTests = []struct { + input string + format string + output string +}{ + {"", "%x", ""}, + {"", "%#x", ""}, + {"", "%#y", "%!y(big.Int=)"}, + + {"10", "%b", "1010"}, + {"10", "%o", "12"}, + {"10", "%d", "10"}, + {"10", "%v", "10"}, + {"10", "%x", "a"}, + {"10", "%X", "A"}, + {"-10", "%X", "-A"}, + {"10", "%y", "%!y(big.Int=10)"}, + {"-10", "%y", "%!y(big.Int=-10)"}, + + {"10", "%#b", "1010"}, + {"10", "%#o", "012"}, + {"10", "%#d", "10"}, + {"10", "%#v", "10"}, + {"10", "%#x", "0xa"}, + {"10", "%#X", "0XA"}, + {"-10", "%#X", "-0XA"}, + {"10", "%#y", "%!y(big.Int=10)"}, + {"-10", "%#y", "%!y(big.Int=-10)"}, + + {"1234", "%d", "1234"}, + {"1234", "%3d", "1234"}, + {"1234", "%4d", "1234"}, + {"-1234", "%d", "-1234"}, + {"1234", "% 5d", " 1234"}, + {"1234", "%+5d", "+1234"}, + {"1234", "%-5d", "1234 "}, + {"1234", "%x", "4d2"}, + {"1234", "%X", "4D2"}, + {"-1234", "%3x", "-4d2"}, + {"-1234", "%4x", "-4d2"}, + {"-1234", "%5x", " -4d2"}, + {"-1234", "%-5x", "-4d2 "}, + {"1234", "%03d", "1234"}, + {"1234", "%04d", "1234"}, + {"1234", "%05d", "01234"}, + {"1234", "%06d", "001234"}, + {"-1234", "%06d", "-01234"}, + {"1234", "%+06d", "+01234"}, + {"1234", "% 06d", " 01234"}, + {"1234", "%-6d", "1234 "}, + {"1234", "%-06d", "1234 "}, + {"-1234", "%-06d", "-1234 "}, + + {"1234", "%.3d", "1234"}, + {"1234", "%.4d", "1234"}, + {"1234", "%.5d", "01234"}, + {"1234", "%.6d", "001234"}, + {"-1234", "%.3d", "-1234"}, + {"-1234", "%.4d", "-1234"}, + {"-1234", "%.5d", "-01234"}, + {"-1234", "%.6d", "-001234"}, + + {"1234", "%8.3d", " 1234"}, + {"1234", "%8.4d", " 1234"}, + {"1234", "%8.5d", " 01234"}, + {"1234", "%8.6d", " 001234"}, + {"-1234", "%8.3d", " -1234"}, + {"-1234", "%8.4d", " -1234"}, + {"-1234", "%8.5d", " -01234"}, + {"-1234", "%8.6d", " -001234"}, + + {"1234", "%+8.3d", " +1234"}, + {"1234", "%+8.4d", " +1234"}, + {"1234", "%+8.5d", " +01234"}, + {"1234", "%+8.6d", " +001234"}, + {"-1234", "%+8.3d", " -1234"}, + {"-1234", "%+8.4d", " -1234"}, + {"-1234", "%+8.5d", " -01234"}, + {"-1234", "%+8.6d", " -001234"}, + + {"1234", "% 8.3d", " 1234"}, + {"1234", "% 8.4d", " 1234"}, + {"1234", "% 8.5d", " 01234"}, + {"1234", "% 8.6d", " 001234"}, + {"-1234", "% 8.3d", " -1234"}, + {"-1234", "% 8.4d", " -1234"}, + {"-1234", "% 8.5d", " -01234"}, + {"-1234", "% 8.6d", " -001234"}, + + {"1234", "%.3x", "4d2"}, + {"1234", "%.4x", "04d2"}, + {"1234", "%.5x", "004d2"}, + {"1234", "%.6x", "0004d2"}, + {"-1234", "%.3x", "-4d2"}, + {"-1234", "%.4x", "-04d2"}, + {"-1234", "%.5x", "-004d2"}, + {"-1234", "%.6x", "-0004d2"}, + + {"1234", "%8.3x", " 4d2"}, + {"1234", "%8.4x", " 04d2"}, + {"1234", "%8.5x", " 004d2"}, + {"1234", "%8.6x", " 0004d2"}, + {"-1234", "%8.3x", " -4d2"}, + {"-1234", "%8.4x", " -04d2"}, + {"-1234", "%8.5x", " -004d2"}, + {"-1234", "%8.6x", " -0004d2"}, + + {"1234", "%+8.3x", " +4d2"}, + {"1234", "%+8.4x", " +04d2"}, + {"1234", "%+8.5x", " +004d2"}, + {"1234", "%+8.6x", " +0004d2"}, + {"-1234", "%+8.3x", " -4d2"}, + {"-1234", "%+8.4x", " -04d2"}, + {"-1234", "%+8.5x", " -004d2"}, + {"-1234", "%+8.6x", " -0004d2"}, + + {"1234", "% 8.3x", " 4d2"}, + {"1234", "% 8.4x", " 04d2"}, + {"1234", "% 8.5x", " 004d2"}, + {"1234", "% 8.6x", " 0004d2"}, + {"1234", "% 8.7x", " 00004d2"}, + {"1234", "% 8.8x", " 000004d2"}, + {"-1234", "% 8.3x", " -4d2"}, + {"-1234", "% 8.4x", " -04d2"}, + {"-1234", "% 8.5x", " -004d2"}, + {"-1234", "% 8.6x", " -0004d2"}, + {"-1234", "% 8.7x", "-00004d2"}, + {"-1234", "% 8.8x", "-000004d2"}, + + {"1234", "%-8.3d", "1234 "}, + {"1234", "%-8.4d", "1234 "}, + {"1234", "%-8.5d", "01234 "}, + {"1234", "%-8.6d", "001234 "}, + {"1234", "%-8.7d", "0001234 "}, + {"1234", "%-8.8d", "00001234"}, + {"-1234", "%-8.3d", "-1234 "}, + {"-1234", "%-8.4d", "-1234 "}, + {"-1234", "%-8.5d", "-01234 "}, + {"-1234", "%-8.6d", "-001234 "}, + {"-1234", "%-8.7d", "-0001234"}, + {"-1234", "%-8.8d", "-00001234"}, + + {"16777215", "%b", "111111111111111111111111"}, // 2**24 - 1 + + {"0", "%.d", ""}, + {"0", "%.0d", ""}, + {"0", "%3.d", ""}, +} + +func TestFormat(t *testing.T) { + for i, test := range formatTests { + var x *Int + if test.input != "" { + var ok bool + x, ok = new(Int).SetString(test.input, 0) + if !ok { + t.Errorf("#%d failed reading input %s", i, test.input) + } + } + output := fmt.Sprintf(test.format, x) + if output != test.output { + t.Errorf("#%d got %q; want %q, {%q, %q, %q}", i, output, test.output, test.input, test.format, test.output) + } + } +} + +var scanTests = []struct { + input string + format string + output string + remaining int +}{ + {"1010", "%b", "10", 0}, + {"0b1010", "%v", "10", 0}, + {"12", "%o", "10", 0}, + {"012", "%v", "10", 0}, + {"10", "%d", "10", 0}, + {"10", "%v", "10", 0}, + {"a", "%x", "10", 0}, + {"0xa", "%v", "10", 0}, + {"A", "%X", "10", 0}, + {"-A", "%X", "-10", 0}, + {"+0b1011001", "%v", "89", 0}, + {"0xA", "%v", "10", 0}, + {"0 ", "%v", "0", 1}, + {"2+3", "%v", "2", 2}, + {"0XABC 12", "%v", "2748", 3}, +} + +func TestScan(t *testing.T) { + var buf bytes.Buffer + for i, test := range scanTests { + x := new(Int) + buf.Reset() + buf.WriteString(test.input) + if _, err := fmt.Fscanf(&buf, test.format, x); err != nil { + t.Errorf("#%d error: %s", i, err) + } + if x.String() != test.output { + t.Errorf("#%d got %s; want %s", i, x.String(), test.output) + } + if buf.Len() != test.remaining { + t.Errorf("#%d got %d bytes remaining; want %d", i, buf.Len(), test.remaining) + } + } +} diff --git a/libgo/go/math/big/nat.go b/libgo/go/math/big/nat.go index 16a87f5c537..6545bc17ed3 100644 --- a/libgo/go/math/big/nat.go +++ b/libgo/go/math/big/nat.go @@ -5,18 +5,22 @@ // Package big implements multi-precision arithmetic (big numbers). // The following numeric types are supported: // -// - Int signed integers -// - Rat rational numbers +// Int signed integers +// Rat rational numbers +// Float floating-point numbers // // Methods are typically of the form: // -// func (z *Int) Op(x, y *Int) *Int (similar for *Rat) +// func (z *T) Unary(x *T) *T // z = op x +// func (z *T) Binary(x, y *T) *T // z = x op y +// func (x *T) M() T1 // v = x.M() // -// and implement operations z = x Op y with the result as receiver; if it -// is one of the operands it may be overwritten (and its memory reused). +// with T one of Int, Rat, or Float. For unary and binary operations, the +// result is the receiver (usually named z in that case); if it is one of +// the operands x or y it may be overwritten (and its memory reused). // To enable chaining of operations, the result is also returned. Methods -// returning a result other than *Int or *Rat take one of the operands as -// the receiver. +// returning a result other than *Int, *Rat, or *Float take an operand as +// the receiver (usually named x in that case). // package big @@ -24,13 +28,7 @@ package big // These are the building blocks for the operations on signed integers // and rationals. -import ( - "errors" - "io" - "math" - "math/rand" - "sync" -) +import "math/rand" // An unsigned integer x of the form // @@ -68,7 +66,7 @@ func (z nat) norm() nat { func (z nat) make(n int) nat { if n <= cap(z) { - return z[0:n] // reuse z + return z[:n] // reuse z } // Choosing a good value for e has significant performance impact // because it increases the chance that a value can be reused. @@ -78,7 +76,7 @@ func (z nat) make(n int) nat { func (z nat) setWord(x Word) nat { if x == 0 { - return z.make(0) + return z[:0] } z = z.make(1) z[0] = x @@ -122,7 +120,7 @@ func (z nat) add(x, y nat) nat { return z.add(y, x) case m == 0: // n == 0 because m >= n; result is 0 - return z.make(0) + return z[:0] case n == 0: // result is x return z.set(x) @@ -148,7 +146,7 @@ func (z nat) sub(x, y nat) nat { panic("underflow") case m == 0: // n == 0 because m >= n; result is 0 - return z.make(0) + return z[:0] case n == 0: // result is x return z.set(x) @@ -218,6 +216,34 @@ func basicMul(z, x, y nat) { } } +// montgomery computes x*y*2^(-n*_W) mod m, +// assuming k = -1/m mod 2^_W. +// z is used for storing the result which is returned; +// z must not alias x, y or m. +func (z nat) montgomery(x, y, m nat, k Word, n int) nat { + var c1, c2 Word + z = z.make(n) + z.clear() + for i := 0; i < n; i++ { + d := y[i] + c1 += addMulVVW(z, x, d) + t := z[0] * k + c2 = addMulVVW(z, m, t) + + copy(z, z[1:]) + z[n-1] = c1 + c2 + if z[n-1] < c1 { + c1 = 1 + } else { + c1 = 0 + } + } + if c1 != 0 { + subVV(z, z, m) + } + return z +} + // Fast version of z[0:n+n>>1].add(z[0:n+n>>1], x[0:n]) w/o bounds checks. // Factored out for readability - do not use outside karatsuba. func karatsubaAdd(z, x nat, n int) { @@ -337,7 +363,7 @@ func karatsuba(z, x, y nat) { } } -// alias returns true if x and y share the same base array. +// alias reports whether x and y share the same base array. func alias(x, y nat) bool { return cap(x) > 0 && cap(y) > 0 && &x[0:cap(x)][cap(x)-1] == &y[0:cap(y)][cap(y)-1] } @@ -384,7 +410,7 @@ func (z nat) mul(x, y nat) nat { case m < n: return z.mul(y, x) case m == 0 || n == 0: - return z.make(0) + return z[:0] case n == 1: return z.mulAddWW(x, y[0], 0) } @@ -488,7 +514,7 @@ func (z nat) divW(x nat, y Word) (q nat, r Word) { q = z.set(x) // result is x return case m == 0: - q = z.make(0) // result is 0 + q = z[:0] // result is 0 return } // m > 0 @@ -504,7 +530,7 @@ func (z nat) div(z2, u, v nat) (q, r nat) { } if u.cmp(v) < 0 { - q = z.make(0) + q = z[:0] r = z2.set(u) return } @@ -543,10 +569,10 @@ func (z nat) divLarge(u, uIn, v nat) (q, r nat) { u = nil // u is an alias for uIn or v - cannot reuse } u = u.make(len(uIn) + 1) - u.clear() + u.clear() // TODO(gri) no need to clear if we allocated a new u // D1. - shift := leadingZeros(v[n-1]) + shift := nlz(v[n-1]) if shift > 0 { // do not modify v, it may be used by another goroutine simultaneously v1 := make(nat, n) @@ -606,385 +632,6 @@ func (x nat) bitLen() int { return 0 } -// MaxBase is the largest number base accepted for string conversions. -const MaxBase = 'z' - 'a' + 10 + 1 // = hexValue('z') + 1 - -func hexValue(ch rune) Word { - d := int(MaxBase + 1) // illegal base - switch { - case '0' <= ch && ch <= '9': - d = int(ch - '0') - case 'a' <= ch && ch <= 'z': - d = int(ch - 'a' + 10) - case 'A' <= ch && ch <= 'Z': - d = int(ch - 'A' + 10) - } - return Word(d) -} - -// scan sets z to the natural number corresponding to the longest possible prefix -// read from r representing an unsigned integer in a given conversion base. -// It returns z, the actual conversion base used, and an error, if any. In the -// error case, the value of z is undefined. The syntax follows the syntax of -// unsigned integer literals in Go. -// -// The base argument must be 0 or a value from 2 through MaxBase. If the base -// is 0, the string prefix determines the actual conversion base. A prefix of -// ``0x'' or ``0X'' selects base 16; the ``0'' prefix selects base 8, and a -// ``0b'' or ``0B'' prefix selects base 2. Otherwise the selected base is 10. -// -func (z nat) scan(r io.RuneScanner, base int) (nat, int, error) { - // reject illegal bases - if base < 0 || base == 1 || MaxBase < base { - return z, 0, errors.New("illegal number base") - } - - // one char look-ahead - ch, _, err := r.ReadRune() - if err != nil { - return z, 0, err - } - - // determine base if necessary - b := Word(base) - if base == 0 { - b = 10 - if ch == '0' { - switch ch, _, err = r.ReadRune(); err { - case nil: - b = 8 - switch ch { - case 'x', 'X': - b = 16 - case 'b', 'B': - b = 2 - } - if b == 2 || b == 16 { - if ch, _, err = r.ReadRune(); err != nil { - return z, 0, err - } - } - case io.EOF: - return z.make(0), 10, nil - default: - return z, 10, err - } - } - } - - // convert string - // - group as many digits d as possible together into a "super-digit" dd with "super-base" bb - // - only when bb does not fit into a word anymore, do a full number mulAddWW using bb and dd - z = z.make(0) - bb := Word(1) - dd := Word(0) - for max := _M / b; ; { - d := hexValue(ch) - if d >= b { - r.UnreadRune() // ch does not belong to number anymore - break - } - - if bb <= max { - bb *= b - dd = dd*b + d - } else { - // bb * b would overflow - z = z.mulAddWW(z, bb, dd) - bb = b - dd = d - } - - if ch, _, err = r.ReadRune(); err != nil { - if err != io.EOF { - return z, int(b), err - } - break - } - } - - switch { - case bb > 1: - // there was at least one mantissa digit - z = z.mulAddWW(z, bb, dd) - case base == 0 && b == 8: - // there was only the octal prefix 0 (possibly followed by digits > 7); - // return base 10, not 8 - return z, 10, nil - case base != 0 || b != 8: - // there was neither a mantissa digit nor the octal prefix 0 - return z, int(b), errors.New("syntax error scanning number") - } - - return z.norm(), int(b), nil -} - -// Character sets for string conversion. -const ( - lowercaseDigits = "0123456789abcdefghijklmnopqrstuvwxyz" - uppercaseDigits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" -) - -// decimalString returns a decimal representation of x. -// It calls x.string with the charset "0123456789". -func (x nat) decimalString() string { - return x.string(lowercaseDigits[0:10]) -} - -// string converts x to a string using digits from a charset; a digit with -// value d is represented by charset[d]. The conversion base is determined -// by len(charset), which must be >= 2 and <= 256. -func (x nat) string(charset string) string { - b := Word(len(charset)) - - // special cases - switch { - case b < 2 || MaxBase > 256: - panic("illegal base") - case len(x) == 0: - return string(charset[0]) - } - - // allocate buffer for conversion - i := int(float64(x.bitLen())/math.Log2(float64(b))) + 1 // off by one at most - s := make([]byte, i) - - // convert power of two and non power of two bases separately - if b == b&-b { - // shift is base-b digit size in bits - shift := trailingZeroBits(b) // shift > 0 because b >= 2 - mask := Word(1)<= shift { - i-- - s[i] = charset[w&mask] - w >>= shift - nbits -= shift - } - - // convert any partial leading digit and advance to next word - if nbits == 0 { - // no partial digit remaining, just advance - w = x[k] - nbits = _W - } else { - // partial digit in current (k-1) and next (k) word - w |= x[k] << nbits - i-- - s[i] = charset[w&mask] - - // advance - w = x[k] >> (shift - nbits) - nbits = _W - (shift - nbits) - } - } - - // convert digits of most-significant word (omit leading zeros) - for nbits >= 0 && w != 0 { - i-- - s[i] = charset[w&mask] - w >>= shift - nbits -= shift - } - - } else { - // determine "big base"; i.e., the largest possible value bb - // that is a power of base b and still fits into a Word - // (as in 10^19 for 19 decimal digits in a 64bit Word) - bb := b // big base is b**ndigits - ndigits := 1 // number of base b digits - for max := Word(_M / b); bb <= max; bb *= b { - ndigits++ // maximize ndigits where bb = b**ndigits, bb <= _M - } - - // construct table of successive squares of bb*leafSize to use in subdivisions - // result (table != nil) <=> (len(x) > leafSize > 0) - table := divisors(len(x), b, ndigits, bb) - - // preserve x, create local copy for use by convertWords - q := nat(nil).set(x) - - // convert q to string s in base b - q.convertWords(s, charset, b, ndigits, bb, table) - - // strip leading zeros - // (x != 0; thus s must contain at least one non-zero digit - // and the loop will terminate) - i = 0 - for zero := charset[0]; s[i] == zero; { - i++ - } - } - - return string(s[i:]) -} - -// Convert words of q to base b digits in s. If q is large, it is recursively "split in half" -// by nat/nat division using tabulated divisors. Otherwise, it is converted iteratively using -// repeated nat/Word division. -// -// The iterative method processes n Words by n divW() calls, each of which visits every Word in the -// incrementally shortened q for a total of n + (n-1) + (n-2) ... + 2 + 1, or n(n+1)/2 divW()'s. -// Recursive conversion divides q by its approximate square root, yielding two parts, each half -// the size of q. Using the iterative method on both halves means 2 * (n/2)(n/2 + 1)/2 divW()'s -// plus the expensive long div(). Asymptotically, the ratio is favorable at 1/2 the divW()'s, and -// is made better by splitting the subblocks recursively. Best is to split blocks until one more -// split would take longer (because of the nat/nat div()) than the twice as many divW()'s of the -// 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 -// specific hardware. -// -func (q nat) convertWords(s []byte, charset string, b Word, ndigits int, bb Word, table []divisor) { - // split larger blocks recursively - if table != nil { - // len(q) > leafSize > 0 - var r nat - index := len(table) - 1 - for len(q) > leafSize { - // find divisor close to sqrt(q) if possible, but in any case < q - maxLength := q.bitLen() // ~= log2 q, or at of least largest possible q of this bit length - minLength := maxLength >> 1 // ~= log2 sqrt(q) - for index > 0 && table[index-1].nbits > minLength { - index-- // desired - } - if table[index].nbits >= maxLength && table[index].bbb.cmp(q) >= 0 { - index-- - if index < 0 { - panic("internal inconsistency") - } - } - - // split q into the two digit number (q'*bbb + r) to form independent subblocks - q, r = q.div(r, q, table[index].bbb) - - // convert subblocks and collect results in s[:h] and s[h:] - h := len(s) - table[index].ndigits - r.convertWords(s[h:], charset, b, ndigits, bb, table[0:index]) - s = s[:h] // == q.convertWords(s, charset, b, ndigits, bb, table[0:index+1]) - } - } - - // having split any large blocks now process the remaining (small) block iteratively - i := len(s) - var r Word - if b == 10 { - // hard-coding for 10 here speeds this up by 1.25x (allows for / and % by constants) - for len(q) > 0 { - // extract least significant, base bb "digit" - q, r = q.divW(q, bb) - for j := 0; j < ndigits && i > 0; j++ { - i-- - // avoid % computation since r%10 == r - int(r/10)*10; - // this appears to be faster for BenchmarkString10000Base10 - // and smaller strings (but a bit slower for larger ones) - t := r / 10 - s[i] = charset[r-t<<3-t-t] // TODO(gri) replace w/ t*10 once compiler produces better code - r = t - } - } - } else { - for len(q) > 0 { - // extract least significant, base bb "digit" - q, r = q.divW(q, bb) - for j := 0; j < ndigits && i > 0; j++ { - i-- - s[i] = charset[r%b] - r /= b - } - } - } - - // prepend high-order zeroes - zero := charset[0] - for i > 0 { // while need more leading zeroes - i-- - s[i] = zero - } -} - -// Split blocks greater than leafSize Words (or set to 0 to disable recursive conversion) -// Benchmark and configure leafSize using: go test -bench="Leaf" -// 8 and 16 effective on 3.0 GHz Xeon "Clovertown" CPU (128 byte cache lines) -// 8 and 16 effective on 2.66 GHz Core 2 Duo "Penryn" CPU -var leafSize int = 8 // number of Word-size binary values treat as a monolithic block - -type divisor struct { - bbb nat // divisor - nbits int // bit length of divisor (discounting leading zeroes) ~= log2(bbb) - ndigits int // digit length of divisor in terms of output base digits -} - -var cacheBase10 struct { - sync.Mutex - table [64]divisor // cached divisors for base 10 -} - -// expWW computes x**y -func (z nat) expWW(x, y Word) nat { - return z.expNN(nat(nil).setWord(x), nat(nil).setWord(y), nil) -} - -// construct table of powers of bb*leafSize to use in subdivisions -func divisors(m int, b Word, ndigits int, bb Word) []divisor { - // only compute table when recursive conversion is enabled and x is large - if leafSize == 0 || m <= leafSize { - return nil - } - - // determine k where (bb**leafSize)**(2**k) >= sqrt(x) - k := 1 - for words := leafSize; words < m>>1 && k < len(cacheBase10.table); words <<= 1 { - k++ - } - - // reuse and extend existing table of divisors or create new table as appropriate - var table []divisor // for b == 10, table overlaps with cacheBase10.table - if b == 10 { - cacheBase10.Lock() - table = cacheBase10.table[0:k] // reuse old table for this conversion - } else { - table = make([]divisor, k) // create new table for this conversion - } - - // extend table - if table[k-1].ndigits == 0 { - // add new entries as needed - var larger nat - for i := 0; i < k; i++ { - if table[i].ndigits == 0 { - if i == 0 { - table[0].bbb = nat(nil).expWW(bb, Word(leafSize)) - table[0].ndigits = ndigits * leafSize - } else { - table[i].bbb = nat(nil).mul(table[i-1].bbb, table[i-1].bbb) - table[i].ndigits = 2 * table[i-1].ndigits - } - - // optimization: exploit aggregated extra bits in macro blocks - larger = nat(nil).set(table[i].bbb) - for mulAddVWW(larger, larger, b, 0) == 0 { - table[i].bbb = table[i].bbb.set(larger) - table[i].ndigits++ - } - - table[i].nbits = table[i].bbb.bitLen() - } - } - } - - if b == 10 { - cacheBase10.Unlock() - } - - return table -} - const deBruijn32 = 0x077CB531 var deBruijn32Lookup = []byte{ @@ -1041,7 +688,7 @@ func (x nat) trailingZeroBits() uint { func (z nat) shl(x nat, s uint) nat { m := len(x) if m == 0 { - return z.make(0) + return z[:0] } // m > 0 @@ -1058,7 +705,7 @@ func (z nat) shr(x nat, s uint) nat { m := len(x) n := m - int(s/_W) if n <= 0 { - return z.make(0) + return z[:0] } // n > 0 @@ -1097,12 +744,36 @@ func (z nat) setBit(x nat, i uint, b uint) nat { panic("set bit is not 0 or 1") } -func (z nat) bit(i uint) uint { - j := int(i / _W) - if j >= len(z) { +// bit returns the value of the i'th bit, with lsb == bit 0. +func (x nat) bit(i uint) uint { + j := i / _W + if j >= uint(len(x)) { return 0 } - return uint(z[j] >> (i % _W) & 1) + // 0 <= j < len(x) + return uint(x[j] >> (i % _W) & 1) +} + +// sticky returns 1 if there's a 1 bit within the +// i least significant bits, otherwise it returns 0. +func (x nat) sticky(i uint) uint { + j := i / _W + if j >= uint(len(x)) { + if len(x) == 0 { + return 0 + } + return 1 + } + // 0 <= j < len(x) + for _, x := range x[:j] { + if x != 0 { + return 1 + } + } + if x[j]<<(_W-i%_W) != 0 { + return 1 + } + return 0 } func (z nat) and(x, y nat) nat { @@ -1176,7 +847,7 @@ func (z nat) xor(x, y nat) nat { return z.norm() } -// greaterThan returns true iff (x1<<_W + x2) > (y1<<_W + y2) +// greaterThan reports whether (x1<<_W + x2) > (y1<<_W + y2) func greaterThan(x1, x2, y1, y2 Word) bool { return x1 > y1 || x1 == y1 && x2 > y2 } @@ -1245,6 +916,13 @@ func (z nat) expNN(x, y, m nat) nat { } // y > 0 + // x**1 mod m == x mod m + if len(y) == 1 && y[0] == 1 && len(m) != 0 { + _, z = z.div(z, x, m) + return z + } + // y > 1 + if len(m) != 0 { // We likely end up being as long as the modulus. z = z.make(len(m)) @@ -1255,13 +933,16 @@ func (z nat) expNN(x, y, m nat) nat { // 4-bit, windowed exponentiation. This involves precomputing 14 values // (x^2...x^15) but then reduces the number of multiply-reduces by a // third. Even for a 32-bit exponent, this reduces the number of - // operations. + // operations. Uses Montgomery method for odd moduli. if len(x) > 1 && len(y) > 1 && len(m) > 0 { + if m[0]&1 == 1 { + return z.expNNMontgomery(x, y, m) + } return z.expNNWindowed(x, y, m) } v := y[len(y)-1] // v > 0 because y is normalized and y > 0 - shift := leadingZeros(v) + 1 + shift := nlz(v) + 1 v <<= shift var q nat @@ -1379,6 +1060,87 @@ func (z nat) expNNWindowed(x, y, m nat) nat { return z.norm() } +// expNNMontgomery calculates x**y mod m using a fixed, 4-bit window. +// Uses Montgomery representation. +func (z nat) expNNMontgomery(x, y, m nat) nat { + var zz, one, rr, RR nat + + numWords := len(m) + + // We want the lengths of x and m to be equal. + if len(x) > numWords { + _, rr = rr.div(rr, x, m) + } else if len(x) < numWords { + rr = rr.make(numWords) + rr.clear() + for i := range x { + rr[i] = x[i] + } + } else { + rr = x + } + x = rr + + // Ideally the precomputations would be performed outside, and reused + // k0 = -mˆ-1 mod 2ˆ_W. Algorithm from: Dumas, J.G. "On Newton–Raphson + // Iteration for Multiplicative Inverses Modulo Prime Powers". + k0 := 2 - m[0] + t := m[0] - 1 + for i := 1; i < _W; i <<= 1 { + t *= t + k0 *= (t + 1) + } + k0 = -k0 + + // RR = 2ˆ(2*_W*len(m)) mod m + RR = RR.setWord(1) + zz = zz.shl(RR, uint(2*numWords*_W)) + _, RR = RR.div(RR, zz, m) + if len(RR) < numWords { + zz = zz.make(numWords) + copy(zz, RR) + RR = zz + } + // one = 1, with equal length to that of m + one = one.make(numWords) + one.clear() + one[0] = 1 + + const n = 4 + // powers[i] contains x^i + var powers [1 << n]nat + powers[0] = powers[0].montgomery(one, RR, m, k0, numWords) + powers[1] = powers[1].montgomery(x, RR, m, k0, numWords) + for i := 2; i < 1<= 0; i-- { + yi := y[i] + for j := 0; j < _W; j += n { + if i != len(y)-1 || j != 0 { + zz = zz.montgomery(z, z, m, k0, numWords) + z = z.montgomery(zz, zz, m, k0, numWords) + zz = zz.montgomery(z, z, m, k0, numWords) + z = z.montgomery(zz, zz, m, k0, numWords) + } + zz = zz.montgomery(z, powers[yi>>(_W-n)], m, k0, numWords) + z, zz = zz, z + yi <<= n + } + } + // convert to regular number + zz = zz.montgomery(z, one, m, k0, numWords) + return zz.norm() +} + // probablyPrime performs reps Miller-Rabin tests to check whether n is prime. // If it returns true, n is prime with probability 1 - 1/4^reps. // If it returns false, n is not prime. @@ -1404,6 +1166,10 @@ func (n nat) probablyPrime(reps int) bool { } } + if n[0]&1 == 0 { + return false // n is even + } + const primesProduct32 = 0xC0CFD797 // Π {p ∈ primes, 2 < p <= 29} const primesProduct64 = 0xE221F97C30E94E1D // Π {p ∈ primes, 2 < p <= 53} diff --git a/libgo/go/math/big/nat_test.go b/libgo/go/math/big/nat_test.go index a2ae53385c9..7ac3cb8a846 100644 --- a/libgo/go/math/big/nat_test.go +++ b/libgo/go/math/big/nat_test.go @@ -5,7 +5,6 @@ package big import ( - "io" "runtime" "strings" "testing" @@ -88,7 +87,7 @@ var prodNN = []argNN{ } func natFromString(s string) nat { - x, _, err := nat(nil).scan(strings.NewReader(s), 0) + x, _, _, err := nat(nil).scan(strings.NewReader(s), 0, false) if err != nil { panic(err) } @@ -206,398 +205,11 @@ func BenchmarkMul(b *testing.B) { } } -func toString(x nat, charset string) string { - base := len(charset) - - // special cases - switch { - case base < 2: - panic("illegal base") - case len(x) == 0: - return string(charset[0]) - } - - // allocate buffer for conversion - i := x.bitLen()/log2(Word(base)) + 1 // +1: round up - s := make([]byte, i) - - // don't destroy x - q := nat(nil).set(x) - - // convert - for len(q) > 0 { - i-- - var r Word - q, r = q.divW(q, Word(base)) - s[i] = charset[r] - } - - return string(s[i:]) -} - -var strTests = []struct { - x nat // nat value to be converted - c string // conversion charset - s string // expected result -}{ - {nil, "01", "0"}, - {nat{1}, "01", "1"}, - {nat{0xc5}, "01", "11000101"}, - {nat{03271}, lowercaseDigits[0:8], "3271"}, - {nat{10}, lowercaseDigits[0:10], "10"}, - {nat{1234567890}, uppercaseDigits[0:10], "1234567890"}, - {nat{0xdeadbeef}, lowercaseDigits[0:16], "deadbeef"}, - {nat{0xdeadbeef}, uppercaseDigits[0:16], "DEADBEEF"}, - {nat{0x229be7}, lowercaseDigits[0:17], "1a2b3c"}, - {nat{0x309663e6}, uppercaseDigits[0:32], "O9COV6"}, -} - -func TestString(t *testing.T) { - for _, a := range strTests { - s := a.x.string(a.c) - if s != a.s { - t.Errorf("string%+v\n\tgot s = %s; want %s", a, s, a.s) - } - - x, b, err := nat(nil).scan(strings.NewReader(a.s), len(a.c)) - if x.cmp(a.x) != 0 { - t.Errorf("scan%+v\n\tgot z = %v; want %v", a, x, a.x) - } - if b != len(a.c) { - t.Errorf("scan%+v\n\tgot b = %d; want %d", a, b, len(a.c)) - } - if err != nil { - t.Errorf("scan%+v\n\tgot error = %s", a, err) - } - } -} - -var natScanTests = []struct { - s string // string to be scanned - base int // input base - x nat // expected nat - b int // expected base - ok bool // expected success - next rune // next character (or 0, if at EOF) -}{ - // error: illegal base - {base: -1}, - {base: 1}, - {base: 37}, - - // error: no mantissa - {}, - {s: "?"}, - {base: 10}, - {base: 36}, - {s: "?", base: 10}, - {s: "0x"}, - {s: "345", base: 2}, - - // no errors - {"0", 0, nil, 10, true, 0}, - {"0", 10, nil, 10, true, 0}, - {"0", 36, nil, 36, true, 0}, - {"1", 0, nat{1}, 10, true, 0}, - {"1", 10, nat{1}, 10, true, 0}, - {"0 ", 0, nil, 10, true, ' '}, - {"08", 0, nil, 10, true, '8'}, - {"018", 0, nat{1}, 8, true, '8'}, - {"0b1", 0, nat{1}, 2, true, 0}, - {"0b11000101", 0, nat{0xc5}, 2, true, 0}, - {"03271", 0, nat{03271}, 8, true, 0}, - {"10ab", 0, nat{10}, 10, true, 'a'}, - {"1234567890", 0, nat{1234567890}, 10, true, 0}, - {"xyz", 36, nat{(33*36+34)*36 + 35}, 36, true, 0}, - {"xyz?", 36, nat{(33*36+34)*36 + 35}, 36, true, '?'}, - {"0x", 16, nil, 16, true, 'x'}, - {"0xdeadbeef", 0, nat{0xdeadbeef}, 16, true, 0}, - {"0XDEADBEEF", 0, nat{0xdeadbeef}, 16, true, 0}, -} - -func TestScanBase(t *testing.T) { - for _, a := range natScanTests { - r := strings.NewReader(a.s) - x, b, err := nat(nil).scan(r, a.base) - if err == nil && !a.ok { - t.Errorf("scan%+v\n\texpected error", a) - } - if err != nil { - if a.ok { - t.Errorf("scan%+v\n\tgot error = %s", a, err) - } - continue - } - if x.cmp(a.x) != 0 { - t.Errorf("scan%+v\n\tgot z = %v; want %v", a, x, a.x) - } - if b != a.b { - t.Errorf("scan%+v\n\tgot b = %d; want %d", a, b, a.base) - } - next, _, err := r.ReadRune() - if err == io.EOF { - next = 0 - err = nil - } - if err == nil && next != a.next { - t.Errorf("scan%+v\n\tgot next = %q; want %q", a, next, a.next) - } - } -} - -var pi = "3" + - "14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651" + - "32823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461" + - "28475648233786783165271201909145648566923460348610454326648213393607260249141273724587006606315588174881520920" + - "96282925409171536436789259036001133053054882046652138414695194151160943305727036575959195309218611738193261179" + - "31051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798" + - "60943702770539217176293176752384674818467669405132000568127145263560827785771342757789609173637178721468440901" + - "22495343014654958537105079227968925892354201995611212902196086403441815981362977477130996051870721134999999837" + - "29780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083" + - "81420617177669147303598253490428755468731159562863882353787593751957781857780532171226806613001927876611195909" + - "21642019893809525720106548586327886593615338182796823030195203530185296899577362259941389124972177528347913151" + - "55748572424541506959508295331168617278558890750983817546374649393192550604009277016711390098488240128583616035" + - "63707660104710181942955596198946767837449448255379774726847104047534646208046684259069491293313677028989152104" + - "75216205696602405803815019351125338243003558764024749647326391419927260426992279678235478163600934172164121992" + - "45863150302861829745557067498385054945885869269956909272107975093029553211653449872027559602364806654991198818" + - "34797753566369807426542527862551818417574672890977772793800081647060016145249192173217214772350141441973568548" + - "16136115735255213347574184946843852332390739414333454776241686251898356948556209921922218427255025425688767179" + - "04946016534668049886272327917860857843838279679766814541009538837863609506800642251252051173929848960841284886" + - "26945604241965285022210661186306744278622039194945047123713786960956364371917287467764657573962413890865832645" + - "99581339047802759009946576407895126946839835259570982582262052248940772671947826848260147699090264013639443745" + - "53050682034962524517493996514314298091906592509372216964615157098583874105978859597729754989301617539284681382" + - "68683868942774155991855925245953959431049972524680845987273644695848653836736222626099124608051243884390451244" + - "13654976278079771569143599770012961608944169486855584840635342207222582848864815845602850601684273945226746767" + - "88952521385225499546667278239864565961163548862305774564980355936345681743241125150760694794510965960940252288" + - "79710893145669136867228748940560101503308617928680920874760917824938589009714909675985261365549781893129784821" + - "68299894872265880485756401427047755513237964145152374623436454285844479526586782105114135473573952311342716610" + - "21359695362314429524849371871101457654035902799344037420073105785390621983874478084784896833214457138687519435" + - "06430218453191048481005370614680674919278191197939952061419663428754440643745123718192179998391015919561814675" + - "14269123974894090718649423196156794520809514655022523160388193014209376213785595663893778708303906979207734672" + - "21825625996615014215030680384477345492026054146659252014974428507325186660021324340881907104863317346496514539" + - "05796268561005508106658796998163574736384052571459102897064140110971206280439039759515677157700420337869936007" + - "23055876317635942187312514712053292819182618612586732157919841484882916447060957527069572209175671167229109816" + - "90915280173506712748583222871835209353965725121083579151369882091444210067510334671103141267111369908658516398" + - "31501970165151168517143765761835155650884909989859982387345528331635507647918535893226185489632132933089857064" + - "20467525907091548141654985946163718027098199430992448895757128289059232332609729971208443357326548938239119325" + - "97463667305836041428138830320382490375898524374417029132765618093773444030707469211201913020330380197621101100" + - "44929321516084244485963766983895228684783123552658213144957685726243344189303968642624341077322697802807318915" + - "44110104468232527162010526522721116603966655730925471105578537634668206531098965269186205647693125705863566201" + - "85581007293606598764861179104533488503461136576867532494416680396265797877185560845529654126654085306143444318" + - "58676975145661406800700237877659134401712749470420562230538994561314071127000407854733269939081454664645880797" + - "27082668306343285878569830523580893306575740679545716377525420211495576158140025012622859413021647155097925923" + - "09907965473761255176567513575178296664547791745011299614890304639947132962107340437518957359614589019389713111" + - "79042978285647503203198691514028708085990480109412147221317947647772622414254854540332157185306142288137585043" + - "06332175182979866223717215916077166925474873898665494945011465406284336639379003976926567214638530673609657120" + - "91807638327166416274888800786925602902284721040317211860820419000422966171196377921337575114959501566049631862" + - "94726547364252308177036751590673502350728354056704038674351362222477158915049530984448933309634087807693259939" + - "78054193414473774418426312986080998886874132604721569516239658645730216315981931951673538129741677294786724229" + - "24654366800980676928238280689964004824354037014163149658979409243237896907069779422362508221688957383798623001" + - "59377647165122893578601588161755782973523344604281512627203734314653197777416031990665541876397929334419521541" + - "34189948544473456738316249934191318148092777710386387734317720754565453220777092120190516609628049092636019759" + - "88281613323166636528619326686336062735676303544776280350450777235547105859548702790814356240145171806246436267" + - "94561275318134078330336254232783944975382437205835311477119926063813346776879695970309833913077109870408591337" - -// Test case for BenchmarkScanPi. -func TestScanPi(t *testing.T) { - var x nat - z, _, err := x.scan(strings.NewReader(pi), 10) - if err != nil { - t.Errorf("scanning pi: %s", err) - } - if s := z.decimalString(); s != pi { - t.Errorf("scanning pi: got %s", s) - } -} - -func TestScanPiParallel(t *testing.T) { - const n = 2 - c := make(chan int) - for i := 0; i < n; i++ { - go func() { - TestScanPi(t) - c <- 0 - }() - } - for i := 0; i < n; i++ { - <-c - } -} - -func BenchmarkScanPi(b *testing.B) { - for i := 0; i < b.N; i++ { - var x nat - x.scan(strings.NewReader(pi), 10) - } -} - -func BenchmarkStringPiParallel(b *testing.B) { - var x nat - x, _, _ = x.scan(strings.NewReader(pi), 0) - if x.decimalString() != pi { - panic("benchmark incorrect: conversion failed") - } - b.RunParallel(func(pb *testing.PB) { - for pb.Next() { - x.decimalString() - } - }) -} - -func BenchmarkScan10Base2(b *testing.B) { ScanHelper(b, 2, 10, 10) } -func BenchmarkScan100Base2(b *testing.B) { ScanHelper(b, 2, 10, 100) } -func BenchmarkScan1000Base2(b *testing.B) { ScanHelper(b, 2, 10, 1000) } -func BenchmarkScan10000Base2(b *testing.B) { ScanHelper(b, 2, 10, 10000) } -func BenchmarkScan100000Base2(b *testing.B) { ScanHelper(b, 2, 10, 100000) } - -func BenchmarkScan10Base8(b *testing.B) { ScanHelper(b, 8, 10, 10) } -func BenchmarkScan100Base8(b *testing.B) { ScanHelper(b, 8, 10, 100) } -func BenchmarkScan1000Base8(b *testing.B) { ScanHelper(b, 8, 10, 1000) } -func BenchmarkScan10000Base8(b *testing.B) { ScanHelper(b, 8, 10, 10000) } -func BenchmarkScan100000Base8(b *testing.B) { ScanHelper(b, 8, 10, 100000) } - -func BenchmarkScan10Base10(b *testing.B) { ScanHelper(b, 10, 10, 10) } -func BenchmarkScan100Base10(b *testing.B) { ScanHelper(b, 10, 10, 100) } -func BenchmarkScan1000Base10(b *testing.B) { ScanHelper(b, 10, 10, 1000) } -func BenchmarkScan10000Base10(b *testing.B) { ScanHelper(b, 10, 10, 10000) } -func BenchmarkScan100000Base10(b *testing.B) { ScanHelper(b, 10, 10, 100000) } - -func BenchmarkScan10Base16(b *testing.B) { ScanHelper(b, 16, 10, 10) } -func BenchmarkScan100Base16(b *testing.B) { ScanHelper(b, 16, 10, 100) } -func BenchmarkScan1000Base16(b *testing.B) { ScanHelper(b, 16, 10, 1000) } -func BenchmarkScan10000Base16(b *testing.B) { ScanHelper(b, 16, 10, 10000) } -func BenchmarkScan100000Base16(b *testing.B) { ScanHelper(b, 16, 10, 100000) } - -func ScanHelper(b *testing.B, base int, x, y Word) { - b.StopTimer() - var z nat - z = z.expWW(x, y) - - var s string - s = z.string(lowercaseDigits[0:base]) - if t := toString(z, lowercaseDigits[0:base]); t != s { - b.Fatalf("scanning: got %s; want %s", s, t) - } - b.StartTimer() - - for i := 0; i < b.N; i++ { - z.scan(strings.NewReader(s), base) - } -} - -func BenchmarkString10Base2(b *testing.B) { StringHelper(b, 2, 10, 10) } -func BenchmarkString100Base2(b *testing.B) { StringHelper(b, 2, 10, 100) } -func BenchmarkString1000Base2(b *testing.B) { StringHelper(b, 2, 10, 1000) } -func BenchmarkString10000Base2(b *testing.B) { StringHelper(b, 2, 10, 10000) } -func BenchmarkString100000Base2(b *testing.B) { StringHelper(b, 2, 10, 100000) } - -func BenchmarkString10Base8(b *testing.B) { StringHelper(b, 8, 10, 10) } -func BenchmarkString100Base8(b *testing.B) { StringHelper(b, 8, 10, 100) } -func BenchmarkString1000Base8(b *testing.B) { StringHelper(b, 8, 10, 1000) } -func BenchmarkString10000Base8(b *testing.B) { StringHelper(b, 8, 10, 10000) } -func BenchmarkString100000Base8(b *testing.B) { StringHelper(b, 8, 10, 100000) } - -func BenchmarkString10Base10(b *testing.B) { StringHelper(b, 10, 10, 10) } -func BenchmarkString100Base10(b *testing.B) { StringHelper(b, 10, 10, 100) } -func BenchmarkString1000Base10(b *testing.B) { StringHelper(b, 10, 10, 1000) } -func BenchmarkString10000Base10(b *testing.B) { StringHelper(b, 10, 10, 10000) } -func BenchmarkString100000Base10(b *testing.B) { StringHelper(b, 10, 10, 100000) } - -func BenchmarkString10Base16(b *testing.B) { StringHelper(b, 16, 10, 10) } -func BenchmarkString100Base16(b *testing.B) { StringHelper(b, 16, 10, 100) } -func BenchmarkString1000Base16(b *testing.B) { StringHelper(b, 16, 10, 1000) } -func BenchmarkString10000Base16(b *testing.B) { StringHelper(b, 16, 10, 10000) } -func BenchmarkString100000Base16(b *testing.B) { StringHelper(b, 16, 10, 100000) } - -func StringHelper(b *testing.B, base int, x, y Word) { - b.StopTimer() - var z nat - z = z.expWW(x, y) - z.string(lowercaseDigits[0:base]) // warm divisor cache - b.StartTimer() - - for i := 0; i < b.N; i++ { - _ = z.string(lowercaseDigits[0:base]) - } -} - -func BenchmarkLeafSize0(b *testing.B) { LeafSizeHelper(b, 10, 0) } // test without splitting -func BenchmarkLeafSize1(b *testing.B) { LeafSizeHelper(b, 10, 1) } -func BenchmarkLeafSize2(b *testing.B) { LeafSizeHelper(b, 10, 2) } -func BenchmarkLeafSize3(b *testing.B) { LeafSizeHelper(b, 10, 3) } -func BenchmarkLeafSize4(b *testing.B) { LeafSizeHelper(b, 10, 4) } -func BenchmarkLeafSize5(b *testing.B) { LeafSizeHelper(b, 10, 5) } -func BenchmarkLeafSize6(b *testing.B) { LeafSizeHelper(b, 10, 6) } -func BenchmarkLeafSize7(b *testing.B) { LeafSizeHelper(b, 10, 7) } -func BenchmarkLeafSize8(b *testing.B) { LeafSizeHelper(b, 10, 8) } -func BenchmarkLeafSize9(b *testing.B) { LeafSizeHelper(b, 10, 9) } -func BenchmarkLeafSize10(b *testing.B) { LeafSizeHelper(b, 10, 10) } -func BenchmarkLeafSize11(b *testing.B) { LeafSizeHelper(b, 10, 11) } -func BenchmarkLeafSize12(b *testing.B) { LeafSizeHelper(b, 10, 12) } -func BenchmarkLeafSize13(b *testing.B) { LeafSizeHelper(b, 10, 13) } -func BenchmarkLeafSize14(b *testing.B) { LeafSizeHelper(b, 10, 14) } -func BenchmarkLeafSize15(b *testing.B) { LeafSizeHelper(b, 10, 15) } -func BenchmarkLeafSize16(b *testing.B) { LeafSizeHelper(b, 10, 16) } -func BenchmarkLeafSize32(b *testing.B) { LeafSizeHelper(b, 10, 32) } // try some large lengths -func BenchmarkLeafSize64(b *testing.B) { LeafSizeHelper(b, 10, 64) } - -func LeafSizeHelper(b *testing.B, base Word, size int) { - b.StopTimer() - originalLeafSize := leafSize - resetTable(cacheBase10.table[:]) - leafSize = size - b.StartTimer() - - for d := 1; d <= 10000; d *= 10 { - b.StopTimer() - var z nat - z = z.expWW(base, Word(d)) // build target number - _ = z.string(lowercaseDigits[0:base]) // warm divisor cache - b.StartTimer() - - for i := 0; i < b.N; i++ { - _ = z.string(lowercaseDigits[0:base]) - } - } - - b.StopTimer() - resetTable(cacheBase10.table[:]) - leafSize = originalLeafSize - b.StartTimer() -} - -func resetTable(table []divisor) { - if table != nil && table[0].bbb != nil { - for i := 0; i < len(table); i++ { - table[i].bbb = nil - table[i].nbits = 0 - table[i].ndigits = 0 - } - } -} - -func TestStringPowers(t *testing.T) { - var b, p Word - for b = 2; b <= 16; b++ { - for p = 0; p <= 512; p++ { - x := nat(nil).expWW(b, p) - xs := x.string(lowercaseDigits[0:b]) - xs2 := toString(x, lowercaseDigits[0:b]) - if xs != xs2 { - t.Errorf("failed at %d ** %d in base %d: %s != %s", b, p, b, xs, xs2) - } - } - if b >= 3 && testing.Short() { - break - } - } -} - -func TestLeadingZeros(t *testing.T) { +func TestNLZ(t *testing.T) { var x Word = _B >> 1 for i := 0; i <= _W; i++ { - if int(leadingZeros(x)) != i { - t.Errorf("failed at %x: got %d want %d", x, leadingZeros(x), i) + if int(nlz(x)) != i { + t.Errorf("failed at %x: got %d want %d", x, nlz(x), i) } x >>= 1 } @@ -691,25 +303,96 @@ func TestModW(t *testing.T) { } func TestTrailingZeroBits(t *testing.T) { + // test 0 case explicitly + if n := trailingZeroBits(0); n != 0 { + t.Errorf("got trailingZeroBits(0) = %d; want 0", n) + } + x := Word(1) - for i := uint(0); i <= _W; i++ { + for i := uint(0); i < _W; i++ { n := trailingZeroBits(x) - if n != i%_W { + if n != i { t.Errorf("got trailingZeroBits(%#x) = %d; want %d", x, n, i%_W) } x <<= 1 } + // test 0 case explicitly + if n := nat(nil).trailingZeroBits(); n != 0 { + t.Errorf("got nat(nil).trailingZeroBits() = %d; want 0", n) + } + y := nat(nil).set(natOne) for i := uint(0); i <= 3*_W; i++ { n := y.trailingZeroBits() if n != i { - t.Errorf("got 0x%s.trailingZeroBits() = %d; want %d", y.string(lowercaseDigits[0:16]), n, i) + t.Errorf("got 0x%s.trailingZeroBits() = %d; want %d", y.hexString(), n, i) } y = y.shl(y, 1) } } +var montgomeryTests = []struct { + x, y, m string + k0 uint64 + out32, out64 string +}{ + { + "0xffffffffffffffffffffffffffffffffffffffffffffffffe", + "0xffffffffffffffffffffffffffffffffffffffffffffffffe", + "0xfffffffffffffffffffffffffffffffffffffffffffffffff", + 0x0000000000000000, + "0xffffffffffffffffffffffffffffffffffffffffff", + "0xffffffffffffffffffffffffffffffffff", + }, + { + "0x0000000080000000", + "0x00000000ffffffff", + "0x0000000010000001", + 0xff0000000fffffff, + "0x0000000088000000", + "0x0000000007800001", + }, + { + "0xffffffffffffffffffffffffffffffff00000000000022222223333333333444444444", + "0xffffffffffffffffffffffffffffffff999999999999999aaabbbbbbbbcccccccccccc", + "0x33377fffffffffffffffffffffffffffffffffffffffffffff0000000000022222eee1", + 0xdecc8f1249812adf, + "0x22bb05b6d95eaaeca2bb7c05e51f807bce9064b5fbad177161695e4558f9474e91cd79", + "0x14beb58d230f85b6d95eaaeca2bb7c05e51f807bce9064b5fb45669afa695f228e48cd", + }, + { + "0x10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffff00000000000022222223333333333444444444", + "0x10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffff999999999999999aaabbbbbbbbcccccccccccc", + "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff33377fffffffffffffffffffffffffffffffffffffffffffff0000000000022222eee1", + 0xdecc8f1249812adf, + "0x5c0d52f451aec609b15da8e5e5626c4eaa88723bdeac9d25ca9b961269400410ca208a16af9c2fb07d7a11c7772cba02c22f9711078d51a3797eb18e691295293284d988e349fa6deba46b25a4ecd9f715", + "0x92fcad4b5c0d52f451aec609b15da8e5e5626c4eaa88723bdeac9d25ca9b961269400410ca208a16af9c2fb07d799c32fe2f3cc5422f9711078d51a3797eb18e691295293284d8f5e69caf6decddfe1df6", + }, +} + +func TestMontgomery(t *testing.T) { + for i, test := range montgomeryTests { + x := natFromString(test.x) + y := natFromString(test.y) + m := natFromString(test.m) + + var out nat + if _W == 32 { + out = natFromString(test.out32) + } else { + out = natFromString(test.out64) + } + + k0 := Word(test.k0 & _M) // mask k0 to ensure that it fits for 32-bit systems. + z := nat(nil).montgomery(x, y, m, k0, len(m)) + z = z.norm() + if z.cmp(out) != 0 { + t.Errorf("#%d got %s want %s", i, z.decimalString(), out.decimalString()) + } + } +} + var expNNTests = []struct { x, y, m string out string @@ -735,14 +418,13 @@ var expNNTests = []struct { func TestExpNN(t *testing.T) { for i, test := range expNNTests { - x, _, _ := nat(nil).scan(strings.NewReader(test.x), 0) - y, _, _ := nat(nil).scan(strings.NewReader(test.y), 0) - out, _, _ := nat(nil).scan(strings.NewReader(test.out), 0) + x := natFromString(test.x) + y := natFromString(test.y) + out := natFromString(test.out) var m nat - if len(test.m) > 0 { - m, _, _ = nat(nil).scan(strings.NewReader(test.m), 0) + m = natFromString(test.m) } z := nat(nil).expNN(x, y, m) @@ -769,3 +451,129 @@ func BenchmarkExp3Power0x10000(b *testing.B) { ExpHelper(b, 3, 0x10000) } func BenchmarkExp3Power0x40000(b *testing.B) { ExpHelper(b, 3, 0x40000) } func BenchmarkExp3Power0x100000(b *testing.B) { ExpHelper(b, 3, 0x100000) } func BenchmarkExp3Power0x400000(b *testing.B) { ExpHelper(b, 3, 0x400000) } + +func fibo(n int) nat { + switch n { + case 0: + return nil + case 1: + return nat{1} + } + f0 := fibo(0) + f1 := fibo(1) + var f2 nat + for i := 1; i < n; i++ { + f2 = f2.add(f0, f1) + f0, f1, f2 = f1, f2, f0 + } + return f1 +} + +var fiboNums = []string{ + "0", + "55", + "6765", + "832040", + "102334155", + "12586269025", + "1548008755920", + "190392490709135", + "23416728348467685", + "2880067194370816120", + "354224848179261915075", +} + +func TestFibo(t *testing.T) { + for i, want := range fiboNums { + n := i * 10 + got := fibo(n).decimalString() + if got != want { + t.Errorf("fibo(%d) failed: got %s want %s", n, got, want) + } + } +} + +func BenchmarkFibo(b *testing.B) { + for i := 0; i < b.N; i++ { + fibo(1e0) + fibo(1e1) + fibo(1e2) + fibo(1e3) + fibo(1e4) + fibo(1e5) + } +} + +var bitTests = []struct { + x string + i uint + want uint +}{ + {"0", 0, 0}, + {"0", 1, 0}, + {"0", 1000, 0}, + + {"0x1", 0, 1}, + {"0x10", 0, 0}, + {"0x10", 3, 0}, + {"0x10", 4, 1}, + {"0x10", 5, 0}, + + {"0x8000000000000000", 62, 0}, + {"0x8000000000000000", 63, 1}, + {"0x8000000000000000", 64, 0}, + + {"0x3" + strings.Repeat("0", 32), 127, 0}, + {"0x3" + strings.Repeat("0", 32), 128, 1}, + {"0x3" + strings.Repeat("0", 32), 129, 1}, + {"0x3" + strings.Repeat("0", 32), 130, 0}, +} + +func TestBit(t *testing.T) { + for i, test := range bitTests { + x := natFromString(test.x) + if got := x.bit(test.i); got != test.want { + t.Errorf("#%d: %s.bit(%d) = %v; want %v", i, test.x, test.i, got, test.want) + } + } +} + +var stickyTests = []struct { + x string + i uint + want uint +}{ + {"0", 0, 0}, + {"0", 1, 0}, + {"0", 1000, 0}, + + {"0x1", 0, 0}, + {"0x1", 1, 1}, + + {"0x1350", 0, 0}, + {"0x1350", 4, 0}, + {"0x1350", 5, 1}, + + {"0x8000000000000000", 63, 0}, + {"0x8000000000000000", 64, 1}, + + {"0x1" + strings.Repeat("0", 100), 400, 0}, + {"0x1" + strings.Repeat("0", 100), 401, 1}, +} + +func TestSticky(t *testing.T) { + for i, test := range stickyTests { + x := natFromString(test.x) + if got := x.sticky(test.i); got != test.want { + t.Errorf("#%d: %s.sticky(%d) = %v; want %v", i, test.x, test.i, got, test.want) + } + if test.want == 1 { + // all subsequent i's should also return 1 + for d := uint(1); d <= 3; d++ { + if got := x.sticky(test.i + d); got != 1 { + t.Errorf("#%d: %s.sticky(%d) = %v; want %v", i, test.x, test.i+d, got, 1) + } + } + } + } +} diff --git a/libgo/go/math/big/natconv.go b/libgo/go/math/big/natconv.go new file mode 100644 index 00000000000..022dcfe38c8 --- /dev/null +++ b/libgo/go/math/big/natconv.go @@ -0,0 +1,495 @@ +// Copyright 2015 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 nat-to-string conversion functions. + +package big + +import ( + "errors" + "fmt" + "io" + "math" + "sync" +) + +// MaxBase is the largest number base accepted for string conversions. +const MaxBase = 'z' - 'a' + 10 + 1 + +// maxPow returns (b**n, n) such that b**n is the largest power b**n <= _M. +// For instance maxPow(10) == (1e19, 19) for 19 decimal digits in a 64bit Word. +// In other words, at most n digits in base b fit into a Word. +// TODO(gri) replace this with a table, generated at build time. +func maxPow(b Word) (p Word, n int) { + p, n = b, 1 // assuming b <= _M + for max := _M / b; p <= max; { + // p == b**n && p <= max + p *= b + n++ + } + // p == b**n && p <= _M + return +} + +// pow returns x**n for n > 0, and 1 otherwise. +func pow(x Word, n int) (p Word) { + // n == sum of bi * 2**i, for 0 <= i < imax, and bi is 0 or 1 + // thus x**n == product of x**(2**i) for all i where bi == 1 + // (Russian Peasant Method for exponentiation) + p = 1 + for n > 0 { + if n&1 != 0 { + p *= x + } + x *= x + n >>= 1 + } + return +} + +// scan scans the number corresponding to the longest possible prefix +// from r representing an unsigned number in a given conversion base. +// It returns the corresponding natural number res, the actual base b, +// a digit count, and a read or syntax error err, if any. +// +// number = [ prefix ] mantissa . +// prefix = "0" [ "x" | "X" | "b" | "B" ] . +// mantissa = digits | digits "." [ digits ] | "." digits . +// digits = digit { digit } . +// digit = "0" ... "9" | "a" ... "z" | "A" ... "Z" . +// +// Unless fracOk is set, the base argument must be 0 or a value between +// 2 and MaxBase. If fracOk is set, the base argument must be one of +// 0, 2, 10, or 16. Providing an invalid base argument leads to a run- +// time panic. +// +// For base 0, the number prefix determines the actual base: A prefix of +// ``0x'' or ``0X'' selects base 16; if fracOk is not set, the ``0'' prefix +// selects base 8, and a ``0b'' or ``0B'' prefix selects base 2. Otherwise +// the selected base is 10 and no prefix is accepted. +// +// If fracOk is set, an octal prefix is ignored (a leading ``0'' simply +// stands for a zero digit), and a period followed by a fractional part +// is permitted. The result value is computed as if there were no period +// present; and the count value is used to determine the fractional part. +// +// A result digit count > 0 corresponds to the number of (non-prefix) digits +// parsed. A digit count <= 0 indicates the presence of a period (if fracOk +// is set, only), and -count is the number of fractional digits found. +// In this case, the actual value of the scanned number is res * b**count. +// +func (z nat) scan(r io.ByteScanner, base int, fracOk bool) (res nat, b, count int, err error) { + // reject illegal bases + baseOk := base == 0 || + !fracOk && 2 <= base && base <= MaxBase || + fracOk && (base == 2 || base == 10 || base == 16) + if !baseOk { + panic(fmt.Sprintf("illegal number base %d", base)) + } + + // one char look-ahead + ch, err := r.ReadByte() + if err != nil { + return + } + + // determine actual base + b = base + if base == 0 { + // actual base is 10 unless there's a base prefix + b = 10 + if ch == '0' { + count = 1 + switch ch, err = r.ReadByte(); err { + case nil: + // possibly one of 0x, 0X, 0b, 0B + if !fracOk { + b = 8 + } + switch ch { + case 'x', 'X': + b = 16 + case 'b', 'B': + b = 2 + } + switch b { + case 16, 2: + count = 0 // prefix is not counted + if ch, err = r.ReadByte(); err != nil { + // io.EOF is also an error in this case + return + } + case 8: + count = 0 // prefix is not counted + } + case io.EOF: + // input is "0" + res = z[:0] + err = nil + return + default: + // read error + return + } + } + } + + // convert string + // Algorithm: Collect digits in groups of at most n digits in di + // and then use mulAddWW for every such group to add them to the + // result. + z = z[:0] + b1 := Word(b) + bn, n := maxPow(b1) // at most n digits in base b1 fit into Word + di := Word(0) // 0 <= di < b1**i < bn + i := 0 // 0 <= i < n + dp := -1 // position of decimal point + for { + if fracOk && ch == '.' { + fracOk = false + dp = count + // advance + if ch, err = r.ReadByte(); err != nil { + if err == io.EOF { + err = nil + break + } + return + } + } + + // convert rune into digit value d1 + var d1 Word + switch { + case '0' <= ch && ch <= '9': + d1 = Word(ch - '0') + case 'a' <= ch && ch <= 'z': + d1 = Word(ch - 'a' + 10) + case 'A' <= ch && ch <= 'Z': + d1 = Word(ch - 'A' + 10) + default: + d1 = MaxBase + 1 + } + if d1 >= b1 { + r.UnreadByte() // ch does not belong to number anymore + break + } + count++ + + // collect d1 in di + di = di*b1 + d1 + i++ + + // if di is "full", add it to the result + if i == n { + z = z.mulAddWW(z, bn, di) + di = 0 + i = 0 + } + + // advance + if ch, err = r.ReadByte(); err != nil { + if err == io.EOF { + err = nil + break + } + return + } + } + + if count == 0 { + // no digits found + switch { + case base == 0 && b == 8: + // there was only the octal prefix 0 (possibly followed by digits > 7); + // count as one digit and return base 10, not 8 + count = 1 + b = 10 + case base != 0 || b != 8: + // there was neither a mantissa digit nor the octal prefix 0 + err = errors.New("syntax error scanning number") + } + return + } + // count > 0 + + // add remaining digits to result + if i > 0 { + z = z.mulAddWW(z, pow(b1, i), di) + } + res = z.norm() + + // adjust for fraction, if any + if dp >= 0 { + // 0 <= dp <= count > 0 + count = dp - count + } + + return +} + +// Character sets for string conversion. +const ( + lowercaseDigits = "0123456789abcdefghijklmnopqrstuvwxyz" + uppercaseDigits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" +) + +// decimalString returns a decimal representation of x. +// It calls x.string with the charset "0123456789". +func (x nat) decimalString() string { + return x.string(lowercaseDigits[:10]) +} + +// hexString returns a hexadecimal representation of x. +// It calls x.string with the charset "0123456789abcdef". +func (x nat) hexString() string { + return x.string(lowercaseDigits[:16]) +} + +// string converts x to a string using digits from a charset; a digit with +// value d is represented by charset[d]. The conversion base is determined +// by len(charset), which must be >= 2 and <= 256. +func (x nat) string(charset string) string { + b := Word(len(charset)) + + // special cases + switch { + case b < 2 || b > 256: + panic("invalid character set length") + case len(x) == 0: + return string(charset[0]) + } + + // allocate buffer for conversion + i := int(float64(x.bitLen())/math.Log2(float64(b))) + 1 // off by one at most + s := make([]byte, i) + + // convert power of two and non power of two bases separately + if b == b&-b { + // shift is base-b digit size in bits + shift := trailingZeroBits(b) // shift > 0 because b >= 2 + mask := Word(1)<= shift { + i-- + s[i] = charset[w&mask] + w >>= shift + nbits -= shift + } + + // convert any partial leading digit and advance to next word + if nbits == 0 { + // no partial digit remaining, just advance + w = x[k] + nbits = _W + } else { + // partial digit in current (k-1) and next (k) word + w |= x[k] << nbits + i-- + s[i] = charset[w&mask] + + // advance + w = x[k] >> (shift - nbits) + nbits = _W - (shift - nbits) + } + } + + // convert digits of most-significant word (omit leading zeros) + for nbits >= 0 && w != 0 { + i-- + s[i] = charset[w&mask] + w >>= shift + nbits -= shift + } + + } else { + bb, ndigits := maxPow(Word(b)) + + // construct table of successive squares of bb*leafSize to use in subdivisions + // result (table != nil) <=> (len(x) > leafSize > 0) + table := divisors(len(x), b, ndigits, bb) + + // preserve x, create local copy for use by convertWords + q := nat(nil).set(x) + + // convert q to string s in base b + q.convertWords(s, charset, b, ndigits, bb, table) + + // strip leading zeros + // (x != 0; thus s must contain at least one non-zero digit + // and the loop will terminate) + i = 0 + for zero := charset[0]; s[i] == zero; { + i++ + } + } + + return string(s[i:]) +} + +// Convert words of q to base b digits in s. If q is large, it is recursively "split in half" +// by nat/nat division using tabulated divisors. Otherwise, it is converted iteratively using +// repeated nat/Word division. +// +// The iterative method processes n Words by n divW() calls, each of which visits every Word in the +// incrementally shortened q for a total of n + (n-1) + (n-2) ... + 2 + 1, or n(n+1)/2 divW()'s. +// Recursive conversion divides q by its approximate square root, yielding two parts, each half +// the size of q. Using the iterative method on both halves means 2 * (n/2)(n/2 + 1)/2 divW()'s +// plus the expensive long div(). Asymptotically, the ratio is favorable at 1/2 the divW()'s, and +// is made better by splitting the subblocks recursively. Best is to split blocks until one more +// split would take longer (because of the nat/nat div()) than the twice as many divW()'s of the +// 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 +// specific hardware. +// +func (q nat) convertWords(s []byte, charset string, b Word, ndigits int, bb Word, table []divisor) { + // split larger blocks recursively + if table != nil { + // len(q) > leafSize > 0 + var r nat + index := len(table) - 1 + for len(q) > leafSize { + // find divisor close to sqrt(q) if possible, but in any case < q + maxLength := q.bitLen() // ~= log2 q, or at of least largest possible q of this bit length + minLength := maxLength >> 1 // ~= log2 sqrt(q) + for index > 0 && table[index-1].nbits > minLength { + index-- // desired + } + if table[index].nbits >= maxLength && table[index].bbb.cmp(q) >= 0 { + index-- + if index < 0 { + panic("internal inconsistency") + } + } + + // split q into the two digit number (q'*bbb + r) to form independent subblocks + q, r = q.div(r, q, table[index].bbb) + + // convert subblocks and collect results in s[:h] and s[h:] + h := len(s) - table[index].ndigits + r.convertWords(s[h:], charset, b, ndigits, bb, table[0:index]) + s = s[:h] // == q.convertWords(s, charset, b, ndigits, bb, table[0:index+1]) + } + } + + // having split any large blocks now process the remaining (small) block iteratively + i := len(s) + var r Word + if b == 10 { + // hard-coding for 10 here speeds this up by 1.25x (allows for / and % by constants) + for len(q) > 0 { + // extract least significant, base bb "digit" + q, r = q.divW(q, bb) + for j := 0; j < ndigits && i > 0; j++ { + i-- + // avoid % computation since r%10 == r - int(r/10)*10; + // this appears to be faster for BenchmarkString10000Base10 + // and smaller strings (but a bit slower for larger ones) + t := r / 10 + s[i] = charset[r-t<<3-t-t] // TODO(gri) replace w/ t*10 once compiler produces better code + r = t + } + } + } else { + for len(q) > 0 { + // extract least significant, base bb "digit" + q, r = q.divW(q, bb) + for j := 0; j < ndigits && i > 0; j++ { + i-- + s[i] = charset[r%b] + r /= b + } + } + } + + // prepend high-order zeroes + zero := charset[0] + for i > 0 { // while need more leading zeroes + i-- + s[i] = zero + } +} + +// Split blocks greater than leafSize Words (or set to 0 to disable recursive conversion) +// Benchmark and configure leafSize using: go test -bench="Leaf" +// 8 and 16 effective on 3.0 GHz Xeon "Clovertown" CPU (128 byte cache lines) +// 8 and 16 effective on 2.66 GHz Core 2 Duo "Penryn" CPU +var leafSize int = 8 // number of Word-size binary values treat as a monolithic block + +type divisor struct { + bbb nat // divisor + nbits int // bit length of divisor (discounting leading zeroes) ~= log2(bbb) + ndigits int // digit length of divisor in terms of output base digits +} + +var cacheBase10 struct { + sync.Mutex + table [64]divisor // cached divisors for base 10 +} + +// expWW computes x**y +func (z nat) expWW(x, y Word) nat { + return z.expNN(nat(nil).setWord(x), nat(nil).setWord(y), nil) +} + +// construct table of powers of bb*leafSize to use in subdivisions +func divisors(m int, b Word, ndigits int, bb Word) []divisor { + // only compute table when recursive conversion is enabled and x is large + if leafSize == 0 || m <= leafSize { + return nil + } + + // determine k where (bb**leafSize)**(2**k) >= sqrt(x) + k := 1 + for words := leafSize; words < m>>1 && k < len(cacheBase10.table); words <<= 1 { + k++ + } + + // reuse and extend existing table of divisors or create new table as appropriate + var table []divisor // for b == 10, table overlaps with cacheBase10.table + if b == 10 { + cacheBase10.Lock() + table = cacheBase10.table[0:k] // reuse old table for this conversion + } else { + table = make([]divisor, k) // create new table for this conversion + } + + // extend table + if table[k-1].ndigits == 0 { + // add new entries as needed + var larger nat + for i := 0; i < k; i++ { + if table[i].ndigits == 0 { + if i == 0 { + table[0].bbb = nat(nil).expWW(bb, Word(leafSize)) + table[0].ndigits = ndigits * leafSize + } else { + table[i].bbb = nat(nil).mul(table[i-1].bbb, table[i-1].bbb) + table[i].ndigits = 2 * table[i-1].ndigits + } + + // optimization: exploit aggregated extra bits in macro blocks + larger = nat(nil).set(table[i].bbb) + for mulAddVWW(larger, larger, b, 0) == 0 { + table[i].bbb = table[i].bbb.set(larger) + table[i].ndigits++ + } + + table[i].nbits = table[i].bbb.bitLen() + } + } + } + + if b == 10 { + cacheBase10.Unlock() + } + + return table +} diff --git a/libgo/go/math/big/natconv_test.go b/libgo/go/math/big/natconv_test.go new file mode 100644 index 00000000000..f321fbc2df0 --- /dev/null +++ b/libgo/go/math/big/natconv_test.go @@ -0,0 +1,425 @@ +// Copyright 2015 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 big + +import ( + "io" + "strings" + "testing" +) + +func toString(x nat, charset string) string { + base := len(charset) + + // special cases + switch { + case base < 2: + panic("illegal base") + case len(x) == 0: + return string(charset[0]) + } + + // allocate buffer for conversion + i := x.bitLen()/log2(Word(base)) + 1 // +1: round up + s := make([]byte, i) + + // don't destroy x + q := nat(nil).set(x) + + // convert + for len(q) > 0 { + i-- + var r Word + q, r = q.divW(q, Word(base)) + s[i] = charset[r] + } + + return string(s[i:]) +} + +var strTests = []struct { + x nat // nat value to be converted + c string // conversion charset + s string // expected result +}{ + {nil, "01", "0"}, + {nat{1}, "01", "1"}, + {nat{0xc5}, "01", "11000101"}, + {nat{03271}, lowercaseDigits[:8], "3271"}, + {nat{10}, lowercaseDigits[:10], "10"}, + {nat{1234567890}, uppercaseDigits[:10], "1234567890"}, + {nat{0xdeadbeef}, lowercaseDigits[:16], "deadbeef"}, + {nat{0xdeadbeef}, uppercaseDigits[:16], "DEADBEEF"}, + {nat{0x229be7}, lowercaseDigits[:17], "1a2b3c"}, + {nat{0x309663e6}, uppercaseDigits[:32], "O9COV6"}, +} + +func TestString(t *testing.T) { + // test invalid character set explicitly + var panicStr string + func() { + defer func() { + panicStr = recover().(string) + }() + natOne.string("0") + }() + if panicStr != "invalid character set length" { + t.Errorf("expected panic for invalid character set") + } + + for _, a := range strTests { + s := a.x.string(a.c) + if s != a.s { + t.Errorf("string%+v\n\tgot s = %s; want %s", a, s, a.s) + } + + x, b, _, err := nat(nil).scan(strings.NewReader(a.s), len(a.c), false) + if x.cmp(a.x) != 0 { + t.Errorf("scan%+v\n\tgot z = %v; want %v", a, x, a.x) + } + if b != len(a.c) { + t.Errorf("scan%+v\n\tgot b = %d; want %d", a, b, len(a.c)) + } + if err != nil { + t.Errorf("scan%+v\n\tgot error = %s", a, err) + } + } +} + +var natScanTests = []struct { + s string // string to be scanned + base int // input base + frac bool // fraction ok + x nat // expected nat + b int // expected base + count int // expected digit count + ok bool // expected success + next rune // next character (or 0, if at EOF) +}{ + // error: no mantissa + {}, + {s: "?"}, + {base: 10}, + {base: 36}, + {s: "?", base: 10}, + {s: "0x"}, + {s: "345", base: 2}, + + // error: incorrect use of decimal point + {s: ".0"}, + {s: ".0", base: 10}, + {s: ".", base: 0}, + {s: "0x.0"}, + + // no errors + {"0", 0, false, nil, 10, 1, true, 0}, + {"0", 10, false, nil, 10, 1, true, 0}, + {"0", 36, false, nil, 36, 1, true, 0}, + {"1", 0, false, nat{1}, 10, 1, true, 0}, + {"1", 10, false, nat{1}, 10, 1, true, 0}, + {"0 ", 0, false, nil, 10, 1, true, ' '}, + {"08", 0, false, nil, 10, 1, true, '8'}, + {"08", 10, false, nat{8}, 10, 2, true, 0}, + {"018", 0, false, nat{1}, 8, 1, true, '8'}, + {"0b1", 0, false, nat{1}, 2, 1, true, 0}, + {"0b11000101", 0, false, nat{0xc5}, 2, 8, true, 0}, + {"03271", 0, false, nat{03271}, 8, 4, true, 0}, + {"10ab", 0, false, nat{10}, 10, 2, true, 'a'}, + {"1234567890", 0, false, nat{1234567890}, 10, 10, true, 0}, + {"xyz", 36, false, nat{(33*36+34)*36 + 35}, 36, 3, true, 0}, + {"xyz?", 36, false, nat{(33*36+34)*36 + 35}, 36, 3, true, '?'}, + {"0x", 16, false, nil, 16, 1, true, 'x'}, + {"0xdeadbeef", 0, false, nat{0xdeadbeef}, 16, 8, true, 0}, + {"0XDEADBEEF", 0, false, nat{0xdeadbeef}, 16, 8, true, 0}, + + // no errors, decimal point + {"0.", 0, false, nil, 10, 1, true, '.'}, + {"0.", 10, true, nil, 10, 0, true, 0}, + {"0.1.2", 10, true, nat{1}, 10, -1, true, '.'}, + {".000", 10, true, nil, 10, -3, true, 0}, + {"12.3", 10, true, nat{123}, 10, -1, true, 0}, + {"012.345", 10, true, nat{12345}, 10, -3, true, 0}, +} + +func TestScanBase(t *testing.T) { + for _, a := range natScanTests { + r := strings.NewReader(a.s) + x, b, count, err := nat(nil).scan(r, a.base, a.frac) + if err == nil && !a.ok { + t.Errorf("scan%+v\n\texpected error", a) + } + if err != nil { + if a.ok { + t.Errorf("scan%+v\n\tgot error = %s", a, err) + } + continue + } + if x.cmp(a.x) != 0 { + t.Errorf("scan%+v\n\tgot z = %v; want %v", a, x, a.x) + } + if b != a.b { + t.Errorf("scan%+v\n\tgot b = %d; want %d", a, b, a.base) + } + if count != a.count { + t.Errorf("scan%+v\n\tgot count = %d; want %d", a, count, a.count) + } + next, _, err := r.ReadRune() + if err == io.EOF { + next = 0 + err = nil + } + if err == nil && next != a.next { + t.Errorf("scan%+v\n\tgot next = %q; want %q", a, next, a.next) + } + } +} + +var pi = "3" + + "14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651" + + "32823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461" + + "28475648233786783165271201909145648566923460348610454326648213393607260249141273724587006606315588174881520920" + + "96282925409171536436789259036001133053054882046652138414695194151160943305727036575959195309218611738193261179" + + "31051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798" + + "60943702770539217176293176752384674818467669405132000568127145263560827785771342757789609173637178721468440901" + + "22495343014654958537105079227968925892354201995611212902196086403441815981362977477130996051870721134999999837" + + "29780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083" + + "81420617177669147303598253490428755468731159562863882353787593751957781857780532171226806613001927876611195909" + + "21642019893809525720106548586327886593615338182796823030195203530185296899577362259941389124972177528347913151" + + "55748572424541506959508295331168617278558890750983817546374649393192550604009277016711390098488240128583616035" + + "63707660104710181942955596198946767837449448255379774726847104047534646208046684259069491293313677028989152104" + + "75216205696602405803815019351125338243003558764024749647326391419927260426992279678235478163600934172164121992" + + "45863150302861829745557067498385054945885869269956909272107975093029553211653449872027559602364806654991198818" + + "34797753566369807426542527862551818417574672890977772793800081647060016145249192173217214772350141441973568548" + + "16136115735255213347574184946843852332390739414333454776241686251898356948556209921922218427255025425688767179" + + "04946016534668049886272327917860857843838279679766814541009538837863609506800642251252051173929848960841284886" + + "26945604241965285022210661186306744278622039194945047123713786960956364371917287467764657573962413890865832645" + + "99581339047802759009946576407895126946839835259570982582262052248940772671947826848260147699090264013639443745" + + "53050682034962524517493996514314298091906592509372216964615157098583874105978859597729754989301617539284681382" + + "68683868942774155991855925245953959431049972524680845987273644695848653836736222626099124608051243884390451244" + + "13654976278079771569143599770012961608944169486855584840635342207222582848864815845602850601684273945226746767" + + "88952521385225499546667278239864565961163548862305774564980355936345681743241125150760694794510965960940252288" + + "79710893145669136867228748940560101503308617928680920874760917824938589009714909675985261365549781893129784821" + + "68299894872265880485756401427047755513237964145152374623436454285844479526586782105114135473573952311342716610" + + "21359695362314429524849371871101457654035902799344037420073105785390621983874478084784896833214457138687519435" + + "06430218453191048481005370614680674919278191197939952061419663428754440643745123718192179998391015919561814675" + + "14269123974894090718649423196156794520809514655022523160388193014209376213785595663893778708303906979207734672" + + "21825625996615014215030680384477345492026054146659252014974428507325186660021324340881907104863317346496514539" + + "05796268561005508106658796998163574736384052571459102897064140110971206280439039759515677157700420337869936007" + + "23055876317635942187312514712053292819182618612586732157919841484882916447060957527069572209175671167229109816" + + "90915280173506712748583222871835209353965725121083579151369882091444210067510334671103141267111369908658516398" + + "31501970165151168517143765761835155650884909989859982387345528331635507647918535893226185489632132933089857064" + + "20467525907091548141654985946163718027098199430992448895757128289059232332609729971208443357326548938239119325" + + "97463667305836041428138830320382490375898524374417029132765618093773444030707469211201913020330380197621101100" + + "44929321516084244485963766983895228684783123552658213144957685726243344189303968642624341077322697802807318915" + + "44110104468232527162010526522721116603966655730925471105578537634668206531098965269186205647693125705863566201" + + "85581007293606598764861179104533488503461136576867532494416680396265797877185560845529654126654085306143444318" + + "58676975145661406800700237877659134401712749470420562230538994561314071127000407854733269939081454664645880797" + + "27082668306343285878569830523580893306575740679545716377525420211495576158140025012622859413021647155097925923" + + "09907965473761255176567513575178296664547791745011299614890304639947132962107340437518957359614589019389713111" + + "79042978285647503203198691514028708085990480109412147221317947647772622414254854540332157185306142288137585043" + + "06332175182979866223717215916077166925474873898665494945011465406284336639379003976926567214638530673609657120" + + "91807638327166416274888800786925602902284721040317211860820419000422966171196377921337575114959501566049631862" + + "94726547364252308177036751590673502350728354056704038674351362222477158915049530984448933309634087807693259939" + + "78054193414473774418426312986080998886874132604721569516239658645730216315981931951673538129741677294786724229" + + "24654366800980676928238280689964004824354037014163149658979409243237896907069779422362508221688957383798623001" + + "59377647165122893578601588161755782973523344604281512627203734314653197777416031990665541876397929334419521541" + + "34189948544473456738316249934191318148092777710386387734317720754565453220777092120190516609628049092636019759" + + "88281613323166636528619326686336062735676303544776280350450777235547105859548702790814356240145171806246436267" + + "94561275318134078330336254232783944975382437205835311477119926063813346776879695970309833913077109870408591337" + +// Test case for BenchmarkScanPi. +func TestScanPi(t *testing.T) { + var x nat + z, _, _, err := x.scan(strings.NewReader(pi), 10, false) + if err != nil { + t.Errorf("scanning pi: %s", err) + } + if s := z.decimalString(); s != pi { + t.Errorf("scanning pi: got %s", s) + } +} + +func TestScanPiParallel(t *testing.T) { + const n = 2 + c := make(chan int) + for i := 0; i < n; i++ { + go func() { + TestScanPi(t) + c <- 0 + }() + } + for i := 0; i < n; i++ { + <-c + } +} + +func BenchmarkScanPi(b *testing.B) { + for i := 0; i < b.N; i++ { + var x nat + x.scan(strings.NewReader(pi), 10, false) + } +} + +func BenchmarkStringPiParallel(b *testing.B) { + var x nat + x, _, _, _ = x.scan(strings.NewReader(pi), 0, false) + if x.decimalString() != pi { + panic("benchmark incorrect: conversion failed") + } + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + x.decimalString() + } + }) +} + +func BenchmarkScan10Base2(b *testing.B) { ScanHelper(b, 2, 10, 10) } +func BenchmarkScan100Base2(b *testing.B) { ScanHelper(b, 2, 10, 100) } +func BenchmarkScan1000Base2(b *testing.B) { ScanHelper(b, 2, 10, 1000) } +func BenchmarkScan10000Base2(b *testing.B) { ScanHelper(b, 2, 10, 10000) } +func BenchmarkScan100000Base2(b *testing.B) { ScanHelper(b, 2, 10, 100000) } + +func BenchmarkScan10Base8(b *testing.B) { ScanHelper(b, 8, 10, 10) } +func BenchmarkScan100Base8(b *testing.B) { ScanHelper(b, 8, 10, 100) } +func BenchmarkScan1000Base8(b *testing.B) { ScanHelper(b, 8, 10, 1000) } +func BenchmarkScan10000Base8(b *testing.B) { ScanHelper(b, 8, 10, 10000) } +func BenchmarkScan100000Base8(b *testing.B) { ScanHelper(b, 8, 10, 100000) } + +func BenchmarkScan10Base10(b *testing.B) { ScanHelper(b, 10, 10, 10) } +func BenchmarkScan100Base10(b *testing.B) { ScanHelper(b, 10, 10, 100) } +func BenchmarkScan1000Base10(b *testing.B) { ScanHelper(b, 10, 10, 1000) } +func BenchmarkScan10000Base10(b *testing.B) { ScanHelper(b, 10, 10, 10000) } +func BenchmarkScan100000Base10(b *testing.B) { ScanHelper(b, 10, 10, 100000) } + +func BenchmarkScan10Base16(b *testing.B) { ScanHelper(b, 16, 10, 10) } +func BenchmarkScan100Base16(b *testing.B) { ScanHelper(b, 16, 10, 100) } +func BenchmarkScan1000Base16(b *testing.B) { ScanHelper(b, 16, 10, 1000) } +func BenchmarkScan10000Base16(b *testing.B) { ScanHelper(b, 16, 10, 10000) } +func BenchmarkScan100000Base16(b *testing.B) { ScanHelper(b, 16, 10, 100000) } + +func ScanHelper(b *testing.B, base int, x, y Word) { + b.StopTimer() + var z nat + z = z.expWW(x, y) + + var s string + s = z.string(lowercaseDigits[:base]) + if t := toString(z, lowercaseDigits[:base]); t != s { + b.Fatalf("scanning: got %s; want %s", s, t) + } + b.StartTimer() + + for i := 0; i < b.N; i++ { + z.scan(strings.NewReader(s), base, false) + } +} + +func BenchmarkString10Base2(b *testing.B) { StringHelper(b, 2, 10, 10) } +func BenchmarkString100Base2(b *testing.B) { StringHelper(b, 2, 10, 100) } +func BenchmarkString1000Base2(b *testing.B) { StringHelper(b, 2, 10, 1000) } +func BenchmarkString10000Base2(b *testing.B) { StringHelper(b, 2, 10, 10000) } +func BenchmarkString100000Base2(b *testing.B) { StringHelper(b, 2, 10, 100000) } + +func BenchmarkString10Base8(b *testing.B) { StringHelper(b, 8, 10, 10) } +func BenchmarkString100Base8(b *testing.B) { StringHelper(b, 8, 10, 100) } +func BenchmarkString1000Base8(b *testing.B) { StringHelper(b, 8, 10, 1000) } +func BenchmarkString10000Base8(b *testing.B) { StringHelper(b, 8, 10, 10000) } +func BenchmarkString100000Base8(b *testing.B) { StringHelper(b, 8, 10, 100000) } + +func BenchmarkString10Base10(b *testing.B) { StringHelper(b, 10, 10, 10) } +func BenchmarkString100Base10(b *testing.B) { StringHelper(b, 10, 10, 100) } +func BenchmarkString1000Base10(b *testing.B) { StringHelper(b, 10, 10, 1000) } +func BenchmarkString10000Base10(b *testing.B) { StringHelper(b, 10, 10, 10000) } +func BenchmarkString100000Base10(b *testing.B) { StringHelper(b, 10, 10, 100000) } + +func BenchmarkString10Base16(b *testing.B) { StringHelper(b, 16, 10, 10) } +func BenchmarkString100Base16(b *testing.B) { StringHelper(b, 16, 10, 100) } +func BenchmarkString1000Base16(b *testing.B) { StringHelper(b, 16, 10, 1000) } +func BenchmarkString10000Base16(b *testing.B) { StringHelper(b, 16, 10, 10000) } +func BenchmarkString100000Base16(b *testing.B) { StringHelper(b, 16, 10, 100000) } + +func StringHelper(b *testing.B, base int, x, y Word) { + b.StopTimer() + var z nat + z = z.expWW(x, y) + z.string(lowercaseDigits[:base]) // warm divisor cache + b.StartTimer() + + for i := 0; i < b.N; i++ { + _ = z.string(lowercaseDigits[:base]) + } +} + +func BenchmarkLeafSize0(b *testing.B) { LeafSizeHelper(b, 10, 0) } // test without splitting +func BenchmarkLeafSize1(b *testing.B) { LeafSizeHelper(b, 10, 1) } +func BenchmarkLeafSize2(b *testing.B) { LeafSizeHelper(b, 10, 2) } +func BenchmarkLeafSize3(b *testing.B) { LeafSizeHelper(b, 10, 3) } +func BenchmarkLeafSize4(b *testing.B) { LeafSizeHelper(b, 10, 4) } +func BenchmarkLeafSize5(b *testing.B) { LeafSizeHelper(b, 10, 5) } +func BenchmarkLeafSize6(b *testing.B) { LeafSizeHelper(b, 10, 6) } +func BenchmarkLeafSize7(b *testing.B) { LeafSizeHelper(b, 10, 7) } +func BenchmarkLeafSize8(b *testing.B) { LeafSizeHelper(b, 10, 8) } +func BenchmarkLeafSize9(b *testing.B) { LeafSizeHelper(b, 10, 9) } +func BenchmarkLeafSize10(b *testing.B) { LeafSizeHelper(b, 10, 10) } +func BenchmarkLeafSize11(b *testing.B) { LeafSizeHelper(b, 10, 11) } +func BenchmarkLeafSize12(b *testing.B) { LeafSizeHelper(b, 10, 12) } +func BenchmarkLeafSize13(b *testing.B) { LeafSizeHelper(b, 10, 13) } +func BenchmarkLeafSize14(b *testing.B) { LeafSizeHelper(b, 10, 14) } +func BenchmarkLeafSize15(b *testing.B) { LeafSizeHelper(b, 10, 15) } +func BenchmarkLeafSize16(b *testing.B) { LeafSizeHelper(b, 10, 16) } +func BenchmarkLeafSize32(b *testing.B) { LeafSizeHelper(b, 10, 32) } // try some large lengths +func BenchmarkLeafSize64(b *testing.B) { LeafSizeHelper(b, 10, 64) } + +func LeafSizeHelper(b *testing.B, base Word, size int) { + b.StopTimer() + originalLeafSize := leafSize + resetTable(cacheBase10.table[:]) + leafSize = size + b.StartTimer() + + for d := 1; d <= 10000; d *= 10 { + b.StopTimer() + var z nat + z = z.expWW(base, Word(d)) // build target number + _ = z.string(lowercaseDigits[:base]) // warm divisor cache + b.StartTimer() + + for i := 0; i < b.N; i++ { + _ = z.string(lowercaseDigits[:base]) + } + } + + b.StopTimer() + resetTable(cacheBase10.table[:]) + leafSize = originalLeafSize + b.StartTimer() +} + +func resetTable(table []divisor) { + if table != nil && table[0].bbb != nil { + for i := 0; i < len(table); i++ { + table[i].bbb = nil + table[i].nbits = 0 + table[i].ndigits = 0 + } + } +} + +func TestStringPowers(t *testing.T) { + var b, p Word + for b = 2; b <= 16; b++ { + for p = 0; p <= 512; p++ { + x := nat(nil).expWW(b, p) + xs := x.string(lowercaseDigits[:b]) + xs2 := toString(x, lowercaseDigits[:b]) + if xs != xs2 { + t.Errorf("failed at %d ** %d in base %d: %s != %s", b, p, b, xs, xs2) + } + } + if b >= 3 && testing.Short() { + break + } + } +} diff --git a/libgo/go/math/big/rat.go b/libgo/go/math/big/rat.go index c5339fe4431..fb16f18a964 100644 --- a/libgo/go/math/big/rat.go +++ b/libgo/go/math/big/rat.go @@ -11,7 +11,6 @@ import ( "errors" "fmt" "math" - "strings" ) // A Rat represents a quotient a/b of arbitrary precision. @@ -324,14 +323,14 @@ func (z *Rat) SetFrac64(a, b int64) *Rat { // SetInt sets z to x (by making a copy of x) and returns z. func (z *Rat) SetInt(x *Int) *Rat { z.a.Set(x) - z.b.abs = z.b.abs.make(0) + z.b.abs = z.b.abs[:0] return z } // SetInt64 sets z to x and returns z. func (z *Rat) SetInt64(x int64) *Rat { z.a.SetInt64(x) - z.b.abs = z.b.abs.make(0) + z.b.abs = z.b.abs[:0] return z } @@ -370,7 +369,7 @@ func (z *Rat) Inv(x *Rat) *Rat { } b := z.a.abs if b.cmp(natOne) == 0 { - b = b.make(0) // normalize denominator + b = b[:0] // normalize denominator } z.a.abs, z.b.abs = a, b // sign doesn't change return z @@ -386,7 +385,7 @@ func (x *Rat) Sign() int { return x.a.Sign() } -// IsInt returns true if the denominator of x is 1. +// IsInt reports whether the denominator of x is 1. func (x *Rat) IsInt() bool { return len(x.b.abs) == 0 || x.b.abs.cmp(natOne) == 0 } @@ -415,12 +414,12 @@ func (z *Rat) norm() *Rat { case len(z.a.abs) == 0: // z == 0 - normalize sign and denominator z.a.neg = false - z.b.abs = z.b.abs.make(0) + z.b.abs = z.b.abs[:0] case len(z.b.abs) == 0: // z is normalized int - nothing to do case z.b.abs.cmp(natOne) == 0: // z is int - normalize denominator - z.b.abs = z.b.abs.make(0) + z.b.abs = z.b.abs[:0] default: neg := z.a.neg z.a.neg = false @@ -430,7 +429,7 @@ func (z *Rat) norm() *Rat { z.b.abs, _ = z.b.abs.div(nil, z.b.abs, f.abs) if z.b.abs.cmp(natOne) == 0 { // z is int - normalize denominator - z.b.abs = z.b.abs.make(0) + z.b.abs = z.b.abs[:0] } } z.a.neg = neg @@ -512,151 +511,6 @@ func (z *Rat) Quo(x, y *Rat) *Rat { return z.norm() } -func ratTok(ch rune) bool { - return strings.IndexRune("+-/0123456789.eE", ch) >= 0 -} - -// Scan is a support routine for fmt.Scanner. It accepts the formats -// 'e', 'E', 'f', 'F', 'g', 'G', and 'v'. All formats are equivalent. -func (z *Rat) Scan(s fmt.ScanState, ch rune) error { - tok, err := s.Token(true, ratTok) - if err != nil { - return err - } - if strings.IndexRune("efgEFGv", ch) < 0 { - return errors.New("Rat.Scan: invalid verb") - } - if _, ok := z.SetString(string(tok)); !ok { - return errors.New("Rat.Scan: invalid syntax") - } - return nil -} - -// SetString sets z to the value of s and returns z and a boolean indicating -// success. s can be given as a fraction "a/b" or as a floating-point number -// optionally followed by an exponent. If the operation failed, the value of -// z is undefined but the returned value is nil. -func (z *Rat) SetString(s string) (*Rat, bool) { - if len(s) == 0 { - return nil, false - } - - // check for a quotient - sep := strings.Index(s, "/") - if sep >= 0 { - if _, ok := z.a.SetString(s[0:sep], 10); !ok { - return nil, false - } - s = s[sep+1:] - var err error - if z.b.abs, _, err = z.b.abs.scan(strings.NewReader(s), 10); err != nil { - return nil, false - } - if len(z.b.abs) == 0 { - return nil, false - } - return z.norm(), true - } - - // check for a decimal point - sep = strings.Index(s, ".") - // check for an exponent - e := strings.IndexAny(s, "eE") - var exp Int - if e >= 0 { - if e < sep { - // The E must come after the decimal point. - return nil, false - } - if _, ok := exp.SetString(s[e+1:], 10); !ok { - return nil, false - } - s = s[0:e] - } - if sep >= 0 { - s = s[0:sep] + s[sep+1:] - exp.Sub(&exp, NewInt(int64(len(s)-sep))) - } - - if _, ok := z.a.SetString(s, 10); !ok { - return nil, false - } - powTen := nat(nil).expNN(natTen, exp.abs, nil) - if exp.neg { - z.b.abs = powTen - z.norm() - } else { - z.a.abs = z.a.abs.mul(z.a.abs, powTen) - z.b.abs = z.b.abs.make(0) - } - - return z, true -} - -// String returns a string representation of x in the form "a/b" (even if b == 1). -func (x *Rat) String() string { - s := "/1" - if len(x.b.abs) != 0 { - s = "/" + x.b.abs.decimalString() - } - return x.a.String() + s -} - -// RatString returns a string representation of x in the form "a/b" if b != 1, -// and in the form "a" if b == 1. -func (x *Rat) RatString() string { - if x.IsInt() { - return x.a.String() - } - return x.String() -} - -// FloatString returns a string representation of x in decimal form with prec -// digits of precision after the decimal point and the last digit rounded. -func (x *Rat) FloatString(prec int) string { - if x.IsInt() { - s := x.a.String() - if prec > 0 { - s += "." + strings.Repeat("0", prec) - } - return s - } - // x.b.abs != 0 - - q, r := nat(nil).div(nat(nil), x.a.abs, x.b.abs) - - p := natOne - if prec > 0 { - p = nat(nil).expNN(natTen, nat(nil).setUint64(uint64(prec)), nil) - } - - r = r.mul(r, p) - r, r2 := r.div(nat(nil), r, x.b.abs) - - // see if we need to round up - r2 = r2.add(r2, r2) - if x.b.abs.cmp(r2) <= 0 { - r = r.add(r, natOne) - if r.cmp(p) >= 0 { - q = nat(nil).add(q, natOne) - r = nat(nil).sub(r, p) - } - } - - s := q.decimalString() - if x.a.neg { - s = "-" + s - } - - if prec > 0 { - rs := r.decimalString() - leadingZeros := prec - len(rs) - s += "." + strings.Repeat("0", leadingZeros) + rs - } - - return s -} - // Gob codec version. Permits backward-compatible changes to the encoding. const ratGobVersion byte = 1 @@ -667,7 +521,7 @@ func (x *Rat) GobEncode() ([]byte, error) { } buf := make([]byte, 1+4+(len(x.a.abs)+len(x.b.abs))*_S) // extra bytes for version and sign bit (1), and numerator length (4) i := x.b.abs.bytes(buf) - j := x.a.abs.bytes(buf[0:i]) + j := x.a.abs.bytes(buf[:i]) n := i - j if int(uint32(n)) != n { // this should never happen @@ -692,7 +546,7 @@ func (z *Rat) GobDecode(buf []byte) error { } b := buf[0] if b>>1 != ratGobVersion { - return errors.New(fmt.Sprintf("Rat.GobDecode: encoding version %d not supported", b>>1)) + return fmt.Errorf("Rat.GobDecode: encoding version %d not supported", b>>1) } const j = 1 + 4 i := j + binary.BigEndian.Uint32(buf[j-4:j]) diff --git a/libgo/go/math/big/rat_test.go b/libgo/go/math/big/rat_test.go index 5dbbb3510f0..012d0c47ec4 100644 --- a/libgo/go/math/big/rat_test.go +++ b/libgo/go/math/big/rat_test.go @@ -9,10 +9,7 @@ import ( "encoding/gob" "encoding/json" "encoding/xml" - "fmt" "math" - "strconv" - "strings" "testing" ) @@ -56,112 +53,6 @@ func TestZeroRat(t *testing.T) { z.Quo(&x, &y) } -var setStringTests = []struct { - in, out string - ok bool -}{ - {"0", "0", true}, - {"-0", "0", true}, - {"1", "1", true}, - {"-1", "-1", true}, - {"1.", "1", true}, - {"1e0", "1", true}, - {"1.e1", "10", true}, - {in: "1e", ok: false}, - {in: "1.e", ok: false}, - {in: "1e+14e-5", ok: false}, - {in: "1e4.5", ok: false}, - {in: "r", ok: false}, - {in: "a/b", ok: false}, - {in: "a.b", ok: false}, - {"-0.1", "-1/10", true}, - {"-.1", "-1/10", true}, - {"2/4", "1/2", true}, - {".25", "1/4", true}, - {"-1/5", "-1/5", true}, - {"8129567.7690E14", "812956776900000000000", true}, - {"78189e+4", "781890000", true}, - {"553019.8935e+8", "55301989350000", true}, - {"98765432109876543210987654321e-10", "98765432109876543210987654321/10000000000", true}, - {"9877861857500000E-7", "3951144743/4", true}, - {"2169378.417e-3", "2169378417/1000000", true}, - {"884243222337379604041632732738665534", "884243222337379604041632732738665534", true}, - {"53/70893980658822810696", "53/70893980658822810696", true}, - {"106/141787961317645621392", "53/70893980658822810696", true}, - {"204211327800791583.81095", "4084226556015831676219/20000", true}, - {in: "1/0", ok: false}, -} - -func TestRatSetString(t *testing.T) { - for i, test := range setStringTests { - x, ok := new(Rat).SetString(test.in) - - if ok { - if !test.ok { - t.Errorf("#%d SetString(%q) expected failure", i, test.in) - } else if x.RatString() != test.out { - t.Errorf("#%d SetString(%q) got %s want %s", i, test.in, x.RatString(), test.out) - } - } else if x != nil { - t.Errorf("#%d SetString(%q) got %p want nil", i, test.in, x) - } - } -} - -func TestRatScan(t *testing.T) { - var buf bytes.Buffer - for i, test := range setStringTests { - x := new(Rat) - buf.Reset() - buf.WriteString(test.in) - - _, err := fmt.Fscanf(&buf, "%v", x) - if err == nil != test.ok { - if test.ok { - t.Errorf("#%d error: %s", i, err) - } else { - t.Errorf("#%d expected error", i) - } - continue - } - if err == nil && x.RatString() != test.out { - t.Errorf("#%d got %s want %s", i, x.RatString(), test.out) - } - } -} - -var floatStringTests = []struct { - in string - prec int - out string -}{ - {"0", 0, "0"}, - {"0", 4, "0.0000"}, - {"1", 0, "1"}, - {"1", 2, "1.00"}, - {"-1", 0, "-1"}, - {".25", 2, "0.25"}, - {".25", 1, "0.3"}, - {".25", 3, "0.250"}, - {"-1/3", 3, "-0.333"}, - {"-2/3", 4, "-0.6667"}, - {"0.96", 1, "1.0"}, - {"0.999", 2, "1.00"}, - {"0.9", 0, "1"}, - {".25", -1, "0"}, - {".55", -1, "1"}, -} - -func TestFloatString(t *testing.T) { - for i, test := range floatStringTests { - x, _ := new(Rat).SetString(test.in) - - if x.FloatString(test.prec) != test.out { - t.Errorf("#%d got %s want %s", i, x.FloatString(test.prec), test.out) - } - } -} - func TestRatSign(t *testing.T) { zero := NewRat(0, 1) for _, a := range setStringTests { @@ -592,321 +483,6 @@ func TestIssue3521(t *testing.T) { } } -// Test inputs to Rat.SetString. The prefix "long:" causes the test -// to be skipped in --test.short mode. (The threshold is about 500us.) -var float64inputs = []string{ - // Constants plundered from strconv/testfp.txt. - - // Table 1: Stress Inputs for Conversion to 53-bit Binary, < 1/2 ULP - "5e+125", - "69e+267", - "999e-026", - "7861e-034", - "75569e-254", - "928609e-261", - "9210917e+080", - "84863171e+114", - "653777767e+273", - "5232604057e-298", - "27235667517e-109", - "653532977297e-123", - "3142213164987e-294", - "46202199371337e-072", - "231010996856685e-073", - "9324754620109615e+212", - "78459735791271921e+049", - "272104041512242479e+200", - "6802601037806061975e+198", - "20505426358836677347e-221", - "836168422905420598437e-234", - "4891559871276714924261e+222", - - // Table 2: Stress Inputs for Conversion to 53-bit Binary, > 1/2 ULP - "9e-265", - "85e-037", - "623e+100", - "3571e+263", - "81661e+153", - "920657e-023", - "4603285e-024", - "87575437e-309", - "245540327e+122", - "6138508175e+120", - "83356057653e+193", - "619534293513e+124", - "2335141086879e+218", - "36167929443327e-159", - "609610927149051e-255", - "3743626360493413e-165", - "94080055902682397e-242", - "899810892172646163e+283", - "7120190517612959703e+120", - "25188282901709339043e-252", - "308984926168550152811e-052", - "6372891218502368041059e+064", - - // Table 14: Stress Inputs for Conversion to 24-bit Binary, <1/2 ULP - "5e-20", - "67e+14", - "985e+15", - "7693e-42", - "55895e-16", - "996622e-44", - "7038531e-32", - "60419369e-46", - "702990899e-20", - "6930161142e-48", - "25933168707e+13", - "596428896559e+20", - - // Table 15: Stress Inputs for Conversion to 24-bit Binary, >1/2 ULP - "3e-23", - "57e+18", - "789e-35", - "2539e-18", - "76173e+28", - "887745e-11", - "5382571e-37", - "82381273e-35", - "750486563e-38", - "3752432815e-39", - "75224575729e-45", - "459926601011e+15", - - // Constants plundered from strconv/atof_test.go. - - "0", - "1", - "+1", - "1e23", - "1E23", - "100000000000000000000000", - "1e-100", - "123456700", - "99999999999999974834176", - "100000000000000000000001", - "100000000000000008388608", - "100000000000000016777215", - "100000000000000016777216", - "-1", - "-0.1", - "-0", // NB: exception made for this input - "1e-20", - "625e-3", - - // largest float64 - "1.7976931348623157e308", - "-1.7976931348623157e308", - // next float64 - too large - "1.7976931348623159e308", - "-1.7976931348623159e308", - // the border is ...158079 - // borderline - okay - "1.7976931348623158e308", - "-1.7976931348623158e308", - // borderline - too large - "1.797693134862315808e308", - "-1.797693134862315808e308", - - // a little too large - "1e308", - "2e308", - "1e309", - - // way too large - "1e310", - "-1e310", - "1e400", - "-1e400", - "long:1e400000", - "long:-1e400000", - - // denormalized - "1e-305", - "1e-306", - "1e-307", - "1e-308", - "1e-309", - "1e-310", - "1e-322", - // smallest denormal - "5e-324", - "4e-324", - "3e-324", - // too small - "2e-324", - // way too small - "1e-350", - "long:1e-400000", - // way too small, negative - "-1e-350", - "long:-1e-400000", - - // try to overflow exponent - // [Disabled: too slow and memory-hungry with rationals.] - // "1e-4294967296", - // "1e+4294967296", - // "1e-18446744073709551616", - // "1e+18446744073709551616", - - // http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/ - "2.2250738585072012e-308", - // http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/ - "2.2250738585072011e-308", - - // A very large number (initially wrongly parsed by the fast algorithm). - "4.630813248087435e+307", - - // A different kind of very large number. - "22.222222222222222", - "long:2." + strings.Repeat("2", 4000) + "e+1", - - // Exactly halfway between 1 and math.Nextafter(1, 2). - // Round to even (down). - "1.00000000000000011102230246251565404236316680908203125", - // Slightly lower; still round down. - "1.00000000000000011102230246251565404236316680908203124", - // Slightly higher; round up. - "1.00000000000000011102230246251565404236316680908203126", - // Slightly higher, but you have to read all the way to the end. - "long:1.00000000000000011102230246251565404236316680908203125" + strings.Repeat("0", 10000) + "1", - - // Smallest denormal, 2^(-1022-52) - "4.940656458412465441765687928682213723651e-324", - // Half of smallest denormal, 2^(-1022-53) - "2.470328229206232720882843964341106861825e-324", - // A little more than the exact half of smallest denormal - // 2^-1075 + 2^-1100. (Rounds to 1p-1074.) - "2.470328302827751011111470718709768633275e-324", - // The exact halfway between smallest normal and largest denormal: - // 2^-1022 - 2^-1075. (Rounds to 2^-1022.) - "2.225073858507201136057409796709131975935e-308", - - "1152921504606846975", // 1<<60 - 1 - "-1152921504606846975", // -(1<<60 - 1) - "1152921504606846977", // 1<<60 + 1 - "-1152921504606846977", // -(1<<60 + 1) - - "1/3", -} - -// isFinite reports whether f represents a finite rational value. -// It is equivalent to !math.IsNan(f) && !math.IsInf(f, 0). -func isFinite(f float64) bool { - return math.Abs(f) <= math.MaxFloat64 -} - -func TestFloat32SpecialCases(t *testing.T) { - for _, input := range float64inputs { - if strings.HasPrefix(input, "long:") { - if testing.Short() { - continue - } - input = input[len("long:"):] - } - - r, ok := new(Rat).SetString(input) - if !ok { - t.Errorf("Rat.SetString(%q) failed", input) - continue - } - f, exact := r.Float32() - - // 1. Check string -> Rat -> float32 conversions are - // consistent with strconv.ParseFloat. - // Skip this check if the input uses "a/b" rational syntax. - if !strings.Contains(input, "/") { - e64, _ := strconv.ParseFloat(input, 32) - e := float32(e64) - - // Careful: negative Rats too small for - // float64 become -0, but Rat obviously cannot - // preserve the sign from SetString("-0"). - switch { - case math.Float32bits(e) == math.Float32bits(f): - // Ok: bitwise equal. - case f == 0 && r.Num().BitLen() == 0: - // Ok: Rat(0) is equivalent to both +/- float64(0). - default: - t.Errorf("strconv.ParseFloat(%q) = %g (%b), want %g (%b); delta = %g", input, e, e, f, f, f-e) - } - } - - if !isFinite(float64(f)) { - continue - } - - // 2. Check f is best approximation to r. - if !checkIsBestApprox32(t, f, r) { - // Append context information. - t.Errorf("(input was %q)", input) - } - - // 3. Check f->R->f roundtrip is non-lossy. - checkNonLossyRoundtrip32(t, f) - - // 4. Check exactness using slow algorithm. - if wasExact := new(Rat).SetFloat64(float64(f)).Cmp(r) == 0; wasExact != exact { - t.Errorf("Rat.SetString(%q).Float32().exact = %t, want %t", input, exact, wasExact) - } - } -} - -func TestFloat64SpecialCases(t *testing.T) { - for _, input := range float64inputs { - if strings.HasPrefix(input, "long:") { - if testing.Short() { - continue - } - input = input[len("long:"):] - } - - r, ok := new(Rat).SetString(input) - if !ok { - t.Errorf("Rat.SetString(%q) failed", input) - continue - } - f, exact := r.Float64() - - // 1. Check string -> Rat -> float64 conversions are - // consistent with strconv.ParseFloat. - // Skip this check if the input uses "a/b" rational syntax. - if !strings.Contains(input, "/") { - e, _ := strconv.ParseFloat(input, 64) - - // Careful: negative Rats too small for - // float64 become -0, but Rat obviously cannot - // preserve the sign from SetString("-0"). - switch { - case math.Float64bits(e) == math.Float64bits(f): - // Ok: bitwise equal. - case f == 0 && r.Num().BitLen() == 0: - // Ok: Rat(0) is equivalent to both +/- float64(0). - default: - t.Errorf("strconv.ParseFloat(%q) = %g (%b), want %g (%b); delta = %g", input, e, e, f, f, f-e) - } - } - - if !isFinite(f) { - continue - } - - // 2. Check f is best approximation to r. - if !checkIsBestApprox64(t, f, r) { - // Append context information. - t.Errorf("(input was %q)", input) - } - - // 3. Check f->R->f roundtrip is non-lossy. - checkNonLossyRoundtrip64(t, f) - - // 4. Check exactness using slow algorithm. - if wasExact := new(Rat).SetFloat64(f).Cmp(r) == 0; wasExact != exact { - t.Errorf("Rat.SetString(%q).Float64().exact = %t, want %t", input, exact, wasExact) - } - } -} - func TestFloat32Distribution(t *testing.T) { // Generate a distribution of (sign, mantissa, exp) values // broader than the float32 range, and check Rat.Float32() diff --git a/libgo/go/math/big/ratconv.go b/libgo/go/math/big/ratconv.go new file mode 100644 index 00000000000..961ff649a50 --- /dev/null +++ b/libgo/go/math/big/ratconv.go @@ -0,0 +1,252 @@ +// Copyright 2015 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 rat-to-string conversion functions. + +package big + +import ( + "errors" + "fmt" + "io" + "strconv" + "strings" +) + +func ratTok(ch rune) bool { + return strings.IndexRune("+-/0123456789.eE", ch) >= 0 +} + +// Scan is a support routine for fmt.Scanner. It accepts the formats +// 'e', 'E', 'f', 'F', 'g', 'G', and 'v'. All formats are equivalent. +func (z *Rat) Scan(s fmt.ScanState, ch rune) error { + tok, err := s.Token(true, ratTok) + if err != nil { + return err + } + if strings.IndexRune("efgEFGv", ch) < 0 { + return errors.New("Rat.Scan: invalid verb") + } + if _, ok := z.SetString(string(tok)); !ok { + return errors.New("Rat.Scan: invalid syntax") + } + return nil +} + +// SetString sets z to the value of s and returns z and a boolean indicating +// success. s can be given as a fraction "a/b" or as a floating-point number +// optionally followed by an exponent. If the operation failed, the value of +// z is undefined but the returned value is nil. +func (z *Rat) SetString(s string) (*Rat, bool) { + if len(s) == 0 { + return nil, false + } + // len(s) > 0 + + // parse fraction a/b, if any + if sep := strings.Index(s, "/"); sep >= 0 { + if _, ok := z.a.SetString(s[:sep], 0); !ok { + return nil, false + } + s = s[sep+1:] + var err error + if z.b.abs, _, _, err = z.b.abs.scan(strings.NewReader(s), 0, false); err != nil { + return nil, false + } + if len(z.b.abs) == 0 { + return nil, false + } + return z.norm(), true + } + + // parse floating-point number + r := strings.NewReader(s) + + // sign + neg, err := scanSign(r) + if err != nil { + return nil, false + } + + // mantissa + var ecorr int + z.a.abs, _, ecorr, err = z.a.abs.scan(r, 10, true) + if err != nil { + return nil, false + } + + // exponent + var exp int64 + exp, _, err = scanExponent(r, false) + if err != nil { + return nil, false + } + + // there should be no unread characters left + if _, err = r.ReadByte(); err != io.EOF { + return nil, false + } + + // correct exponent + if ecorr < 0 { + exp += int64(ecorr) + } + + // compute exponent power + expabs := exp + if expabs < 0 { + expabs = -expabs + } + powTen := nat(nil).expNN(natTen, nat(nil).setWord(Word(expabs)), nil) + + // complete fraction + if exp < 0 { + z.b.abs = powTen + z.norm() + } else { + z.a.abs = z.a.abs.mul(z.a.abs, powTen) + z.b.abs = z.b.abs[:0] + } + + z.a.neg = neg && len(z.a.abs) > 0 // 0 has no sign + + return z, true +} + +// scanExponent scans the longest possible prefix of r representing a decimal +// ('e', 'E') or binary ('p') exponent, if any. It returns the exponent, the +// exponent base (10 or 2), or a read or syntax error, if any. +// +// exponent = ( "E" | "e" | "p" ) [ sign ] digits . +// sign = "+" | "-" . +// digits = digit { digit } . +// digit = "0" ... "9" . +// +// A binary exponent is only permitted if binExpOk is set. +func scanExponent(r io.ByteScanner, binExpOk bool) (exp int64, base int, err error) { + base = 10 + + var ch byte + if ch, err = r.ReadByte(); err != nil { + if err == io.EOF { + err = nil // no exponent; same as e0 + } + return + } + + switch ch { + case 'e', 'E': + // ok + case 'p': + if binExpOk { + base = 2 + break // ok + } + fallthrough // binary exponent not permitted + default: + r.UnreadByte() + return // no exponent; same as e0 + } + + var neg bool + if neg, err = scanSign(r); err != nil { + return + } + + var digits []byte + if neg { + digits = append(digits, '-') + } + + // no need to use nat.scan for exponent digits + // since we only care about int64 values - the + // from-scratch scan is easy enough and faster + for i := 0; ; i++ { + if ch, err = r.ReadByte(); err != nil { + if err != io.EOF || i == 0 { + return + } + err = nil + break // i > 0 + } + if ch < '0' || '9' < ch { + if i == 0 { + r.UnreadByte() + err = fmt.Errorf("invalid exponent (missing digits)") + return + } + break // i > 0 + } + digits = append(digits, byte(ch)) + } + // i > 0 => we have at least one digit + + exp, err = strconv.ParseInt(string(digits), 10, 64) + return +} + +// String returns a string representation of x in the form "a/b" (even if b == 1). +func (x *Rat) String() string { + s := "/1" + if len(x.b.abs) != 0 { + s = "/" + x.b.abs.decimalString() + } + return x.a.String() + s +} + +// RatString returns a string representation of x in the form "a/b" if b != 1, +// and in the form "a" if b == 1. +func (x *Rat) RatString() string { + if x.IsInt() { + return x.a.String() + } + return x.String() +} + +// FloatString returns a string representation of x in decimal form with prec +// digits of precision after the decimal point. The last digit is rounded to +// nearest, with halves rounded away from zero. +func (x *Rat) FloatString(prec int) string { + if x.IsInt() { + s := x.a.String() + if prec > 0 { + s += "." + strings.Repeat("0", prec) + } + return s + } + // x.b.abs != 0 + + q, r := nat(nil).div(nat(nil), x.a.abs, x.b.abs) + + p := natOne + if prec > 0 { + p = nat(nil).expNN(natTen, nat(nil).setUint64(uint64(prec)), nil) + } + + r = r.mul(r, p) + r, r2 := r.div(nat(nil), r, x.b.abs) + + // see if we need to round up + r2 = r2.add(r2, r2) + if x.b.abs.cmp(r2) <= 0 { + r = r.add(r, natOne) + if r.cmp(p) >= 0 { + q = nat(nil).add(q, natOne) + r = nat(nil).sub(r, p) + } + } + + s := q.decimalString() + if x.a.neg { + s = "-" + s + } + + if prec > 0 { + rs := r.decimalString() + leadingZeros := prec - len(rs) + s += "." + strings.Repeat("0", leadingZeros) + rs + } + + return s +} diff --git a/libgo/go/math/big/ratconv_test.go b/libgo/go/math/big/ratconv_test.go new file mode 100644 index 00000000000..da2fdab4cab --- /dev/null +++ b/libgo/go/math/big/ratconv_test.go @@ -0,0 +1,453 @@ +// Copyright 2015 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 big + +import ( + "bytes" + "fmt" + "math" + "strconv" + "strings" + "testing" +) + +type StringTest struct { + in, out string + ok bool +} + +var setStringTests = []StringTest{ + {"0", "0", true}, + {"-0", "0", true}, + {"1", "1", true}, + {"-1", "-1", true}, + {"1.", "1", true}, + {"1e0", "1", true}, + {"1.e1", "10", true}, + {in: "1e"}, + {in: "1.e"}, + {in: "1e+14e-5"}, + {in: "1e4.5"}, + {in: "r"}, + {in: "a/b"}, + {in: "a.b"}, + {"-0.1", "-1/10", true}, + {"-.1", "-1/10", true}, + {"2/4", "1/2", true}, + {".25", "1/4", true}, + {"-1/5", "-1/5", true}, + {"8129567.7690E14", "812956776900000000000", true}, + {"78189e+4", "781890000", true}, + {"553019.8935e+8", "55301989350000", true}, + {"98765432109876543210987654321e-10", "98765432109876543210987654321/10000000000", true}, + {"9877861857500000E-7", "3951144743/4", true}, + {"2169378.417e-3", "2169378417/1000000", true}, + {"884243222337379604041632732738665534", "884243222337379604041632732738665534", true}, + {"53/70893980658822810696", "53/70893980658822810696", true}, + {"106/141787961317645621392", "53/70893980658822810696", true}, + {"204211327800791583.81095", "4084226556015831676219/20000", true}, + {in: "1/0"}, +} + +// These are not supported by fmt.Fscanf. +var setStringTests2 = []StringTest{ + {"0x10", "16", true}, + {"-010/1", "-8", true}, // TODO(gri) should we even permit octal here? + {"-010.", "-10", true}, + {"0x10/0x20", "1/2", true}, + {"0b1000/3", "8/3", true}, + // TODO(gri) add more tests +} + +func TestRatSetString(t *testing.T) { + var tests []StringTest + tests = append(tests, setStringTests...) + tests = append(tests, setStringTests2...) + + for i, test := range tests { + x, ok := new(Rat).SetString(test.in) + + if ok { + if !test.ok { + t.Errorf("#%d SetString(%q) expected failure", i, test.in) + } else if x.RatString() != test.out { + t.Errorf("#%d SetString(%q) got %s want %s", i, test.in, x.RatString(), test.out) + } + } else if x != nil { + t.Errorf("#%d SetString(%q) got %p want nil", i, test.in, x) + } + } +} + +func TestRatScan(t *testing.T) { + var buf bytes.Buffer + for i, test := range setStringTests { + x := new(Rat) + buf.Reset() + buf.WriteString(test.in) + + _, err := fmt.Fscanf(&buf, "%v", x) + if err == nil != test.ok { + if test.ok { + t.Errorf("#%d (%s) error: %s", i, test.in, err) + } else { + t.Errorf("#%d (%s) expected error", i, test.in) + } + continue + } + if err == nil && x.RatString() != test.out { + t.Errorf("#%d got %s want %s", i, x.RatString(), test.out) + } + } +} + +var floatStringTests = []struct { + in string + prec int + out string +}{ + {"0", 0, "0"}, + {"0", 4, "0.0000"}, + {"1", 0, "1"}, + {"1", 2, "1.00"}, + {"-1", 0, "-1"}, + {"0.05", 1, "0.1"}, + {"-0.05", 1, "-0.1"}, + {".25", 2, "0.25"}, + {".25", 1, "0.3"}, + {".25", 3, "0.250"}, + {"-1/3", 3, "-0.333"}, + {"-2/3", 4, "-0.6667"}, + {"0.96", 1, "1.0"}, + {"0.999", 2, "1.00"}, + {"0.9", 0, "1"}, + {".25", -1, "0"}, + {".55", -1, "1"}, +} + +func TestFloatString(t *testing.T) { + for i, test := range floatStringTests { + x, _ := new(Rat).SetString(test.in) + + if x.FloatString(test.prec) != test.out { + t.Errorf("#%d got %s want %s", i, x.FloatString(test.prec), test.out) + } + } +} + +// Test inputs to Rat.SetString. The prefix "long:" causes the test +// to be skipped in --test.short mode. (The threshold is about 500us.) +var float64inputs = []string{ + // Constants plundered from strconv/testfp.txt. + + // Table 1: Stress Inputs for Conversion to 53-bit Binary, < 1/2 ULP + "5e+125", + "69e+267", + "999e-026", + "7861e-034", + "75569e-254", + "928609e-261", + "9210917e+080", + "84863171e+114", + "653777767e+273", + "5232604057e-298", + "27235667517e-109", + "653532977297e-123", + "3142213164987e-294", + "46202199371337e-072", + "231010996856685e-073", + "9324754620109615e+212", + "78459735791271921e+049", + "272104041512242479e+200", + "6802601037806061975e+198", + "20505426358836677347e-221", + "836168422905420598437e-234", + "4891559871276714924261e+222", + + // Table 2: Stress Inputs for Conversion to 53-bit Binary, > 1/2 ULP + "9e-265", + "85e-037", + "623e+100", + "3571e+263", + "81661e+153", + "920657e-023", + "4603285e-024", + "87575437e-309", + "245540327e+122", + "6138508175e+120", + "83356057653e+193", + "619534293513e+124", + "2335141086879e+218", + "36167929443327e-159", + "609610927149051e-255", + "3743626360493413e-165", + "94080055902682397e-242", + "899810892172646163e+283", + "7120190517612959703e+120", + "25188282901709339043e-252", + "308984926168550152811e-052", + "6372891218502368041059e+064", + + // Table 14: Stress Inputs for Conversion to 24-bit Binary, <1/2 ULP + "5e-20", + "67e+14", + "985e+15", + "7693e-42", + "55895e-16", + "996622e-44", + "7038531e-32", + "60419369e-46", + "702990899e-20", + "6930161142e-48", + "25933168707e+13", + "596428896559e+20", + + // Table 15: Stress Inputs for Conversion to 24-bit Binary, >1/2 ULP + "3e-23", + "57e+18", + "789e-35", + "2539e-18", + "76173e+28", + "887745e-11", + "5382571e-37", + "82381273e-35", + "750486563e-38", + "3752432815e-39", + "75224575729e-45", + "459926601011e+15", + + // Constants plundered from strconv/atof_test.go. + + "0", + "1", + "+1", + "1e23", + "1E23", + "100000000000000000000000", + "1e-100", + "123456700", + "99999999999999974834176", + "100000000000000000000001", + "100000000000000008388608", + "100000000000000016777215", + "100000000000000016777216", + "-1", + "-0.1", + "-0", // NB: exception made for this input + "1e-20", + "625e-3", + + // largest float64 + "1.7976931348623157e308", + "-1.7976931348623157e308", + // next float64 - too large + "1.7976931348623159e308", + "-1.7976931348623159e308", + // the border is ...158079 + // borderline - okay + "1.7976931348623158e308", + "-1.7976931348623158e308", + // borderline - too large + "1.797693134862315808e308", + "-1.797693134862315808e308", + + // a little too large + "1e308", + "2e308", + "1e309", + + // way too large + "1e310", + "-1e310", + "1e400", + "-1e400", + "long:1e400000", + "long:-1e400000", + + // denormalized + "1e-305", + "1e-306", + "1e-307", + "1e-308", + "1e-309", + "1e-310", + "1e-322", + // smallest denormal + "5e-324", + "4e-324", + "3e-324", + // too small + "2e-324", + // way too small + "1e-350", + "long:1e-400000", + // way too small, negative + "-1e-350", + "long:-1e-400000", + + // try to overflow exponent + // [Disabled: too slow and memory-hungry with rationals.] + // "1e-4294967296", + // "1e+4294967296", + // "1e-18446744073709551616", + // "1e+18446744073709551616", + + // http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/ + "2.2250738585072012e-308", + // http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/ + "2.2250738585072011e-308", + + // A very large number (initially wrongly parsed by the fast algorithm). + "4.630813248087435e+307", + + // A different kind of very large number. + "22.222222222222222", + "long:2." + strings.Repeat("2", 4000) + "e+1", + + // Exactly halfway between 1 and math.Nextafter(1, 2). + // Round to even (down). + "1.00000000000000011102230246251565404236316680908203125", + // Slightly lower; still round down. + "1.00000000000000011102230246251565404236316680908203124", + // Slightly higher; round up. + "1.00000000000000011102230246251565404236316680908203126", + // Slightly higher, but you have to read all the way to the end. + "long:1.00000000000000011102230246251565404236316680908203125" + strings.Repeat("0", 10000) + "1", + + // Smallest denormal, 2^(-1022-52) + "4.940656458412465441765687928682213723651e-324", + // Half of smallest denormal, 2^(-1022-53) + "2.470328229206232720882843964341106861825e-324", + // A little more than the exact half of smallest denormal + // 2^-1075 + 2^-1100. (Rounds to 1p-1074.) + "2.470328302827751011111470718709768633275e-324", + // The exact halfway between smallest normal and largest denormal: + // 2^-1022 - 2^-1075. (Rounds to 2^-1022.) + "2.225073858507201136057409796709131975935e-308", + + "1152921504606846975", // 1<<60 - 1 + "-1152921504606846975", // -(1<<60 - 1) + "1152921504606846977", // 1<<60 + 1 + "-1152921504606846977", // -(1<<60 + 1) + + "1/3", +} + +// isFinite reports whether f represents a finite rational value. +// It is equivalent to !math.IsNan(f) && !math.IsInf(f, 0). +func isFinite(f float64) bool { + return math.Abs(f) <= math.MaxFloat64 +} + +func TestFloat32SpecialCases(t *testing.T) { + for _, input := range float64inputs { + if strings.HasPrefix(input, "long:") { + if testing.Short() { + continue + } + input = input[len("long:"):] + } + + r, ok := new(Rat).SetString(input) + if !ok { + t.Errorf("Rat.SetString(%q) failed", input) + continue + } + f, exact := r.Float32() + + // 1. Check string -> Rat -> float32 conversions are + // consistent with strconv.ParseFloat. + // Skip this check if the input uses "a/b" rational syntax. + if !strings.Contains(input, "/") { + e64, _ := strconv.ParseFloat(input, 32) + e := float32(e64) + + // Careful: negative Rats too small for + // float64 become -0, but Rat obviously cannot + // preserve the sign from SetString("-0"). + switch { + case math.Float32bits(e) == math.Float32bits(f): + // Ok: bitwise equal. + case f == 0 && r.Num().BitLen() == 0: + // Ok: Rat(0) is equivalent to both +/- float64(0). + default: + t.Errorf("strconv.ParseFloat(%q) = %g (%b), want %g (%b); delta = %g", input, e, e, f, f, f-e) + } + } + + if !isFinite(float64(f)) { + continue + } + + // 2. Check f is best approximation to r. + if !checkIsBestApprox32(t, f, r) { + // Append context information. + t.Errorf("(input was %q)", input) + } + + // 3. Check f->R->f roundtrip is non-lossy. + checkNonLossyRoundtrip32(t, f) + + // 4. Check exactness using slow algorithm. + if wasExact := new(Rat).SetFloat64(float64(f)).Cmp(r) == 0; wasExact != exact { + t.Errorf("Rat.SetString(%q).Float32().exact = %t, want %t", input, exact, wasExact) + } + } +} + +func TestFloat64SpecialCases(t *testing.T) { + for _, input := range float64inputs { + if strings.HasPrefix(input, "long:") { + if testing.Short() { + continue + } + input = input[len("long:"):] + } + + r, ok := new(Rat).SetString(input) + if !ok { + t.Errorf("Rat.SetString(%q) failed", input) + continue + } + f, exact := r.Float64() + + // 1. Check string -> Rat -> float64 conversions are + // consistent with strconv.ParseFloat. + // Skip this check if the input uses "a/b" rational syntax. + if !strings.Contains(input, "/") { + e, _ := strconv.ParseFloat(input, 64) + + // Careful: negative Rats too small for + // float64 become -0, but Rat obviously cannot + // preserve the sign from SetString("-0"). + switch { + case math.Float64bits(e) == math.Float64bits(f): + // Ok: bitwise equal. + case f == 0 && r.Num().BitLen() == 0: + // Ok: Rat(0) is equivalent to both +/- float64(0). + default: + t.Errorf("strconv.ParseFloat(%q) = %g (%b), want %g (%b); delta = %g", input, e, e, f, f, f-e) + } + } + + if !isFinite(f) { + continue + } + + // 2. Check f is best approximation to r. + if !checkIsBestApprox64(t, f, r) { + // Append context information. + t.Errorf("(input was %q)", input) + } + + // 3. Check f->R->f roundtrip is non-lossy. + checkNonLossyRoundtrip64(t, f) + + // 4. Check exactness using slow algorithm. + if wasExact := new(Rat).SetFloat64(f).Cmp(r) == 0; wasExact != exact { + t.Errorf("Rat.SetString(%q).Float64().exact = %t, want %t", input, exact, wasExact) + } + } +} diff --git a/libgo/go/math/big/roundingmode_string.go b/libgo/go/math/big/roundingmode_string.go new file mode 100644 index 00000000000..05024b80656 --- /dev/null +++ b/libgo/go/math/big/roundingmode_string.go @@ -0,0 +1,16 @@ +// generated by stringer -type=RoundingMode; DO NOT EDIT + +package big + +import "fmt" + +const _RoundingMode_name = "ToNearestEvenToNearestAwayToZeroAwayFromZeroToNegativeInfToPositiveInf" + +var _RoundingMode_index = [...]uint8{0, 13, 26, 32, 44, 57, 70} + +func (i RoundingMode) String() string { + if i+1 >= RoundingMode(len(_RoundingMode_index)) { + return fmt.Sprintf("RoundingMode(%d)", i) + } + return _RoundingMode_name[_RoundingMode_index[i]:_RoundingMode_index[i+1]] +} diff --git a/libgo/go/math/cbrt.go b/libgo/go/math/cbrt.go index 272e3092310..f009fafd7d8 100644 --- a/libgo/go/math/cbrt.go +++ b/libgo/go/math/cbrt.go @@ -4,13 +4,17 @@ package math -/* - The algorithm is based in part on "Optimal Partitioning of - Newton's Method for Calculating Roots", by Gunter Meinardus - and G. D. Taylor, Mathematics of Computation © 1980 American - Mathematical Society. - (http://www.jstor.org/stable/2006387?seq=9, accessed 11-Feb-2010) -*/ +// The go code is a modified version of the original C code from +// http://www.netlib.org/fdlibm/s_cbrt.c and came with this notice. +// +// ==================================================== +// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. +// +// Developed at SunSoft, a Sun Microsystems, Inc. business. +// Permission to use, copy, modify, and distribute this +// software is freely granted, provided that this notice +// is preserved. +// ==================================================== // Cbrt returns the cube root of x. // @@ -20,57 +24,54 @@ package math // Cbrt(NaN) = NaN func Cbrt(x float64) float64 { const ( - A1 = 1.662848358e-01 - A2 = 1.096040958e+00 - A3 = 4.105032829e-01 - A4 = 5.649335816e-01 - B1 = 2.639607233e-01 - B2 = 8.699282849e-01 - B3 = 1.629083358e-01 - B4 = 2.824667908e-01 - C1 = 4.190115298e-01 - C2 = 6.904625373e-01 - C3 = 6.46502159e-02 - C4 = 1.412333954e-01 + B1 = 715094163 // (682-0.03306235651)*2**20 + B2 = 696219795 // (664-0.03306235651)*2**20 + C = 5.42857142857142815906e-01 // 19/35 = 0x3FE15F15F15F15F1 + D = -7.05306122448979611050e-01 // -864/1225 = 0xBFE691DE2532C834 + E = 1.41428571428571436819e+00 // 99/70 = 0x3FF6A0EA0EA0EA0F + F = 1.60714285714285720630e+00 // 45/28 = 0x3FF9B6DB6DB6DB6E + G = 3.57142857142857150787e-01 // 5/14 = 0x3FD6DB6DB6DB6DB7 + SmallestNormal = 2.22507385850720138309e-308 // 2**-1022 = 0x0010000000000000 ) // special cases switch { case x == 0 || IsNaN(x) || IsInf(x, 0): return x } + sign := false if x < 0 { x = -x sign = true } - // Reduce argument and estimate cube root - f, e := Frexp(x) // 0.5 <= f < 1.0 - m := e % 3 - if m > 0 { - m -= 3 - e -= m // e is multiple of 3 - } - switch m { - case 0: // 0.5 <= f < 1.0 - f = A1*f + A2 - A3/(A4+f) - case -1: - f *= 0.5 // 0.25 <= f < 0.5 - f = B1*f + B2 - B3/(B4+f) - default: // m == -2 - f *= 0.25 // 0.125 <= f < 0.25 - f = C1*f + C2 - C3/(C4+f) + + // rough cbrt to 5 bits + t := Float64frombits(Float64bits(x)/3 + B1<<32) + if x < SmallestNormal { + // subnormal number + t = float64(1 << 54) // set t= 2**54 + t *= x + t = Float64frombits(Float64bits(t)/3 + B2<<32) } - y := Ldexp(f, e/3) // e/3 = exponent of cube root - // Iterate - s := y * y * y - t := s + x - y *= (t + x) / (s + t) - // Reiterate - s = (y*y*y - x) / x - y -= y * (((14.0/81.0)*s-(2.0/9.0))*s + (1.0 / 3.0)) * s + // new cbrt to 23 bits + r := t * t / x + s := C + r*t + t *= G + F/(s+E+D/s) + + // chop to 22 bits, make larger than cbrt(x) + t = Float64frombits(Float64bits(t)&(0xFFFFFFFFC<<28) + 1<<30) + + // one step newton iteration to 53 bits with error less than 0.667ulps + s = t * t // t*t is exact + r = x / s + w := t + t + r = (r - t) / (w + r) // r-s is exact + t = t + t*r + + // restore the sign bit if sign { - y = -y + t = -t } - return y + return t } diff --git a/libgo/go/math/const.go b/libgo/go/math/const.go index f1247c383fd..b4405383c8e 100644 --- a/libgo/go/math/const.go +++ b/libgo/go/math/const.go @@ -6,20 +6,19 @@ package math // Mathematical constants. -// Reference: http://oeis.org/Axxxxxx const ( - E = 2.71828182845904523536028747135266249775724709369995957496696763 // A001113 - Pi = 3.14159265358979323846264338327950288419716939937510582097494459 // A000796 - Phi = 1.61803398874989484820458683436563811772030917980576286213544862 // A001622 + E = 2.71828182845904523536028747135266249775724709369995957496696763 // http://oeis.org/A001113 + Pi = 3.14159265358979323846264338327950288419716939937510582097494459 // http://oeis.org/A000796 + Phi = 1.61803398874989484820458683436563811772030917980576286213544862 // http://oeis.org/A001622 - Sqrt2 = 1.41421356237309504880168872420969807856967187537694807317667974 // A002193 - SqrtE = 1.64872127070012814684865078781416357165377610071014801157507931 // A019774 - SqrtPi = 1.77245385090551602729816748334114518279754945612238712821380779 // A002161 - SqrtPhi = 1.27201964951406896425242246173749149171560804184009624861664038 // A139339 + Sqrt2 = 1.41421356237309504880168872420969807856967187537694807317667974 // http://oeis.org/A002193 + SqrtE = 1.64872127070012814684865078781416357165377610071014801157507931 // http://oeis.org/A019774 + SqrtPi = 1.77245385090551602729816748334114518279754945612238712821380779 // http://oeis.org/A002161 + SqrtPhi = 1.27201964951406896425242246173749149171560804184009624861664038 // http://oeis.org/A139339 - Ln2 = 0.693147180559945309417232121458176568075500134360255254120680009 // A002162 + Ln2 = 0.693147180559945309417232121458176568075500134360255254120680009 // http://oeis.org/A002162 Log2E = 1 / Ln2 - Ln10 = 2.30258509299404568401799145468436420760110148862877297603332790 // A002392 + Ln10 = 2.30258509299404568401799145468436420760110148862877297603332790 // http://oeis.org/A002392 Log10E = 1 / Ln10 ) diff --git a/libgo/go/math/expm1.go b/libgo/go/math/expm1.go index f7e15dbbc9d..8d7b3d365a6 100644 --- a/libgo/go/math/expm1.go +++ b/libgo/go/math/expm1.go @@ -164,11 +164,11 @@ func expm1(x float64) float64 { // filter out huge argument if absx >= Ln2X56 { // if |x| >= 56 * ln2 - if absx >= Othreshold { // if |x| >= 709.78... - return Inf(1) // overflow - } if sign { - return -1 // x < -56*ln2, return -1.0 + return -1 // x < -56*ln2, return -1 + } + if absx >= Othreshold { // if |x| >= 709.78... + return Inf(1) } } diff --git a/libgo/go/math/log10.go b/libgo/go/math/log10.go index d880ec2040d..2c09d88f2a1 100644 --- a/libgo/go/math/log10.go +++ b/libgo/go/math/log10.go @@ -27,5 +27,10 @@ func Log2(x float64) float64 { func log2(x float64) float64 { frac, exp := Frexp(x) + // Make sure exact powers of two give an exact answer. + // Don't depend on Log(0.5)*(1/Ln2)+exp being exactly exp-1. + if frac == 0.5 { + return float64(exp - 1) + } return Log(frac)*(1/Ln2) + float64(exp) } diff --git a/libgo/go/math/nextafter.go b/libgo/go/math/nextafter.go index bbb139986aa..9088e4d248a 100644 --- a/libgo/go/math/nextafter.go +++ b/libgo/go/math/nextafter.go @@ -5,10 +5,11 @@ package math // Nextafter32 returns the next representable float32 value after x towards y. -// Special cases: +// +// Special cases are: // Nextafter32(x, x) = x -// Nextafter32(NaN, y) = NaN -// Nextafter32(x, NaN) = NaN +// Nextafter32(NaN, y) = NaN +// Nextafter32(x, NaN) = NaN func Nextafter32(x, y float32) (r float32) { switch { case IsNaN(float64(x)) || IsNaN(float64(y)): // special case @@ -26,10 +27,11 @@ func Nextafter32(x, y float32) (r float32) { } // Nextafter returns the next representable float64 value after x towards y. -// Special cases: -// Nextafter64(x, x) = x -// Nextafter64(NaN, y) = NaN -// Nextafter64(x, NaN) = NaN +// +// Special cases are: +// Nextafter(x, x) = x +// Nextafter(NaN, y) = NaN +// Nextafter(x, NaN) = NaN func Nextafter(x, y float64) (r float64) { switch { case IsNaN(x) || IsNaN(y): // special case diff --git a/libgo/go/math/rand/rand.go b/libgo/go/math/rand/rand.go index 3ffb5c4e5c6..6360128e391 100644 --- a/libgo/go/math/rand/rand.go +++ b/libgo/go/math/rand/rand.go @@ -9,6 +9,9 @@ // sequence of values each time a program is run. Use the Seed function to // initialize the default Source if different behavior is required for each run. // The default Source is safe for concurrent use by multiple goroutines. +// +// For random numbers suitable for security-sensitive work, see the crypto/rand +// package. package rand import "sync" diff --git a/libgo/go/math/rand/rand_test.go b/libgo/go/math/rand/rand_test.go index ab0dc49b411..c61494f8eb8 100644 --- a/libgo/go/math/rand/rand_test.go +++ b/libgo/go/math/rand/rand_test.go @@ -8,6 +8,8 @@ import ( "errors" "fmt" "math" + "os" + "runtime" "testing" ) @@ -322,10 +324,17 @@ func TestExpTables(t *testing.T) { } } -// For issue 6721, the problem came after 7533753 calls, so check 10e6. func TestFloat32(t *testing.T) { + // For issue 6721, the problem came after 7533753 calls, so check 10e6. + num := int(10e6) + // But ARM5 floating point emulation is slow (Issue 10749), so + // do less for that builder: + if testing.Short() && runtime.GOARCH == "arm" && os.Getenv("GOARM") == "5" { + num /= 100 // 1.72 seconds instead of 172 seconds + } + r := New(NewSource(1)) - for ct := 0; ct < 10e6; ct++ { + for ct := 0; ct < num; ct++ { f := r.Float32() if f >= 1 { t.Fatal("Float32() should be in range [0,1). ct:", ct, "f:", f) diff --git a/libgo/go/math/rand/zipf.go b/libgo/go/math/rand/zipf.go index 8db2c6f5bff..f04c814eb75 100644 --- a/libgo/go/math/rand/zipf.go +++ b/libgo/go/math/rand/zipf.go @@ -32,8 +32,10 @@ func (z *Zipf) hinv(x float64) float64 { return math.Exp(z.oneminusQinv*math.Log(z.oneminusQ*x)) - z.v } -// NewZipf returns a Zipf generating variates p(k) on [0, imax] -// proportional to (v+k)**(-s) where s>1 and k>=0, and v>=1. +// NewZipf returns a Zipf variate generator. +// The generator generates values k ∈ [0, imax] +// such that P(k) is proportional to (v + k) ** (-s). +// Requirements: s > 1 and v >= 1. func NewZipf(r *Rand, s float64, v float64, imax uint64) *Zipf { z := new(Zipf) if s <= 1.0 || v < 1 { diff --git a/libgo/go/math/sqrt.go b/libgo/go/math/sqrt.go index 56122b59814..215d6485442 100644 --- a/libgo/go/math/sqrt.go +++ b/libgo/go/math/sqrt.go @@ -96,6 +96,12 @@ func Sqrt(x float64) float64 { // Sqrt(±0) = ±0 // Sqrt(x < 0) = NaN // Sqrt(NaN) = NaN + +// Note: Sqrt is implemented in assembly on some systems. +// Others have assembly stubs that jump to func sqrt below. +// On systems where Sqrt is a single instruction, the compiler +// may turn a direct call into a direct use of that instruction instead. + func sqrt(x float64) float64 { // special cases switch { diff --git a/libgo/go/mime/encodedword.go b/libgo/go/mime/encodedword.go new file mode 100644 index 00000000000..9796f506dc2 --- /dev/null +++ b/libgo/go/mime/encodedword.go @@ -0,0 +1,329 @@ +// Copyright 2015 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 mime + +import ( + "bytes" + "encoding/base64" + "errors" + "fmt" + "io" + "strings" + "sync" + "unicode" + "unicode/utf8" +) + +// A WordEncoder is a RFC 2047 encoded-word encoder. +type WordEncoder byte + +const ( + // BEncoding represents Base64 encoding scheme as defined by RFC 2045. + BEncoding = WordEncoder('b') + // QEncoding represents the Q-encoding scheme as defined by RFC 2047. + QEncoding = WordEncoder('q') +) + +var ( + errInvalidWord = errors.New("mime: invalid RFC 2047 encoded-word") +) + +// Encode returns the encoded-word form of s. If s is ASCII without special +// characters, it is returned unchanged. The provided charset is the IANA +// charset name of s. It is case insensitive. +func (e WordEncoder) Encode(charset, s string) string { + if !needsEncoding(s) { + return s + } + return e.encodeWord(charset, s) +} + +func needsEncoding(s string) bool { + for _, b := range s { + if (b < ' ' || b > '~') && b != '\t' { + return true + } + } + return false +} + +// encodeWord encodes a string into an encoded-word. +func (e WordEncoder) encodeWord(charset, s string) string { + buf := getBuffer() + defer putBuffer(buf) + + buf.WriteString("=?") + buf.WriteString(charset) + buf.WriteByte('?') + buf.WriteByte(byte(e)) + buf.WriteByte('?') + + if e == BEncoding { + w := base64.NewEncoder(base64.StdEncoding, buf) + io.WriteString(w, s) + w.Close() + } else { + enc := make([]byte, 3) + for i := 0; i < len(s); i++ { + b := s[i] + switch { + case b == ' ': + buf.WriteByte('_') + case b <= '~' && b >= '!' && b != '=' && b != '?' && b != '_': + buf.WriteByte(b) + default: + enc[0] = '=' + enc[1] = upperhex[b>>4] + enc[2] = upperhex[b&0x0f] + buf.Write(enc) + } + } + } + buf.WriteString("?=") + return buf.String() +} + +const upperhex = "0123456789ABCDEF" + +// A WordDecoder decodes MIME headers containing RFC 2047 encoded-words. +type WordDecoder struct { + // CharsetReader, if non-nil, defines a function to generate + // charset-conversion readers, converting from the provided + // charset into UTF-8. + // Charsets are always lower-case. utf-8, iso-8859-1 and us-ascii charsets + // are handled by default. + // One of the the CharsetReader's result values must be non-nil. + CharsetReader func(charset string, input io.Reader) (io.Reader, error) +} + +// Decode decodes an encoded-word. If word is not a valid RFC 2047 encoded-word, +// word is returned unchanged. +func (d *WordDecoder) Decode(word string) (string, error) { + fields := strings.Split(word, "?") // TODO: remove allocation? + if len(fields) != 5 || fields[0] != "=" || fields[4] != "=" || len(fields[2]) != 1 { + return "", errInvalidWord + } + + content, err := decode(fields[2][0], fields[3]) + if err != nil { + return "", err + } + + buf := getBuffer() + defer putBuffer(buf) + + if err := d.convert(buf, fields[1], content); err != nil { + return "", err + } + + return buf.String(), nil +} + +// DecodeHeader decodes all encoded-words of the given string. It returns an +// error if and only if CharsetReader of d returns an error. +func (d *WordDecoder) DecodeHeader(header string) (string, error) { + // If there is no encoded-word, returns before creating a buffer. + i := strings.Index(header, "=?") + if i == -1 { + return header, nil + } + + buf := getBuffer() + defer putBuffer(buf) + + buf.WriteString(header[:i]) + header = header[i:] + + betweenWords := false + for { + start := strings.Index(header, "=?") + if start == -1 { + break + } + cur := start + len("=?") + + i := strings.Index(header[cur:], "?") + if i == -1 { + break + } + charset := header[cur : cur+i] + cur += i + len("?") + + if len(header) < cur+len("Q??=") { + break + } + encoding := header[cur] + cur++ + + if header[cur] != '?' { + break + } + cur++ + + j := strings.Index(header[cur:], "?=") + if j == -1 { + break + } + text := header[cur : cur+j] + end := cur + j + len("?=") + + content, err := decode(encoding, text) + if err != nil { + betweenWords = false + buf.WriteString(header[:start+2]) + header = header[start+2:] + continue + } + + // Write characters before the encoded-word. White-space and newline + // characters separating two encoded-words must be deleted. + if start > 0 && (!betweenWords || hasNonWhitespace(header[:start])) { + buf.WriteString(header[:start]) + } + + if err := d.convert(buf, charset, content); err != nil { + return "", err + } + + header = header[end:] + betweenWords = true + } + + if len(header) > 0 { + buf.WriteString(header) + } + + return buf.String(), nil +} + +func decode(encoding byte, text string) ([]byte, error) { + switch encoding { + case 'B', 'b': + return base64.StdEncoding.DecodeString(text) + case 'Q', 'q': + return qDecode(text) + default: + return nil, errInvalidWord + } +} + +func (d *WordDecoder) convert(buf *bytes.Buffer, charset string, content []byte) error { + switch { + case strings.EqualFold("utf-8", charset): + buf.Write(content) + case strings.EqualFold("iso-8859-1", charset): + for _, c := range content { + buf.WriteRune(rune(c)) + } + case strings.EqualFold("us-ascii", charset): + for _, c := range content { + if c >= utf8.RuneSelf { + buf.WriteRune(unicode.ReplacementChar) + } else { + buf.WriteByte(c) + } + } + default: + if d.CharsetReader == nil { + return fmt.Errorf("mime: unhandled charset %q", charset) + } + r, err := d.CharsetReader(strings.ToLower(charset), bytes.NewReader(content)) + if err != nil { + return err + } + if _, err = buf.ReadFrom(r); err != nil { + return err + } + } + return nil +} + +// hasNonWhitespace reports whether s (assumed to be ASCII) contains at least +// one byte of non-whitespace. +func hasNonWhitespace(s string) bool { + for _, b := range s { + switch b { + // Encoded-words can only be separated by linear white spaces which does + // not include vertical tabs (\v). + case ' ', '\t', '\n', '\r': + default: + return true + } + } + return false +} + +// qDecode decodes a Q encoded string. +func qDecode(s string) ([]byte, error) { + dec := make([]byte, len(s)) + n := 0 + for i := 0; i < len(s); i++ { + switch c := s[i]; { + case c == '_': + dec[n] = ' ' + case c == '=': + if i+2 >= len(s) { + return nil, errInvalidWord + } + b, err := readHexByte(s[i+1], s[i+2]) + if err != nil { + return nil, err + } + dec[n] = b + i += 2 + case (c <= '~' && c >= ' ') || c == '\n' || c == '\r' || c == '\t': + dec[n] = c + default: + return nil, errInvalidWord + } + n++ + } + + return dec[:n], nil +} + +// readHexByte returns the byte from its quoted-printable representation. +func readHexByte(a, b byte) (byte, error) { + var hb, lb byte + var err error + if hb, err = fromHex(a); err != nil { + return 0, err + } + if lb, err = fromHex(b); err != nil { + return 0, err + } + return hb<<4 | lb, nil +} + +func fromHex(b byte) (byte, error) { + switch { + case b >= '0' && b <= '9': + return b - '0', nil + case b >= 'A' && b <= 'F': + return b - 'A' + 10, nil + // Accept badly encoded bytes. + case b >= 'a' && b <= 'f': + return b - 'a' + 10, nil + } + return 0, fmt.Errorf("mime: invalid hex byte %#02x", b) +} + +var bufPool = sync.Pool{ + New: func() interface{} { + return new(bytes.Buffer) + }, +} + +func getBuffer() *bytes.Buffer { + return bufPool.Get().(*bytes.Buffer) +} + +func putBuffer(buf *bytes.Buffer) { + if buf.Len() > 1024 { + return + } + buf.Reset() + bufPool.Put(buf) +} diff --git a/libgo/go/mime/encodedword_test.go b/libgo/go/mime/encodedword_test.go new file mode 100644 index 00000000000..2beff5d3414 --- /dev/null +++ b/libgo/go/mime/encodedword_test.go @@ -0,0 +1,287 @@ +// Copyright 2015 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 mime + +import ( + "bytes" + "errors" + "fmt" + "io" + "io/ioutil" + "strings" + "testing" +) + +func ExampleWordEncoder_Encode() { + fmt.Println(QEncoding.Encode("utf-8", "¡Hola, señor!")) + fmt.Println(QEncoding.Encode("utf-8", "Hello!")) + fmt.Println(BEncoding.Encode("UTF-8", "¡Hola, señor!")) + fmt.Println(QEncoding.Encode("ISO-8859-1", "Caf\xE9")) + // Output: + // =?utf-8?q?=C2=A1Hola,_se=C3=B1or!?= + // Hello! + // =?UTF-8?b?wqFIb2xhLCBzZcOxb3Ih?= + // =?ISO-8859-1?q?Caf=E9?= +} + +func ExampleWordDecoder_Decode() { + dec := new(WordDecoder) + header, err := dec.Decode("=?utf-8?q?=C2=A1Hola,_se=C3=B1or!?=") + if err != nil { + panic(err) + } + fmt.Println(header) + + dec.CharsetReader = func(charset string, input io.Reader) (io.Reader, error) { + switch charset { + case "x-case": + // Fake character set for example. + // Real use would integrate with packages such + // as code.google.com/p/go-charset + content, err := ioutil.ReadAll(input) + if err != nil { + return nil, err + } + return bytes.NewReader(bytes.ToUpper(content)), nil + default: + return nil, fmt.Errorf("unhandled charset %q", charset) + } + } + header, err = dec.Decode("=?x-case?q?hello!?=") + if err != nil { + panic(err) + } + fmt.Println(header) + // Output: + // ¡Hola, señor! + // HELLO! +} + +func ExampleWordDecoder_DecodeHeader() { + dec := new(WordDecoder) + header, err := dec.DecodeHeader("=?utf-8?q?=C3=89ric?= , =?utf-8?q?Ana=C3=AFs?= ") + if err != nil { + panic(err) + } + fmt.Println(header) + + header, err = dec.DecodeHeader("=?utf-8?q?=C2=A1Hola,?= =?utf-8?q?_se=C3=B1or!?=") + if err != nil { + panic(err) + } + fmt.Println(header) + + dec.CharsetReader = func(charset string, input io.Reader) (io.Reader, error) { + switch charset { + case "x-case": + // Fake character set for example. + // Real use would integrate with packages such + // as code.google.com/p/go-charset + content, err := ioutil.ReadAll(input) + if err != nil { + return nil, err + } + return bytes.NewReader(bytes.ToUpper(content)), nil + default: + return nil, fmt.Errorf("unhandled charset %q", charset) + } + } + header, err = dec.DecodeHeader("=?x-case?q?hello_?= =?x-case?q?world!?=") + if err != nil { + panic(err) + } + fmt.Println(header) + // Output: + // Éric , Anaïs + // ¡Hola, señor! + // HELLO WORLD! +} + +func TestEncodeWord(t *testing.T) { + utf8, iso88591 := "utf-8", "iso-8859-1" + tests := []struct { + enc WordEncoder + charset string + src, exp string + }{ + {QEncoding, utf8, "François-Jérôme", "=?utf-8?q?Fran=C3=A7ois-J=C3=A9r=C3=B4me?="}, + {BEncoding, utf8, "Café", "=?utf-8?b?Q2Fmw6k=?="}, + {QEncoding, iso88591, "La Seleção", "=?iso-8859-1?q?La_Sele=C3=A7=C3=A3o?="}, + {QEncoding, utf8, "", ""}, + {QEncoding, utf8, "A", "A"}, + {QEncoding, iso88591, "a", "a"}, + {QEncoding, utf8, "123 456", "123 456"}, + {QEncoding, utf8, "\t !\"#$%&'()*+,-./ :;<>?@[\\]^_`{|}~", "\t !\"#$%&'()*+,-./ :;<>?@[\\]^_`{|}~"}, + } + + for _, test := range tests { + if s := test.enc.Encode(test.charset, test.src); s != test.exp { + t.Errorf("Encode(%q) = %q, want %q", test.src, s, test.exp) + } + } +} + +func TestDecodeWord(t *testing.T) { + tests := []struct { + src, exp string + hasErr bool + }{ + {"=?UTF-8?Q?=C2=A1Hola,_se=C3=B1or!?=", "¡Hola, señor!", false}, + {"=?UTF-8?Q?Fran=C3=A7ois-J=C3=A9r=C3=B4me?=", "François-Jérôme", false}, + {"=?UTF-8?q?ascii?=", "ascii", false}, + {"=?utf-8?B?QW5kcsOp?=", "André", false}, + {"=?ISO-8859-1?Q?Rapha=EBl_Dupont?=", "Raphaël Dupont", false}, + {"=?utf-8?b?IkFudG9uaW8gSm9zw6kiIDxqb3NlQGV4YW1wbGUub3JnPg==?=", `"Antonio José" `, false}, + {"=?UTF-8?A?Test?=", "", true}, + {"=?UTF-8?Q?A=B?=", "", true}, + {"=?UTF-8?Q?=A?=", "", true}, + {"=?UTF-8?A?A?=", "", true}, + } + + for _, test := range tests { + dec := new(WordDecoder) + s, err := dec.Decode(test.src) + if test.hasErr && err == nil { + t.Errorf("Decode(%q) should return an error", test.src) + continue + } + if !test.hasErr && err != nil { + t.Errorf("Decode(%q): %v", test.src, err) + continue + } + if s != test.exp { + t.Errorf("Decode(%q) = %q, want %q", test.src, s, test.exp) + } + } +} + +func TestDecodeHeader(t *testing.T) { + tests := []struct { + src, exp string + }{ + {"=?UTF-8?Q?=C2=A1Hola,_se=C3=B1or!?=", "¡Hola, señor!"}, + {"=?UTF-8?Q?Fran=C3=A7ois-J=C3=A9r=C3=B4me?=", "François-Jérôme"}, + {"=?UTF-8?q?ascii?=", "ascii"}, + {"=?utf-8?B?QW5kcsOp?=", "André"}, + {"=?ISO-8859-1?Q?Rapha=EBl_Dupont?=", "Raphaël Dupont"}, + {"Jean", "Jean"}, + {"=?utf-8?b?IkFudG9uaW8gSm9zw6kiIDxqb3NlQGV4YW1wbGUub3JnPg==?=", `"Antonio José" `}, + {"=?UTF-8?A?Test?=", "=?UTF-8?A?Test?="}, + {"=?UTF-8?Q?A=B?=", "=?UTF-8?Q?A=B?="}, + {"=?UTF-8?Q?=A?=", "=?UTF-8?Q?=A?="}, + {"=?UTF-8?A?A?=", "=?UTF-8?A?A?="}, + // Incomplete words + {"=?", "=?"}, + {"=?UTF-8?", "=?UTF-8?"}, + {"=?UTF-8?=", "=?UTF-8?="}, + {"=?UTF-8?Q", "=?UTF-8?Q"}, + {"=?UTF-8?Q?", "=?UTF-8?Q?"}, + {"=?UTF-8?Q?=", "=?UTF-8?Q?="}, + {"=?UTF-8?Q?A", "=?UTF-8?Q?A"}, + {"=?UTF-8?Q?A?", "=?UTF-8?Q?A?"}, + // Tests from RFC 2047 + {"=?ISO-8859-1?Q?a?=", "a"}, + {"=?ISO-8859-1?Q?a?= b", "a b"}, + {"=?ISO-8859-1?Q?a?= =?ISO-8859-1?Q?b?=", "ab"}, + {"=?ISO-8859-1?Q?a?= =?ISO-8859-1?Q?b?=", "ab"}, + {"=?ISO-8859-1?Q?a?= \r\n\t =?ISO-8859-1?Q?b?=", "ab"}, + {"=?ISO-8859-1?Q?a_b?=", "a b"}, + } + + for _, test := range tests { + dec := new(WordDecoder) + s, err := dec.DecodeHeader(test.src) + if err != nil { + t.Errorf("DecodeHeader(%q): %v", test.src, err) + } + if s != test.exp { + t.Errorf("DecodeHeader(%q) = %q, want %q", test.src, s, test.exp) + } + } +} + +func TestCharsetDecoder(t *testing.T) { + tests := []struct { + src string + want string + charsets []string + content []string + }{ + {"=?utf-8?b?Q2Fmw6k=?=", "Café", nil, nil}, + {"=?ISO-8859-1?Q?caf=E9?=", "café", nil, nil}, + {"=?US-ASCII?Q?foo_bar?=", "foo bar", nil, nil}, + {"=?utf-8?Q?=?=", "=?utf-8?Q?=?=", nil, nil}, + {"=?utf-8?Q?=A?=", "=?utf-8?Q?=A?=", nil, nil}, + { + "=?ISO-8859-15?Q?f=F5=F6?= =?windows-1252?Q?b=E0r?=", + "f\xf5\xf6b\xe0r", + []string{"iso-8859-15", "windows-1252"}, + []string{"f\xf5\xf6", "b\xe0r"}, + }, + } + + for _, test := range tests { + i := 0 + dec := &WordDecoder{ + CharsetReader: func(charset string, input io.Reader) (io.Reader, error) { + if charset != test.charsets[i] { + t.Errorf("DecodeHeader(%q), got charset %q, want %q", test.src, charset, test.charsets[i]) + } + content, err := ioutil.ReadAll(input) + if err != nil { + t.Errorf("DecodeHeader(%q), error in reader: %v", test.src, err) + } + got := string(content) + if got != test.content[i] { + t.Errorf("DecodeHeader(%q), got content %q, want %q", test.src, got, test.content[i]) + } + i++ + + return strings.NewReader(got), nil + }, + } + got, err := dec.DecodeHeader(test.src) + if err != nil { + t.Errorf("DecodeHeader(%q): %v", test.src, err) + } + if got != test.want { + t.Errorf("DecodeHeader(%q) = %q, want %q", test.src, got, test.want) + } + } +} + +func TestCharsetDecoderError(t *testing.T) { + dec := &WordDecoder{ + CharsetReader: func(charset string, input io.Reader) (io.Reader, error) { + return nil, errors.New("Test error") + }, + } + + if _, err := dec.DecodeHeader("=?charset?Q?foo?="); err == nil { + t.Error("DecodeHeader should return an error") + } +} + +func BenchmarkQEncodeWord(b *testing.B) { + for i := 0; i < b.N; i++ { + QEncoding.Encode("UTF-8", "¡Hola, señor!") + } +} + +func BenchmarkQDecodeWord(b *testing.B) { + dec := new(WordDecoder) + + for i := 0; i < b.N; i++ { + dec.Decode("=?utf-8?q?=C2=A1Hola,_se=C3=B1or!?=") + } +} + +func BenchmarkQDecodeHeader(b *testing.B) { + dec := new(WordDecoder) + + for i := 0; i < b.N; i++ { + dec.Decode("=?utf-8?q?=C2=A1Hola,_se=C3=B1or!?=") + } +} diff --git a/libgo/go/mime/grammar.go b/libgo/go/mime/grammar.go index 2347324aa5a..31b66e8f03a 100644 --- a/libgo/go/mime/grammar.go +++ b/libgo/go/mime/grammar.go @@ -8,13 +8,13 @@ import ( "strings" ) -// isTSpecial returns true if rune is in 'tspecials' as defined by RFC +// isTSpecial reports whether rune is in 'tspecials' as defined by RFC // 1521 and RFC 2045. func isTSpecial(r rune) bool { return strings.IndexRune(`()<>@,;:\"/[]?=`, r) != -1 } -// isTokenChar returns true if rune is in 'token' as defined by RFC +// isTokenChar reports whether rune is in 'token' as defined by RFC // 1521 and RFC 2045. func isTokenChar(r rune) bool { // token := 1* 0x20 && r < 0x7f && !isTSpecial(r) } -// isToken returns true if s is a 'token' as defined by RFC 1521 +// isToken reports whether s is a 'token' as defined by RFC 1521 // and RFC 2045. func isToken(s string) bool { if s == "" { diff --git a/libgo/go/mime/multipart/multipart.go b/libgo/go/mime/multipart/multipart.go index 01a667d930d..6f65a55de27 100644 --- a/libgo/go/mime/multipart/multipart.go +++ b/libgo/go/mime/multipart/multipart.go @@ -19,6 +19,7 @@ import ( "io" "io/ioutil" "mime" + "mime/quotedprintable" "net/textproto" ) @@ -111,7 +112,7 @@ func newPart(mr *Reader) (*Part, error) { const cte = "Content-Transfer-Encoding" if bp.Header.Get(cte) == "quoted-printable" { bp.Header.Del(cte) - bp.r = newQuotedPrintableReader(bp.r) + bp.r = quotedprintable.NewReader(bp.r) } return bp, nil } @@ -164,16 +165,18 @@ func (pr partReader) Read(d []byte) (n int, err error) { if peek == nil { panic("nil peek buf") } - // Search the peek buffer for "\r\n--boundary". If found, // consume everything up to the boundary. If not, consume only // as much of the peek buffer as cannot hold the boundary // string. nCopy := 0 foundBoundary := false - if idx := bytes.Index(peek, p.mr.nlDashBoundary); idx != -1 { + if idx, isEnd := p.mr.peekBufferSeparatorIndex(peek); idx != -1 { nCopy = idx - foundBoundary = true + foundBoundary = isEnd + if !isEnd && nCopy == 0 { + nCopy = 1 // make some progress. + } } else if safeCount := len(peek) - len(p.mr.nlDashBoundary); safeCount > 0 { nCopy = safeCount } else if unexpectedEOF { @@ -337,6 +340,33 @@ func (mr *Reader) peekBufferIsEmptyPart(peek []byte) bool { return bytes.HasPrefix(rest, mr.nl) } +// peekBufferSeparatorIndex returns the index of mr.nlDashBoundary in +// peek and whether it is a real boundary (and not a prefix of an +// unrelated separator). To be the end, the peek buffer must contain a +// newline after the boundary. +func (mr *Reader) peekBufferSeparatorIndex(peek []byte) (idx int, isEnd bool) { + idx = bytes.Index(peek, mr.nlDashBoundary) + if idx == -1 { + return + } + peek = peek[idx+len(mr.nlDashBoundary):] + if len(peek) > 1 && peek[0] == '-' && peek[1] == '-' { + return idx, true + } + peek = skipLWSPChar(peek) + // Don't have a complete line after the peek. + if bytes.IndexByte(peek, '\n') == -1 { + return -1, false + } + if len(peek) > 0 && peek[0] == '\n' { + return idx, true + } + if len(peek) > 1 && peek[0] == '\r' && peek[1] == '\n' { + return idx, true + } + return idx, false +} + // skipLWSPChar returns b with leading spaces and tabs removed. // RFC 822 defines: // LWSP-char = SPACE / HTAB diff --git a/libgo/go/mime/multipart/multipart_test.go b/libgo/go/mime/multipart/multipart_test.go index d662e834059..30452d1d458 100644 --- a/libgo/go/mime/multipart/multipart_test.go +++ b/libgo/go/mime/multipart/multipart_test.go @@ -351,7 +351,7 @@ func TestLineContinuation(t *testing.T) { } func TestQuotedPrintableEncoding(t *testing.T) { - // From http://golang.org/issue/4411 + // From https://golang.org/issue/4411 body := "--0016e68ee29c5d515f04cedf6733\r\nContent-Type: text/plain; charset=ISO-8859-1\r\nContent-Disposition: form-data; name=text\r\nContent-Transfer-Encoding: quoted-printable\r\n\r\nwords words words words words words words words words words words words wor=\r\nds words words words words words words words words words words words words =\r\nwords words words words words words words words words words words words wor=\r\nds words words words words words words words words words words words words =\r\nwords words words words words words words words words\r\n--0016e68ee29c5d515f04cedf6733\r\nContent-Type: text/plain; charset=ISO-8859-1\r\nContent-Disposition: form-data; name=submit\r\n\r\nSubmit\r\n--0016e68ee29c5d515f04cedf6733--" r := NewReader(strings.NewReader(body), "0016e68ee29c5d515f04cedf6733") part, err := r.NextPart() @@ -565,6 +565,58 @@ foo: bar }, }, + // Issue 10616; minimal + { + name: "issue 10616 minimal", + sep: "sep", + in: "--sep \r\nFoo: bar\r\n\r\n" + + "a\r\n" + + "--sep_alt\r\n" + + "b\r\n" + + "\r\n--sep--", + want: []headerBody{ + {textproto.MIMEHeader{"Foo": {"bar"}}, "a\r\n--sep_alt\r\nb\r\n"}, + }, + }, + + // Issue 10616; full example from bug. + { + name: "nested separator prefix is outer separator", + sep: "----=_NextPart_4c2fbafd7ec4c8bf08034fe724b608d9", + in: strings.Replace(`------=_NextPart_4c2fbafd7ec4c8bf08034fe724b608d9 +Content-Type: multipart/alternative; boundary="----=_NextPart_4c2fbafd7ec4c8bf08034fe724b608d9_alt" + +------=_NextPart_4c2fbafd7ec4c8bf08034fe724b608d9_alt +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 8bit + +This is a multi-part message in MIME format. + +------=_NextPart_4c2fbafd7ec4c8bf08034fe724b608d9_alt +Content-Type: text/html; charset="utf-8" +Content-Transfer-Encoding: 8bit + +html things +------=_NextPart_4c2fbafd7ec4c8bf08034fe724b608d9_alt-- +------=_NextPart_4c2fbafd7ec4c8bf08034fe724b608d9--`, "\n", "\r\n", -1), + want: []headerBody{ + {textproto.MIMEHeader{"Content-Type": {`multipart/alternative; boundary="----=_NextPart_4c2fbafd7ec4c8bf08034fe724b608d9_alt"`}}, + strings.Replace(`------=_NextPart_4c2fbafd7ec4c8bf08034fe724b608d9_alt +Content-Type: text/plain; charset="utf-8" +Content-Transfer-Encoding: 8bit + +This is a multi-part message in MIME format. + +------=_NextPart_4c2fbafd7ec4c8bf08034fe724b608d9_alt +Content-Type: text/html; charset="utf-8" +Content-Transfer-Encoding: 8bit + +html things +------=_NextPart_4c2fbafd7ec4c8bf08034fe724b608d9_alt--`, "\n", "\r\n", -1), + }, + }, + }, + roundTripParseTest(), } diff --git a/libgo/go/mime/multipart/quotedprintable.go b/libgo/go/mime/multipart/quotedprintable.go deleted file mode 100644 index 9ff4ee703ee..00000000000 --- a/libgo/go/mime/multipart/quotedprintable.go +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// The file define a quoted-printable decoder, as specified in RFC 2045. -// Deviations: -// 1. in addition to "=\r\n", "=\n" is also treated as soft line break. -// 2. it will pass through a '\r' or '\n' not preceded by '=', consistent -// with other broken QP encoders & decoders. - -package multipart - -import ( - "bufio" - "bytes" - "fmt" - "io" -) - -type qpReader struct { - br *bufio.Reader - rerr error // last read error - line []byte // to be consumed before more of br -} - -func newQuotedPrintableReader(r io.Reader) io.Reader { - return &qpReader{ - br: bufio.NewReader(r), - } -} - -func fromHex(b byte) (byte, error) { - switch { - case b >= '0' && b <= '9': - return b - '0', nil - case b >= 'A' && b <= 'F': - return b - 'A' + 10, nil - } - return 0, fmt.Errorf("multipart: invalid quoted-printable hex byte 0x%02x", b) -} - -func (q *qpReader) readHexByte(v []byte) (b byte, err error) { - if len(v) < 2 { - return 0, io.ErrUnexpectedEOF - } - var hb, lb byte - if hb, err = fromHex(v[0]); err != nil { - return 0, err - } - if lb, err = fromHex(v[1]); err != nil { - return 0, err - } - return hb<<4 | lb, nil -} - -func isQPDiscardWhitespace(r rune) bool { - switch r { - case '\n', '\r', ' ', '\t': - return true - } - return false -} - -var ( - crlf = []byte("\r\n") - lf = []byte("\n") - softSuffix = []byte("=") -) - -func (q *qpReader) Read(p []byte) (n int, err error) { - for len(p) > 0 { - if len(q.line) == 0 { - if q.rerr != nil { - return n, q.rerr - } - q.line, q.rerr = q.br.ReadSlice('\n') - - // Does the line end in CRLF instead of just LF? - hasLF := bytes.HasSuffix(q.line, lf) - hasCR := bytes.HasSuffix(q.line, crlf) - wholeLine := q.line - q.line = bytes.TrimRightFunc(wholeLine, isQPDiscardWhitespace) - if bytes.HasSuffix(q.line, softSuffix) { - rightStripped := wholeLine[len(q.line):] - q.line = q.line[:len(q.line)-1] - if !bytes.HasPrefix(rightStripped, lf) && !bytes.HasPrefix(rightStripped, crlf) { - q.rerr = fmt.Errorf("multipart: invalid bytes after =: %q", rightStripped) - } - } else if hasLF { - if hasCR { - q.line = append(q.line, '\r', '\n') - } else { - q.line = append(q.line, '\n') - } - } - continue - } - b := q.line[0] - - switch { - case b == '=': - b, err = q.readHexByte(q.line[1:]) - if err != nil { - return n, err - } - q.line = q.line[2:] // 2 of the 3; other 1 is done below - case b == '\t' || b == '\r' || b == '\n': - break - case b < ' ' || b > '~': - return n, fmt.Errorf("multipart: invalid unescaped byte 0x%02x in quoted-printable body", b) - } - p[0] = b - p = p[1:] - q.line = q.line[1:] - n++ - } - return n, nil -} diff --git a/libgo/go/mime/multipart/quotedprintable_test.go b/libgo/go/mime/multipart/quotedprintable_test.go deleted file mode 100644 index c4de3eb7566..00000000000 --- a/libgo/go/mime/multipart/quotedprintable_test.go +++ /dev/null @@ -1,204 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package multipart - -import ( - "bufio" - "bytes" - "errors" - "flag" - "fmt" - "io" - "os/exec" - "regexp" - "sort" - "strings" - "testing" - "time" -) - -func TestQuotedPrintable(t *testing.T) { - tests := []struct { - in, want string - err interface{} - }{ - {in: "", want: ""}, - {in: "foo bar", want: "foo bar"}, - {in: "foo bar=3D", want: "foo bar="}, - {in: "foo bar=\n", want: "foo bar"}, - {in: "foo bar\n", want: "foo bar\n"}, // somewhat lax. - {in: "foo bar=0", want: "foo bar", err: io.ErrUnexpectedEOF}, - {in: "foo bar=ab", want: "foo bar", err: "multipart: invalid quoted-printable hex byte 0x61"}, - {in: "foo bar=0D=0A", want: "foo bar\r\n"}, - {in: " A B \r\n C ", want: " A B\r\n C"}, - {in: " A B =\r\n C ", want: " A B C"}, - {in: " A B =\n C ", want: " A B C"}, // lax. treating LF as CRLF - {in: "foo=\nbar", want: "foobar"}, - {in: "foo\x00bar", want: "foo", err: "multipart: invalid unescaped byte 0x00 in quoted-printable body"}, - {in: "foo bar\xff", want: "foo bar", err: "multipart: invalid unescaped byte 0xff in quoted-printable body"}, - - // Equal sign. - {in: "=3D30\n", want: "=30\n"}, - {in: "=00=FF0=\n", want: "\x00\xff0"}, - - // Trailing whitespace - {in: "foo \n", want: "foo\n"}, - {in: "foo \n\nfoo =\n\nfoo=20\n\n", want: "foo\n\nfoo \nfoo \n\n"}, - - // Tests that we allow bare \n and \r through, despite it being strictly - // not permitted per RFC 2045, Section 6.7 Page 22 bullet (4). - {in: "foo\nbar", want: "foo\nbar"}, - {in: "foo\rbar", want: "foo\rbar"}, - {in: "foo\r\nbar", want: "foo\r\nbar"}, - - // Different types of soft line-breaks. - {in: "foo=\r\nbar", want: "foobar"}, - {in: "foo=\nbar", want: "foobar"}, - {in: "foo=\rbar", want: "foo", err: "multipart: invalid quoted-printable hex byte 0x0d"}, - {in: "foo=\r\r\r \nbar", want: "foo", err: `multipart: invalid bytes after =: "\r\r\r \n"`}, - - // Example from RFC 2045: - {in: "Now's the time =\n" + "for all folk to come=\n" + " to the aid of their country.", - want: "Now's the time for all folk to come to the aid of their country."}, - } - for _, tt := range tests { - var buf bytes.Buffer - _, err := io.Copy(&buf, newQuotedPrintableReader(strings.NewReader(tt.in))) - if got := buf.String(); got != tt.want { - t.Errorf("for %q, got %q; want %q", tt.in, got, tt.want) - } - switch verr := tt.err.(type) { - case nil: - if err != nil { - t.Errorf("for %q, got unexpected error: %v", tt.in, err) - } - case string: - if got := fmt.Sprint(err); got != verr { - t.Errorf("for %q, got error %q; want %q", tt.in, got, verr) - } - case error: - if err != verr { - t.Errorf("for %q, got error %q; want %q", tt.in, err, verr) - } - } - } - -} - -func everySequence(base, alpha string, length int, fn func(string)) { - if len(base) == length { - fn(base) - return - } - for i := 0; i < len(alpha); i++ { - everySequence(base+alpha[i:i+1], alpha, length, fn) - } -} - -var useQprint = flag.Bool("qprint", false, "Compare against the 'qprint' program.") - -var badSoftRx = regexp.MustCompile(`=([^\r\n]+?\n)|([^\r\n]+$)|(\r$)|(\r[^\n]+\n)|( \r\n)`) - -func TestQPExhaustive(t *testing.T) { - if *useQprint { - _, err := exec.LookPath("qprint") - if err != nil { - t.Fatalf("Error looking for qprint: %v", err) - } - } - - var buf bytes.Buffer - res := make(map[string]int) - everySequence("", "0A \r\n=", 6, func(s string) { - if strings.HasSuffix(s, "=") || strings.Contains(s, "==") { - return - } - buf.Reset() - _, err := io.Copy(&buf, newQuotedPrintableReader(strings.NewReader(s))) - if err != nil { - errStr := err.Error() - if strings.Contains(errStr, "invalid bytes after =:") { - errStr = "invalid bytes after =" - } - res[errStr]++ - if strings.Contains(errStr, "invalid quoted-printable hex byte ") { - if strings.HasSuffix(errStr, "0x20") && (strings.Contains(s, "=0 ") || strings.Contains(s, "=A ") || strings.Contains(s, "= ")) { - return - } - if strings.HasSuffix(errStr, "0x3d") && (strings.Contains(s, "=0=") || strings.Contains(s, "=A=")) { - return - } - if strings.HasSuffix(errStr, "0x0a") || strings.HasSuffix(errStr, "0x0d") { - // bunch of cases; since whitespace at the end of a line before \n is removed. - return - } - } - if strings.Contains(errStr, "unexpected EOF") { - return - } - if errStr == "invalid bytes after =" && badSoftRx.MatchString(s) { - return - } - t.Errorf("decode(%q) = %v", s, err) - return - } - if *useQprint { - cmd := exec.Command("qprint", "-d") - cmd.Stdin = strings.NewReader(s) - stderr, err := cmd.StderrPipe() - if err != nil { - panic(err) - } - qpres := make(chan interface{}, 2) - go func() { - br := bufio.NewReader(stderr) - s, _ := br.ReadString('\n') - if s != "" { - qpres <- errors.New(s) - if cmd.Process != nil { - // It can get stuck on invalid input, like: - // echo -n "0000= " | qprint -d - cmd.Process.Kill() - } - } - }() - go func() { - want, err := cmd.Output() - if err == nil { - qpres <- want - } - }() - select { - case got := <-qpres: - if want, ok := got.([]byte); ok { - if string(want) != buf.String() { - t.Errorf("go decode(%q) = %q; qprint = %q", s, want, buf.String()) - } - } else { - t.Logf("qprint -d(%q) = %v", s, got) - } - case <-time.After(5 * time.Second): - t.Logf("qprint timeout on %q", s) - } - } - res["OK"]++ - }) - var outcomes []string - for k, v := range res { - outcomes = append(outcomes, fmt.Sprintf("%v: %d", k, v)) - } - sort.Strings(outcomes) - got := strings.Join(outcomes, "\n") - want := `OK: 21576 -invalid bytes after =: 3397 -multipart: invalid quoted-printable hex byte 0x0a: 1400 -multipart: invalid quoted-printable hex byte 0x0d: 2700 -multipart: invalid quoted-printable hex byte 0x20: 2490 -multipart: invalid quoted-printable hex byte 0x3d: 440 -unexpected EOF: 3122` - if got != want { - t.Errorf("Got:\n%s\nWant:\n%s", got, want) - } -} diff --git a/libgo/go/mime/multipart/writer.go b/libgo/go/mime/multipart/writer.go index e13a956afee..80960939d62 100644 --- a/libgo/go/mime/multipart/writer.go +++ b/libgo/go/mime/multipart/writer.go @@ -39,7 +39,8 @@ func (w *Writer) Boundary() string { // boundary separator with an explicit value. // // SetBoundary must be called before any parts are created, may only -// contain certain ASCII characters, and must be 1-69 bytes long. +// contain certain ASCII characters, and must be non-empty and +// at most 69 bytes long. func (w *Writer) SetBoundary(boundary string) error { if w.lastpart != nil { return errors.New("mime: SetBoundary called after write") diff --git a/libgo/go/mime/quotedprintable/reader.go b/libgo/go/mime/quotedprintable/reader.go new file mode 100644 index 00000000000..3bd6833da5f --- /dev/null +++ b/libgo/go/mime/quotedprintable/reader.go @@ -0,0 +1,124 @@ +// 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 quotedprintable implements quoted-printable encoding as specified by +// RFC 2045. +package quotedprintable + +import ( + "bufio" + "bytes" + "fmt" + "io" +) + +// Reader is a quoted-printable decoder. +type Reader struct { + br *bufio.Reader + rerr error // last read error + line []byte // to be consumed before more of br +} + +// NewReader returns a quoted-printable reader, decoding from r. +func NewReader(r io.Reader) *Reader { + return &Reader{ + br: bufio.NewReader(r), + } +} + +func fromHex(b byte) (byte, error) { + switch { + case b >= '0' && b <= '9': + return b - '0', nil + case b >= 'A' && b <= 'F': + return b - 'A' + 10, nil + // Accept badly encoded bytes. + case b >= 'a' && b <= 'f': + return b - 'a' + 10, nil + } + return 0, fmt.Errorf("quotedprintable: invalid hex byte 0x%02x", b) +} + +func readHexByte(v []byte) (b byte, err error) { + if len(v) < 2 { + return 0, io.ErrUnexpectedEOF + } + var hb, lb byte + if hb, err = fromHex(v[0]); err != nil { + return 0, err + } + if lb, err = fromHex(v[1]); err != nil { + return 0, err + } + return hb<<4 | lb, nil +} + +func isQPDiscardWhitespace(r rune) bool { + switch r { + case '\n', '\r', ' ', '\t': + return true + } + return false +} + +var ( + crlf = []byte("\r\n") + lf = []byte("\n") + softSuffix = []byte("=") +) + +// Read reads and decodes quoted-printable data from the underlying reader. +func (r *Reader) Read(p []byte) (n int, err error) { + // Deviations from RFC 2045: + // 1. in addition to "=\r\n", "=\n" is also treated as soft line break. + // 2. it will pass through a '\r' or '\n' not preceded by '=', consistent + // with other broken QP encoders & decoders. + for len(p) > 0 { + if len(r.line) == 0 { + if r.rerr != nil { + return n, r.rerr + } + r.line, r.rerr = r.br.ReadSlice('\n') + + // Does the line end in CRLF instead of just LF? + hasLF := bytes.HasSuffix(r.line, lf) + hasCR := bytes.HasSuffix(r.line, crlf) + wholeLine := r.line + r.line = bytes.TrimRightFunc(wholeLine, isQPDiscardWhitespace) + if bytes.HasSuffix(r.line, softSuffix) { + rightStripped := wholeLine[len(r.line):] + r.line = r.line[:len(r.line)-1] + if !bytes.HasPrefix(rightStripped, lf) && !bytes.HasPrefix(rightStripped, crlf) { + r.rerr = fmt.Errorf("quotedprintable: invalid bytes after =: %q", rightStripped) + } + } else if hasLF { + if hasCR { + r.line = append(r.line, '\r', '\n') + } else { + r.line = append(r.line, '\n') + } + } + continue + } + b := r.line[0] + + switch { + case b == '=': + b, err = readHexByte(r.line[1:]) + if err != nil { + return n, err + } + r.line = r.line[2:] // 2 of the 3; other 1 is done below + case b == '\t' || b == '\r' || b == '\n': + break + case b < ' ' || b > '~': + return n, fmt.Errorf("quotedprintable: invalid unescaped byte 0x%02x in body", b) + } + p[0] = b + p = p[1:] + r.line = r.line[1:] + n++ + } + return n, nil +} diff --git a/libgo/go/mime/quotedprintable/reader_test.go b/libgo/go/mime/quotedprintable/reader_test.go new file mode 100644 index 00000000000..e77b2610ec1 --- /dev/null +++ b/libgo/go/mime/quotedprintable/reader_test.go @@ -0,0 +1,204 @@ +// 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 quotedprintable + +import ( + "bufio" + "bytes" + "errors" + "flag" + "fmt" + "io" + "os/exec" + "regexp" + "sort" + "strings" + "testing" + "time" +) + +func TestReader(t *testing.T) { + tests := []struct { + in, want string + err interface{} + }{ + {in: "", want: ""}, + {in: "foo bar", want: "foo bar"}, + {in: "foo bar=3D", want: "foo bar="}, + {in: "foo bar=3d", want: "foo bar="}, // lax. + {in: "foo bar=\n", want: "foo bar"}, + {in: "foo bar\n", want: "foo bar\n"}, // somewhat lax. + {in: "foo bar=0", want: "foo bar", err: io.ErrUnexpectedEOF}, + {in: "foo bar=0D=0A", want: "foo bar\r\n"}, + {in: " A B \r\n C ", want: " A B\r\n C"}, + {in: " A B =\r\n C ", want: " A B C"}, + {in: " A B =\n C ", want: " A B C"}, // lax. treating LF as CRLF + {in: "foo=\nbar", want: "foobar"}, + {in: "foo\x00bar", want: "foo", err: "quotedprintable: invalid unescaped byte 0x00 in body"}, + {in: "foo bar\xff", want: "foo bar", err: "quotedprintable: invalid unescaped byte 0xff in body"}, + + // Equal sign. + {in: "=3D30\n", want: "=30\n"}, + {in: "=00=FF0=\n", want: "\x00\xff0"}, + + // Trailing whitespace + {in: "foo \n", want: "foo\n"}, + {in: "foo \n\nfoo =\n\nfoo=20\n\n", want: "foo\n\nfoo \nfoo \n\n"}, + + // Tests that we allow bare \n and \r through, despite it being strictly + // not permitted per RFC 2045, Section 6.7 Page 22 bullet (4). + {in: "foo\nbar", want: "foo\nbar"}, + {in: "foo\rbar", want: "foo\rbar"}, + {in: "foo\r\nbar", want: "foo\r\nbar"}, + + // Different types of soft line-breaks. + {in: "foo=\r\nbar", want: "foobar"}, + {in: "foo=\nbar", want: "foobar"}, + {in: "foo=\rbar", want: "foo", err: "quotedprintable: invalid hex byte 0x0d"}, + {in: "foo=\r\r\r \nbar", want: "foo", err: `quotedprintable: invalid bytes after =: "\r\r\r \n"`}, + + // Example from RFC 2045: + {in: "Now's the time =\n" + "for all folk to come=\n" + " to the aid of their country.", + want: "Now's the time for all folk to come to the aid of their country."}, + } + for _, tt := range tests { + var buf bytes.Buffer + _, err := io.Copy(&buf, NewReader(strings.NewReader(tt.in))) + if got := buf.String(); got != tt.want { + t.Errorf("for %q, got %q; want %q", tt.in, got, tt.want) + } + switch verr := tt.err.(type) { + case nil: + if err != nil { + t.Errorf("for %q, got unexpected error: %v", tt.in, err) + } + case string: + if got := fmt.Sprint(err); got != verr { + t.Errorf("for %q, got error %q; want %q", tt.in, got, verr) + } + case error: + if err != verr { + t.Errorf("for %q, got error %q; want %q", tt.in, err, verr) + } + } + } + +} + +func everySequence(base, alpha string, length int, fn func(string)) { + if len(base) == length { + fn(base) + return + } + for i := 0; i < len(alpha); i++ { + everySequence(base+alpha[i:i+1], alpha, length, fn) + } +} + +var useQprint = flag.Bool("qprint", false, "Compare against the 'qprint' program.") + +var badSoftRx = regexp.MustCompile(`=([^\r\n]+?\n)|([^\r\n]+$)|(\r$)|(\r[^\n]+\n)|( \r\n)`) + +func TestExhaustive(t *testing.T) { + if *useQprint { + _, err := exec.LookPath("qprint") + if err != nil { + t.Fatalf("Error looking for qprint: %v", err) + } + } + + var buf bytes.Buffer + res := make(map[string]int) + everySequence("", "0A \r\n=", 6, func(s string) { + if strings.HasSuffix(s, "=") || strings.Contains(s, "==") { + return + } + buf.Reset() + _, err := io.Copy(&buf, NewReader(strings.NewReader(s))) + if err != nil { + errStr := err.Error() + if strings.Contains(errStr, "invalid bytes after =:") { + errStr = "invalid bytes after =" + } + res[errStr]++ + if strings.Contains(errStr, "invalid hex byte ") { + if strings.HasSuffix(errStr, "0x20") && (strings.Contains(s, "=0 ") || strings.Contains(s, "=A ") || strings.Contains(s, "= ")) { + return + } + if strings.HasSuffix(errStr, "0x3d") && (strings.Contains(s, "=0=") || strings.Contains(s, "=A=")) { + return + } + if strings.HasSuffix(errStr, "0x0a") || strings.HasSuffix(errStr, "0x0d") { + // bunch of cases; since whitespace at the end of a line before \n is removed. + return + } + } + if strings.Contains(errStr, "unexpected EOF") { + return + } + if errStr == "invalid bytes after =" && badSoftRx.MatchString(s) { + return + } + t.Errorf("decode(%q) = %v", s, err) + return + } + if *useQprint { + cmd := exec.Command("qprint", "-d") + cmd.Stdin = strings.NewReader(s) + stderr, err := cmd.StderrPipe() + if err != nil { + panic(err) + } + qpres := make(chan interface{}, 2) + go func() { + br := bufio.NewReader(stderr) + s, _ := br.ReadString('\n') + if s != "" { + qpres <- errors.New(s) + if cmd.Process != nil { + // It can get stuck on invalid input, like: + // echo -n "0000= " | qprint -d + cmd.Process.Kill() + } + } + }() + go func() { + want, err := cmd.Output() + if err == nil { + qpres <- want + } + }() + select { + case got := <-qpres: + if want, ok := got.([]byte); ok { + if string(want) != buf.String() { + t.Errorf("go decode(%q) = %q; qprint = %q", s, want, buf.String()) + } + } else { + t.Logf("qprint -d(%q) = %v", s, got) + } + case <-time.After(5 * time.Second): + t.Logf("qprint timeout on %q", s) + } + } + res["OK"]++ + }) + var outcomes []string + for k, v := range res { + outcomes = append(outcomes, fmt.Sprintf("%v: %d", k, v)) + } + sort.Strings(outcomes) + got := strings.Join(outcomes, "\n") + want := `OK: 21576 +invalid bytes after =: 3397 +quotedprintable: invalid hex byte 0x0a: 1400 +quotedprintable: invalid hex byte 0x0d: 2700 +quotedprintable: invalid hex byte 0x20: 2490 +quotedprintable: invalid hex byte 0x3d: 440 +unexpected EOF: 3122` + if got != want { + t.Errorf("Got:\n%s\nWant:\n%s", got, want) + } +} diff --git a/libgo/go/mime/quotedprintable/writer.go b/libgo/go/mime/quotedprintable/writer.go new file mode 100644 index 00000000000..16ea0bf7d62 --- /dev/null +++ b/libgo/go/mime/quotedprintable/writer.go @@ -0,0 +1,172 @@ +// Copyright 2015 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 quotedprintable + +import "io" + +const lineMaxLen = 76 + +// A Writer is a quoted-printable writer that implements io.WriteCloser. +type Writer struct { + // Binary mode treats the writer's input as pure binary and processes end of + // line bytes as binary data. + Binary bool + + w io.Writer + i int + line [78]byte + cr bool +} + +// NewWriter returns a new Writer that writes to w. +func NewWriter(w io.Writer) *Writer { + return &Writer{w: w} +} + +// Write encodes p using quoted-printable encoding and writes it to the +// underlying io.Writer. It limits line length to 76 characters. The encoded +// bytes are not necessarily flushed until the Writer is closed. +func (w *Writer) Write(p []byte) (n int, err error) { + for i, b := range p { + switch { + // Simple writes are done in batch. + case b >= '!' && b <= '~' && b != '=': + continue + case isWhitespace(b) || !w.Binary && (b == '\n' || b == '\r'): + continue + } + + if i > n { + if err := w.write(p[n:i]); err != nil { + return n, err + } + n = i + } + + if err := w.encode(b); err != nil { + return n, err + } + n++ + } + + if n == len(p) { + return n, nil + } + + if err := w.write(p[n:]); err != nil { + return n, err + } + + return len(p), nil +} + +// Close closes the Writer, flushing any unwritten data to the underlying +// io.Writer, but does not close the underlying io.Writer. +func (w *Writer) Close() error { + if err := w.checkLastByte(); err != nil { + return err + } + + return w.flush() +} + +// write limits text encoded in quoted-printable to 76 characters per line. +func (w *Writer) write(p []byte) error { + for _, b := range p { + if b == '\n' || b == '\r' { + // If the previous byte was \r, the CRLF has already been inserted. + if w.cr && b == '\n' { + w.cr = false + continue + } + + if b == '\r' { + w.cr = true + } + + if err := w.checkLastByte(); err != nil { + return err + } + if err := w.insertCRLF(); err != nil { + return err + } + continue + } + + if w.i == lineMaxLen-1 { + if err := w.insertSoftLineBreak(); err != nil { + return err + } + } + + w.line[w.i] = b + w.i++ + w.cr = false + } + + return nil +} + +func (w *Writer) encode(b byte) error { + if lineMaxLen-1-w.i < 3 { + if err := w.insertSoftLineBreak(); err != nil { + return err + } + } + + w.line[w.i] = '=' + w.line[w.i+1] = upperhex[b>>4] + w.line[w.i+2] = upperhex[b&0x0f] + w.i += 3 + + return nil +} + +const upperhex = "0123456789ABCDEF" + +// checkLastByte encodes the last buffered byte if it is a space or a tab. +func (w *Writer) checkLastByte() error { + if w.i == 0 { + return nil + } + + b := w.line[w.i-1] + if isWhitespace(b) { + w.i-- + if err := w.encode(b); err != nil { + return err + } + } + + return nil +} + +func (w *Writer) insertSoftLineBreak() error { + w.line[w.i] = '=' + w.i++ + + return w.insertCRLF() +} + +func (w *Writer) insertCRLF() error { + w.line[w.i] = '\r' + w.line[w.i+1] = '\n' + w.i += 2 + + return w.flush() +} + +func (w *Writer) flush() error { + if _, err := w.w.Write(w.line[:w.i]); err != nil { + return err + } + + w.i = 0 + return nil +} + +func isWhitespace(b byte) bool { + return b == ' ' || b == '\t' +} diff --git a/libgo/go/mime/quotedprintable/writer_test.go b/libgo/go/mime/quotedprintable/writer_test.go new file mode 100644 index 00000000000..a9b77b3f989 --- /dev/null +++ b/libgo/go/mime/quotedprintable/writer_test.go @@ -0,0 +1,158 @@ +// Copyright 2015 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 quotedprintable + +import ( + "bytes" + "io/ioutil" + "strings" + "testing" +) + +func TestWriter(t *testing.T) { + testWriter(t, false) +} + +func TestWriterBinary(t *testing.T) { + testWriter(t, true) +} + +func testWriter(t *testing.T, binary bool) { + tests := []struct { + in, want, wantB string + }{ + {in: "", want: ""}, + {in: "foo bar", want: "foo bar"}, + {in: "foo bar=", want: "foo bar=3D"}, + {in: "foo bar\r", want: "foo bar\r\n", wantB: "foo bar=0D"}, + {in: "foo bar\r\r", want: "foo bar\r\n\r\n", wantB: "foo bar=0D=0D"}, + {in: "foo bar\n", want: "foo bar\r\n", wantB: "foo bar=0A"}, + {in: "foo bar\r\n", want: "foo bar\r\n", wantB: "foo bar=0D=0A"}, + {in: "foo bar\r\r\n", want: "foo bar\r\n\r\n", wantB: "foo bar=0D=0D=0A"}, + {in: "foo bar ", want: "foo bar=20"}, + {in: "foo bar\t", want: "foo bar=09"}, + {in: "foo bar ", want: "foo bar =20"}, + {in: "foo bar \n", want: "foo bar=20\r\n", wantB: "foo bar =0A"}, + {in: "foo bar \r", want: "foo bar=20\r\n", wantB: "foo bar =0D"}, + {in: "foo bar \r\n", want: "foo bar=20\r\n", wantB: "foo bar =0D=0A"}, + {in: "foo bar \n", want: "foo bar =20\r\n", wantB: "foo bar =0A"}, + {in: "foo bar \n ", want: "foo bar =20\r\n=20", wantB: "foo bar =0A=20"}, + {in: "¡Hola Señor!", want: "=C2=A1Hola Se=C3=B1or!"}, + { + in: "\t !\"#$%&'()*+,-./ :;<>?@[\\]^_`{|}~", + want: "\t !\"#$%&'()*+,-./ :;<>?@[\\]^_`{|}~", + }, + { + in: strings.Repeat("a", 75), + want: strings.Repeat("a", 75), + }, + { + in: strings.Repeat("a", 76), + want: strings.Repeat("a", 75) + "=\r\na", + }, + { + in: strings.Repeat("a", 72) + "=", + want: strings.Repeat("a", 72) + "=3D", + }, + { + in: strings.Repeat("a", 73) + "=", + want: strings.Repeat("a", 73) + "=\r\n=3D", + }, + { + in: strings.Repeat("a", 74) + "=", + want: strings.Repeat("a", 74) + "=\r\n=3D", + }, + { + in: strings.Repeat("a", 75) + "=", + want: strings.Repeat("a", 75) + "=\r\n=3D", + }, + { + in: strings.Repeat(" ", 73), + want: strings.Repeat(" ", 72) + "=20", + }, + { + in: strings.Repeat(" ", 74), + want: strings.Repeat(" ", 73) + "=\r\n=20", + }, + { + in: strings.Repeat(" ", 75), + want: strings.Repeat(" ", 74) + "=\r\n=20", + }, + { + in: strings.Repeat(" ", 76), + want: strings.Repeat(" ", 75) + "=\r\n=20", + }, + { + in: strings.Repeat(" ", 77), + want: strings.Repeat(" ", 75) + "=\r\n =20", + }, + } + + for _, tt := range tests { + buf := new(bytes.Buffer) + w := NewWriter(buf) + + want := tt.want + if binary { + w.Binary = true + if tt.wantB != "" { + want = tt.wantB + } + } + + if _, err := w.Write([]byte(tt.in)); err != nil { + t.Errorf("Write(%q): %v", tt.in, err) + continue + } + if err := w.Close(); err != nil { + t.Errorf("Close(): %v", err) + continue + } + got := buf.String() + if got != want { + t.Errorf("Write(%q), got:\n%q\nwant:\n%q", tt.in, got, want) + } + } +} + +func TestRoundTrip(t *testing.T) { + buf := new(bytes.Buffer) + w := NewWriter(buf) + if _, err := w.Write(testMsg); err != nil { + t.Fatalf("Write: %v", err) + } + if err := w.Close(); err != nil { + t.Fatalf("Close: %v", err) + } + + r := NewReader(buf) + gotBytes, err := ioutil.ReadAll(r) + if err != nil { + t.Fatalf("Error while reading from Reader: %v", err) + } + got := string(gotBytes) + if got != string(testMsg) { + t.Errorf("Encoding and decoding changed the message, got:\n%s", got) + } +} + +// From http://fr.wikipedia.org/wiki/Quoted-Printable +var testMsg = []byte("Quoted-Printable (QP) est un format d'encodage de données codées sur 8 bits, qui utilise exclusivement les caractères alphanumériques imprimables du code ASCII (7 bits).\r\n" + + "\r\n" + + "En effet, les différents codages comprennent de nombreux caractères qui ne sont pas représentables en ASCII (par exemple les caractères accentués), ainsi que des caractères dits « non-imprimables ».\r\n" + + "\r\n" + + "L'encodage Quoted-Printable permet de remédier à ce problème, en procédant de la manière suivante :\r\n" + + "\r\n" + + "Un octet correspondant à un caractère imprimable de l'ASCII sauf le signe égal (donc un caractère de code ASCII entre 33 et 60 ou entre 62 et 126) ou aux caractères de saut de ligne (codes ASCII 13 et 10) ou une suite de tabulations et espaces non situées en fin de ligne (de codes ASCII respectifs 9 et 32) est représenté tel quel.\r\n" + + "Un octet qui ne correspond pas à la définition ci-dessus (caractère non imprimable de l'ASCII, tabulation ou espaces non suivies d'un caractère imprimable avant la fin de la ligne ou signe égal) est représenté par un signe égal, suivi de son numéro, exprimé en hexadécimal.\r\n" + + "Enfin, un signe égal suivi par un saut de ligne (donc la suite des trois caractères de codes ASCII 61, 13 et 10) peut être inséré n'importe où, afin de limiter la taille des lignes produites si nécessaire. Une limite de 76 caractères par ligne est généralement respectée.\r\n") + +func BenchmarkWriter(b *testing.B) { + for i := 0; i < b.N; i++ { + w := NewWriter(ioutil.Discard) + w.Write(testMsg) + w.Close() + } +} diff --git a/libgo/go/mime/type.go b/libgo/go/mime/type.go index ffda1f0ce5f..d369259d8b1 100644 --- a/libgo/go/mime/type.go +++ b/libgo/go/mime/type.go @@ -12,34 +12,75 @@ import ( ) var ( - mimeLock sync.RWMutex - mimeTypesLower = map[string]string{ - ".css": "text/css; charset=utf-8", - ".gif": "image/gif", - ".htm": "text/html; charset=utf-8", - ".html": "text/html; charset=utf-8", - ".jpg": "image/jpeg", - ".js": "application/x-javascript", - ".pdf": "application/pdf", - ".png": "image/png", - ".xml": "text/xml; charset=utf-8", - } - mimeTypes = clone(mimeTypesLower) + mimeLock sync.RWMutex // guards following 3 maps + mimeTypes map[string]string // ".Z" => "application/x-compress" + mimeTypesLower map[string]string // ".z" => "application/x-compress" + + // extensions maps from MIME type to list of lowercase file + // extensions: "image/jpeg" => [".jpg", ".jpeg"] + extensions map[string][]string ) +// setMimeTypes is used by initMime's non-test path, and by tests. +// The two maps must not be the same, or nil. +func setMimeTypes(lowerExt, mixExt map[string]string) { + if lowerExt == nil || mixExt == nil { + panic("nil map") + } + mimeTypesLower = lowerExt + mimeTypes = mixExt + extensions = invert(lowerExt) +} + +var builtinTypesLower = map[string]string{ + ".css": "text/css; charset=utf-8", + ".gif": "image/gif", + ".htm": "text/html; charset=utf-8", + ".html": "text/html; charset=utf-8", + ".jpg": "image/jpeg", + ".js": "application/x-javascript", + ".pdf": "application/pdf", + ".png": "image/png", + ".svg": "image/svg+xml", + ".xml": "text/xml; charset=utf-8", +} + func clone(m map[string]string) map[string]string { m2 := make(map[string]string, len(m)) for k, v := range m { m2[k] = v if strings.ToLower(k) != k { - panic("keys in mimeTypesLower must be lowercase") + panic("keys in builtinTypesLower must be lowercase") } } return m2 } +func invert(m map[string]string) map[string][]string { + m2 := make(map[string][]string, len(m)) + for k, v := range m { + justType, _, err := ParseMediaType(v) + if err != nil { + panic(err) + } + m2[justType] = append(m2[justType], k) + } + return m2 +} + var once sync.Once // guards initMime +var testInitMime, osInitMime func() + +func initMime() { + if fn := testInitMime; fn != nil { + fn() + } else { + setMimeTypes(builtinTypesLower, clone(builtinTypesLower)) + osInitMime() + } +} + // TypeByExtension returns the MIME type associated with the file extension ext. // The extension ext should begin with a leading dot, as in ".html". // When ext has no associated type, TypeByExtension returns "". @@ -63,8 +104,7 @@ func TypeByExtension(ext string) string { defer mimeLock.RUnlock() // Case-sensitive lookup. - v := mimeTypes[ext] - if v != "" { + if v := mimeTypes[ext]; v != "" { return v } @@ -91,19 +131,39 @@ func TypeByExtension(ext string) string { return mimeTypesLower[string(lower)] } +// ExtensionsByType returns the extensions known to be associated with the MIME +// type typ. The returned extensions will each begin with a leading dot, as in +// ".html". When typ has no associated extensions, ExtensionsByType returns an +// nil slice. +func ExtensionsByType(typ string) ([]string, error) { + justType, _, err := ParseMediaType(typ) + if err != nil { + return nil, err + } + + once.Do(initMime) + mimeLock.RLock() + defer mimeLock.RUnlock() + s, ok := extensions[justType] + if !ok { + return nil, nil + } + return append([]string{}, s...), nil +} + // AddExtensionType sets the MIME type associated with // the extension ext to typ. The extension should begin with // a leading dot, as in ".html". func AddExtensionType(ext, typ string) error { if !strings.HasPrefix(ext, ".") { - return fmt.Errorf(`mime: extension %q misses dot`, ext) + return fmt.Errorf("mime: extension %q missing leading dot", ext) } once.Do(initMime) return setExtensionType(ext, typ) } func setExtensionType(extension, mimeType string) error { - _, param, err := ParseMediaType(mimeType) + justType, param, err := ParseMediaType(mimeType) if err != nil { return err } @@ -114,8 +174,14 @@ func setExtensionType(extension, mimeType string) error { extLower := strings.ToLower(extension) mimeLock.Lock() + defer mimeLock.Unlock() mimeTypes[extension] = mimeType mimeTypesLower[extLower] = mimeType - mimeLock.Unlock() + for _, v := range extensions[justType] { + if v == extLower { + return nil + } + } + extensions[justType] = append(extensions[justType], extLower) return nil } diff --git a/libgo/go/mime/type_dragonfly.go b/libgo/go/mime/type_dragonfly.go new file mode 100644 index 00000000000..d09d74a9cce --- /dev/null +++ b/libgo/go/mime/type_dragonfly.go @@ -0,0 +1,9 @@ +// Copyright 2015 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 mime + +func init() { + typeFiles = append(typeFiles, "/usr/local/etc/mime.types") +} diff --git a/libgo/go/mime/type_freebsd.go b/libgo/go/mime/type_freebsd.go new file mode 100644 index 00000000000..d09d74a9cce --- /dev/null +++ b/libgo/go/mime/type_freebsd.go @@ -0,0 +1,9 @@ +// Copyright 2015 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 mime + +func init() { + typeFiles = append(typeFiles, "/usr/local/etc/mime.types") +} diff --git a/libgo/go/mime/type_openbsd.go b/libgo/go/mime/type_openbsd.go new file mode 100644 index 00000000000..c3b1abb99fc --- /dev/null +++ b/libgo/go/mime/type_openbsd.go @@ -0,0 +1,9 @@ +// Copyright 2015 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 mime + +func init() { + typeFiles = append(typeFiles, "/usr/share/misc/mime.types") +} diff --git a/libgo/go/mime/type_plan9.go b/libgo/go/mime/type_plan9.go index 8cbf6777f19..c3ba186e7c6 100644 --- a/libgo/go/mime/type_plan9.go +++ b/libgo/go/mime/type_plan9.go @@ -10,10 +10,29 @@ import ( "strings" ) +func init() { + osInitMime = initMimePlan9 +} + +func initMimePlan9() { + for _, filename := range typeFiles { + loadMimeFile(filename) + } +} + var typeFiles = []string{ "/sys/lib/mimetypes", } +func initMimeForTests() map[string]string { + typeFiles = []string{"testdata/test.types.plan9"} + return map[string]string{ + ".t1": "application/test", + ".t2": "text/test; charset=utf-8", + ".pNg": "image/png", + } +} + func loadMimeFile(filename string) { f, err := os.Open(filename) if err != nil { @@ -36,18 +55,3 @@ func loadMimeFile(filename string) { panic(err) } } - -func initMime() { - for _, filename := range typeFiles { - loadMimeFile(filename) - } -} - -func initMimeForTests() map[string]string { - typeFiles = []string{"testdata/test.types.plan9"} - return map[string]string{ - ".t1": "application/test", - ".t2": "text/test; charset=utf-8", - ".pNg": "image/png", - } -} diff --git a/libgo/go/mime/type_test.go b/libgo/go/mime/type_test.go index e4ec25450ce..48735ef4470 100644 --- a/libgo/go/mime/type_test.go +++ b/libgo/go/mime/type_test.go @@ -5,12 +5,41 @@ package mime import ( + "reflect" + "strings" + "sync" "testing" ) -var typeTests = initMimeForTests() +func setMimeInit(fn func()) (cleanup func()) { + once = sync.Once{} + testInitMime = fn + return func() { testInitMime = nil } +} + +func clearMimeTypes() { + setMimeTypes(map[string]string{}, map[string]string{}) +} + +func setType(ext, typ string) { + if !strings.HasPrefix(ext, ".") { + panic("missing leading dot") + } + if err := setExtensionType(ext, typ); err != nil { + panic("bad test data: " + err.Error()) + } +} func TestTypeByExtension(t *testing.T) { + once = sync.Once{} + // initMimeForTests returns the platform-specific extension => + // type tests. On Unix and Plan 9, this also tests the parsing + // of MIME text files (in testdata/*). On Windows, we test the + // real registry on the machine and assume that ".png" exists + // there, which empirically it always has, for all versions of + // Windows. + typeTests := initMimeForTests() + for ext, want := range typeTests { val := TypeByExtension(ext) if val != want { @@ -19,15 +48,41 @@ func TestTypeByExtension(t *testing.T) { } } +func TestTypeByExtension_LocalData(t *testing.T) { + cleanup := setMimeInit(func() { + clearMimeTypes() + setType(".foo", "x/foo") + setType(".bar", "x/bar") + setType(".Bar", "x/bar; capital=1") + }) + defer cleanup() + + tests := map[string]string{ + ".foo": "x/foo", + ".bar": "x/bar", + ".Bar": "x/bar; capital=1", + ".sdlkfjskdlfj": "", + ".t1": "", // testdata shouldn't be used + } + + for ext, want := range tests { + val := TypeByExtension(ext) + if val != want { + t.Errorf("TypeByExtension(%q) = %q, want %q", ext, val, want) + } + } +} + func TestTypeByExtensionCase(t *testing.T) { const custom = "test/test; charset=iso-8859-1" const caps = "test/test; WAS=ALLCAPS" - if err := AddExtensionType(".TEST", caps); err != nil { - t.Fatalf("error %s for AddExtension(%s)", err, custom) - } - if err := AddExtensionType(".tesT", custom); err != nil { - t.Fatalf("error %s for AddExtension(%s)", err, custom) - } + + cleanup := setMimeInit(func() { + clearMimeTypes() + setType(".TEST", caps) + setType(".tesT", custom) + }) + defer cleanup() // case-sensitive lookup if got := TypeByExtension(".tesT"); got != custom { @@ -43,13 +98,54 @@ func TestTypeByExtensionCase(t *testing.T) { } } +func TestExtensionsByType(t *testing.T) { + cleanup := setMimeInit(func() { + clearMimeTypes() + setType(".gif", "image/gif") + setType(".a", "foo/letter") + setType(".b", "foo/letter") + setType(".B", "foo/letter") + setType(".PNG", "image/png") + }) + defer cleanup() + + tests := []struct { + typ string + want []string + wantErr string + }{ + {typ: "image/gif", want: []string{".gif"}}, + {typ: "image/png", want: []string{".png"}}, // lowercase + {typ: "foo/letter", want: []string{".a", ".b"}}, + {typ: "x/unknown", want: nil}, + } + + for _, tt := range tests { + got, err := ExtensionsByType(tt.typ) + if err != nil && tt.wantErr != "" && strings.Contains(err.Error(), tt.wantErr) { + continue + } + if err != nil { + t.Errorf("ExtensionsByType(%q) error: %v", tt.typ, err) + continue + } + if tt.wantErr != "" { + t.Errorf("ExtensionsByType(%q) = %q, %v; want error substring %q", tt.typ, got, err, tt.wantErr) + continue + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("ExtensionsByType(%q) = %q; want %q", tt.typ, got, tt.want) + } + } +} + func TestLookupMallocs(t *testing.T) { + t.Skip("skipping test on gccgo until it has better escape analysis") n := testing.AllocsPerRun(10000, func() { TypeByExtension(".html") TypeByExtension(".HtML") }) - // Changed from 0 to 1 for gccgo, pending escape analysis. - if n > 1 { + if n > 0 { t.Errorf("allocs = %v; want 0", n) } } diff --git a/libgo/go/mime/type_unix.go b/libgo/go/mime/type_unix.go index 3e404cf7429..bb06a77c458 100644 --- a/libgo/go/mime/type_unix.go +++ b/libgo/go/mime/type_unix.go @@ -12,6 +12,10 @@ import ( "strings" ) +func init() { + osInitMime = initMimeUnix +} + var typeFiles = []string{ "/etc/mime.types", "/etc/apache2/mime.types", @@ -44,7 +48,7 @@ func loadMimeFile(filename string) { } } -func initMime() { +func initMimeUnix() { for _, filename := range typeFiles { loadMimeFile(filename) } diff --git a/libgo/go/mime/type_windows.go b/libgo/go/mime/type_windows.go index ae758d78b31..97b9aeba7a3 100644 --- a/libgo/go/mime/type_windows.go +++ b/libgo/go/mime/type_windows.go @@ -5,54 +5,32 @@ package mime import ( - "syscall" - "unsafe" + "internal/syscall/windows/registry" ) -func initMime() { - var root syscall.Handle - rootpathp, _ := syscall.UTF16PtrFromString(`\`) - if syscall.RegOpenKeyEx(syscall.HKEY_CLASSES_ROOT, rootpathp, - 0, syscall.KEY_READ, &root) != nil { - return - } - defer syscall.RegCloseKey(root) - var count uint32 - if syscall.RegQueryInfoKey(root, nil, nil, nil, &count, nil, nil, nil, nil, nil, nil, nil) != nil { +func init() { + osInitMime = initMimeWindows +} + +func initMimeWindows() { + names, err := registry.CLASSES_ROOT.ReadSubKeyNames(-1) + if err != nil { return } - var buf [1 << 10]uint16 - for i := uint32(0); i < count; i++ { - n := uint32(len(buf)) - if syscall.RegEnumKeyEx(root, i, &buf[0], &n, nil, nil, nil, nil) != nil { - continue - } - ext := syscall.UTF16ToString(buf[:]) - if len(ext) < 2 || ext[0] != '.' { // looking for extensions only - continue - } - var h syscall.Handle - extpathp, _ := syscall.UTF16PtrFromString(`\` + ext) - if syscall.RegOpenKeyEx( - syscall.HKEY_CLASSES_ROOT, extpathp, - 0, syscall.KEY_READ, &h) != nil { + for _, name := range names { + if len(name) < 2 || name[0] != '.' { // looking for extensions only continue } - var typ uint32 - n = uint32(len(buf) * 2) // api expects array of bytes, not uint16 - contenttypep, _ := syscall.UTF16PtrFromString("Content Type") - if syscall.RegQueryValueEx( - h, contenttypep, - nil, &typ, (*byte)(unsafe.Pointer(&buf[0])), &n) != nil { - syscall.RegCloseKey(h) + k, err := registry.OpenKey(registry.CLASSES_ROOT, name, registry.READ) + if err != nil { continue } - syscall.RegCloseKey(h) - if typ != syscall.REG_SZ { // null terminated strings only + v, _, err := k.GetStringValue("Content Type") + k.Close() + if err != nil { continue } - mimeType := syscall.UTF16ToString(buf[:]) - setExtensionType(ext, mimeType) + setExtensionType(name, v) } } diff --git a/libgo/go/net/addrselect.go b/libgo/go/net/addrselect.go new file mode 100644 index 00000000000..e22fbac5cee --- /dev/null +++ b/libgo/go/net/addrselect.go @@ -0,0 +1,388 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd linux netbsd openbsd solaris + +// Minimal RFC 6724 address selection. + +package net + +import "sort" + +func sortByRFC6724(addrs []IPAddr) { + if len(addrs) < 2 { + return + } + sortByRFC6724withSrcs(addrs, srcAddrs(addrs)) +} + +func sortByRFC6724withSrcs(addrs []IPAddr, srcs []IP) { + if len(addrs) != len(srcs) { + panic("internal error") + } + addrAttr := make([]ipAttr, len(addrs)) + srcAttr := make([]ipAttr, len(srcs)) + for i, v := range addrs { + addrAttr[i] = ipAttrOf(v.IP) + srcAttr[i] = ipAttrOf(srcs[i]) + } + sort.Stable(&byRFC6724{ + addrs: addrs, + addrAttr: addrAttr, + srcs: srcs, + srcAttr: srcAttr, + }) +} + +// srcsAddrs tries to UDP-connect to each address to see if it has a +// route. (This doesn't send any packets). The destination port +// number is irrelevant. +func srcAddrs(addrs []IPAddr) []IP { + srcs := make([]IP, len(addrs)) + dst := UDPAddr{Port: 9} + for i := range addrs { + dst.IP = addrs[i].IP + dst.Zone = addrs[i].Zone + c, err := DialUDP("udp", nil, &dst) + if err == nil { + if src, ok := c.LocalAddr().(*UDPAddr); ok { + srcs[i] = src.IP + } + c.Close() + } + } + return srcs +} + +type ipAttr struct { + Scope scope + Precedence uint8 + Label uint8 +} + +func ipAttrOf(ip IP) ipAttr { + if ip == nil { + return ipAttr{} + } + match := rfc6724policyTable.Classify(ip) + return ipAttr{ + Scope: classifyScope(ip), + Precedence: match.Precedence, + Label: match.Label, + } +} + +type byRFC6724 struct { + addrs []IPAddr // addrs to sort + addrAttr []ipAttr + srcs []IP // or nil if unreachable + srcAttr []ipAttr +} + +func (s *byRFC6724) Len() int { return len(s.addrs) } + +func (s *byRFC6724) Swap(i, j int) { + s.addrs[i], s.addrs[j] = s.addrs[j], s.addrs[i] + s.srcs[i], s.srcs[j] = s.srcs[j], s.srcs[i] + s.addrAttr[i], s.addrAttr[j] = s.addrAttr[j], s.addrAttr[i] + s.srcAttr[i], s.srcAttr[j] = s.srcAttr[j], s.srcAttr[i] +} + +// Less reports whether i is a better destination address for this +// host than j. +// +// The algorithm and variable names comes from RFC 6724 section 6. +func (s *byRFC6724) Less(i, j int) bool { + DA := s.addrs[i].IP + DB := s.addrs[j].IP + SourceDA := s.srcs[i] + SourceDB := s.srcs[j] + attrDA := &s.addrAttr[i] + attrDB := &s.addrAttr[j] + attrSourceDA := &s.srcAttr[i] + attrSourceDB := &s.srcAttr[j] + + const preferDA = true + const preferDB = false + + // Rule 1: Avoid unusable destinations. + // If DB is known to be unreachable or if Source(DB) is undefined, then + // prefer DA. Similarly, if DA is known to be unreachable or if + // Source(DA) is undefined, then prefer DB. + if SourceDA == nil && SourceDB == nil { + return false // "equal" + } + if SourceDB == nil { + return preferDA + } + if SourceDA == nil { + return preferDB + } + + // Rule 2: Prefer matching scope. + // If Scope(DA) = Scope(Source(DA)) and Scope(DB) <> Scope(Source(DB)), + // then prefer DA. Similarly, if Scope(DA) <> Scope(Source(DA)) and + // Scope(DB) = Scope(Source(DB)), then prefer DB. + if attrDA.Scope == attrSourceDA.Scope && attrDB.Scope != attrSourceDB.Scope { + return preferDA + } + if attrDA.Scope != attrSourceDA.Scope && attrDB.Scope == attrSourceDB.Scope { + return preferDB + } + + // Rule 3: Avoid deprecated addresses. + // If Source(DA) is deprecated and Source(DB) is not, then prefer DB. + // Similarly, if Source(DA) is not deprecated and Source(DB) is + // deprecated, then prefer DA. + + // TODO(bradfitz): implement? low priority for now. + + // Rule 4: Prefer home addresses. + // If Source(DA) is simultaneously a home address and care-of address + // and Source(DB) is not, then prefer DA. Similarly, if Source(DB) is + // simultaneously a home address and care-of address and Source(DA) is + // not, then prefer DB. + + // TODO(bradfitz): implement? low priority for now. + + // Rule 5: Prefer matching label. + // If Label(Source(DA)) = Label(DA) and Label(Source(DB)) <> Label(DB), + // then prefer DA. Similarly, if Label(Source(DA)) <> Label(DA) and + // Label(Source(DB)) = Label(DB), then prefer DB. + if attrSourceDA.Label == attrDA.Label && + attrSourceDB.Label != attrDB.Label { + return preferDA + } + if attrSourceDA.Label != attrDA.Label && + attrSourceDB.Label == attrDB.Label { + return preferDB + } + + // Rule 6: Prefer higher precedence. + // If Precedence(DA) > Precedence(DB), then prefer DA. Similarly, if + // Precedence(DA) < Precedence(DB), then prefer DB. + if attrDA.Precedence > attrDB.Precedence { + return preferDA + } + if attrDA.Precedence < attrDB.Precedence { + return preferDB + } + + // Rule 7: Prefer native transport. + // If DA is reached via an encapsulating transition mechanism (e.g., + // IPv6 in IPv4) and DB is not, then prefer DB. Similarly, if DB is + // reached via encapsulation and DA is not, then prefer DA. + + // TODO(bradfitz): implement? low priority for now. + + // Rule 8: Prefer smaller scope. + // If Scope(DA) < Scope(DB), then prefer DA. Similarly, if Scope(DA) > + // Scope(DB), then prefer DB. + if attrDA.Scope < attrDB.Scope { + return preferDA + } + if attrDA.Scope > attrDB.Scope { + return preferDB + } + + // Rule 9: Use longest matching prefix. + // When DA and DB belong to the same address family (both are IPv6 or + // both are IPv4): If CommonPrefixLen(Source(DA), DA) > + // CommonPrefixLen(Source(DB), DB), then prefer DA. Similarly, if + // CommonPrefixLen(Source(DA), DA) < CommonPrefixLen(Source(DB), DB), + // then prefer DB. + da4 := DA.To4() != nil + db4 := DB.To4() != nil + if da4 == db4 { + commonA := commonPrefixLen(SourceDA, DA) + commonB := commonPrefixLen(SourceDB, DB) + if commonA > commonB { + return preferDA + } + if commonA < commonB { + return preferDB + } + } + + // Rule 10: Otherwise, leave the order unchanged. + // If DA preceded DB in the original list, prefer DA. + // Otherwise, prefer DB. + return false // "equal" +} + +type policyTableEntry struct { + Prefix *IPNet + Precedence uint8 + Label uint8 +} + +type policyTable []policyTableEntry + +// RFC 6724 section 2.1. +var rfc6724policyTable = policyTable{ + { + Prefix: mustCIDR("::1/128"), + Precedence: 50, + Label: 0, + }, + { + Prefix: mustCIDR("::/0"), + Precedence: 40, + Label: 1, + }, + { + // IPv4-compatible, etc. + Prefix: mustCIDR("::ffff:0:0/96"), + Precedence: 35, + Label: 4, + }, + { + // 6to4 + Prefix: mustCIDR("2002::/16"), + Precedence: 30, + Label: 2, + }, + { + // Teredo + Prefix: mustCIDR("2001::/32"), + Precedence: 5, + Label: 5, + }, + { + Prefix: mustCIDR("fc00::/7"), + Precedence: 3, + Label: 13, + }, + { + Prefix: mustCIDR("::/96"), + Precedence: 1, + Label: 3, + }, + { + Prefix: mustCIDR("fec0::/10"), + Precedence: 1, + Label: 11, + }, + { + Prefix: mustCIDR("3ffe::/16"), + Precedence: 1, + Label: 12, + }, +} + +func init() { + sort.Sort(sort.Reverse(byMaskLength(rfc6724policyTable))) +} + +// byMaskLength sorts policyTableEntry by the size of their Prefix.Mask.Size, +// from smallest mask, to largest. +type byMaskLength []policyTableEntry + +func (s byMaskLength) Len() int { return len(s) } +func (s byMaskLength) Swap(i, j int) { s[i], s[j] = s[j], s[i] } +func (s byMaskLength) Less(i, j int) bool { + isize, _ := s[i].Prefix.Mask.Size() + jsize, _ := s[j].Prefix.Mask.Size() + return isize < jsize +} + +// mustCIDR calls ParseCIDR and panics on any error, or if the network +// is not IPv6. +func mustCIDR(s string) *IPNet { + ip, ipNet, err := ParseCIDR(s) + if err != nil { + panic(err.Error()) + } + if len(ip) != IPv6len { + panic("unexpected IP length") + } + return ipNet +} + +// Classify returns the policyTableEntry of the entry with the longest +// matching prefix that contains ip. +// The table t must be sorted from largest mask size to smallest. +func (t policyTable) Classify(ip IP) policyTableEntry { + for _, ent := range t { + if ent.Prefix.Contains(ip) { + return ent + } + } + return policyTableEntry{} +} + +// RFC 6724 section 3.1. +type scope uint8 + +const ( + scopeInterfaceLocal scope = 0x1 + scopeLinkLocal scope = 0x2 + scopeAdminLocal scope = 0x4 + scopeSiteLocal scope = 0x5 + scopeOrgLocal scope = 0x8 + scopeGlobal scope = 0xe +) + +func classifyScope(ip IP) scope { + if ip.IsLoopback() || ip.IsLinkLocalUnicast() { + return scopeLinkLocal + } + ipv6 := len(ip) == IPv6len && ip.To4() == nil + if ipv6 && ip.IsMulticast() { + return scope(ip[1] & 0xf) + } + // Site-local addresses are defined in RFC 3513 section 2.5.6 + // (and deprecated in RFC 3879). + if ipv6 && ip[0] == 0xfe && ip[1]&0xc0 == 0xc0 { + return scopeSiteLocal + } + return scopeGlobal +} + +// commonPrefixLen reports the length of the longest prefix (looking +// at the most significant, or leftmost, bits) that the +// two addresses have in common, up to the length of a's prefix (i.e., +// the portion of the address not including the interface ID). +// +// If a or b is an IPv4 address as an IPv6 address, the IPv4 addresses +// are compared (with max common prefix length of 32). +// If a and b are different IP versions, 0 is returned. +// +// See https://tools.ietf.org/html/rfc6724#section-2.2 +func commonPrefixLen(a, b IP) (cpl int) { + if a4 := a.To4(); a4 != nil { + a = a4 + } + if b4 := b.To4(); b4 != nil { + b = b4 + } + if len(a) != len(b) { + return 0 + } + // If IPv6, only up to the prefix (first 64 bits) + if len(a) > 8 { + a = a[:8] + b = b[:8] + } + for len(a) > 0 { + if a[0] == b[0] { + cpl += 8 + a = a[1:] + b = b[1:] + continue + } + bits := 8 + ab, bb := a[0], b[0] + for { + ab >>= 1 + bb >>= 1 + bits-- + if ab == bb { + cpl += bits + return + } + } + } + return +} diff --git a/libgo/go/net/addrselect_test.go b/libgo/go/net/addrselect_test.go new file mode 100644 index 00000000000..562022772fa --- /dev/null +++ b/libgo/go/net/addrselect_test.go @@ -0,0 +1,219 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd linux netbsd openbsd solaris + +package net + +import ( + "reflect" + "testing" +) + +func TestSortByRFC6724(t *testing.T) { + tests := []struct { + in []IPAddr + srcs []IP + want []IPAddr + reverse bool // also test it starting backwards + }{ + // Examples from RFC 6724 section 10.2: + + // Prefer matching scope. + { + in: []IPAddr{ + {IP: ParseIP("2001:db8:1::1")}, + {IP: ParseIP("198.51.100.121")}, + }, + srcs: []IP{ + ParseIP("2001:db8:1::2"), + ParseIP("169.254.13.78"), + }, + want: []IPAddr{ + {IP: ParseIP("2001:db8:1::1")}, + {IP: ParseIP("198.51.100.121")}, + }, + reverse: true, + }, + + // Prefer matching scope. + { + in: []IPAddr{ + {IP: ParseIP("2001:db8:1::1")}, + {IP: ParseIP("198.51.100.121")}, + }, + srcs: []IP{ + ParseIP("fe80::1"), + ParseIP("198.51.100.117"), + }, + want: []IPAddr{ + {IP: ParseIP("198.51.100.121")}, + {IP: ParseIP("2001:db8:1::1")}, + }, + reverse: true, + }, + + // Prefer higher precedence. + { + in: []IPAddr{ + {IP: ParseIP("2001:db8:1::1")}, + {IP: ParseIP("10.1.2.3")}, + }, + srcs: []IP{ + ParseIP("2001:db8:1::2"), + ParseIP("10.1.2.4"), + }, + want: []IPAddr{ + {IP: ParseIP("2001:db8:1::1")}, + {IP: ParseIP("10.1.2.3")}, + }, + reverse: true, + }, + + // Prefer smaller scope. + { + in: []IPAddr{ + {IP: ParseIP("2001:db8:1::1")}, + {IP: ParseIP("fe80::1")}, + }, + srcs: []IP{ + ParseIP("2001:db8:1::2"), + ParseIP("fe80::2"), + }, + want: []IPAddr{ + {IP: ParseIP("fe80::1")}, + {IP: ParseIP("2001:db8:1::1")}, + }, + reverse: true, + }, + } + for i, tt := range tests { + inCopy := make([]IPAddr, len(tt.in)) + copy(inCopy, tt.in) + srcCopy := make([]IP, len(tt.in)) + copy(srcCopy, tt.srcs) + sortByRFC6724withSrcs(inCopy, srcCopy) + if !reflect.DeepEqual(inCopy, tt.want) { + t.Errorf("test %d:\nin = %s\ngot: %s\nwant: %s\n", i, tt.in, inCopy, tt.want) + } + if tt.reverse { + copy(inCopy, tt.in) + copy(srcCopy, tt.srcs) + for j := 0; j < len(inCopy)/2; j++ { + k := len(inCopy) - j - 1 + inCopy[j], inCopy[k] = inCopy[k], inCopy[j] + srcCopy[j], srcCopy[k] = srcCopy[k], srcCopy[j] + } + sortByRFC6724withSrcs(inCopy, srcCopy) + if !reflect.DeepEqual(inCopy, tt.want) { + t.Errorf("test %d, starting backwards:\nin = %s\ngot: %s\nwant: %s\n", i, tt.in, inCopy, tt.want) + } + } + + } + +} + +func TestRFC6724PolicyTableClassify(t *testing.T) { + tests := []struct { + ip IP + want policyTableEntry + }{ + { + ip: ParseIP("127.0.0.1"), + want: policyTableEntry{ + Prefix: &IPNet{IP: ParseIP("::ffff:0:0"), Mask: CIDRMask(96, 128)}, + Precedence: 35, + Label: 4, + }, + }, + { + ip: ParseIP("2601:645:8002:a500:986f:1db8:c836:bd65"), + want: policyTableEntry{ + Prefix: &IPNet{IP: ParseIP("::"), Mask: CIDRMask(0, 128)}, + Precedence: 40, + Label: 1, + }, + }, + { + ip: ParseIP("::1"), + want: policyTableEntry{ + Prefix: &IPNet{IP: ParseIP("::1"), Mask: CIDRMask(128, 128)}, + Precedence: 50, + Label: 0, + }, + }, + { + ip: ParseIP("2002::ab12"), + want: policyTableEntry{ + Prefix: &IPNet{IP: ParseIP("2002::"), Mask: CIDRMask(16, 128)}, + Precedence: 30, + Label: 2, + }, + }, + } + for i, tt := range tests { + got := rfc6724policyTable.Classify(tt.ip) + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("%d. Classify(%s) = %v; want %v", i, tt.ip, got, tt.want) + } + } +} + +func TestRFC6724ClassifyScope(t *testing.T) { + tests := []struct { + ip IP + want scope + }{ + {ParseIP("127.0.0.1"), scopeLinkLocal}, // rfc6724#section-3.2 + {ParseIP("::1"), scopeLinkLocal}, // rfc4007#section-4 + {ParseIP("169.254.1.2"), scopeLinkLocal}, // rfc6724#section-3.2 + {ParseIP("fec0::1"), scopeSiteLocal}, + {ParseIP("8.8.8.8"), scopeGlobal}, + + {ParseIP("ff02::"), scopeLinkLocal}, // IPv6 multicast + {ParseIP("ff05::"), scopeSiteLocal}, // IPv6 multicast + {ParseIP("ff04::"), scopeAdminLocal}, // IPv6 multicast + {ParseIP("ff0e::"), scopeGlobal}, // IPv6 multicast + + {IPv4(0xe0, 0, 0, 0), scopeGlobal}, // IPv4 link-local multicast as 16 bytes + {IPv4(0xe0, 2, 2, 2), scopeGlobal}, // IPv4 global multicast as 16 bytes + {IPv4(0xe0, 0, 0, 0).To4(), scopeGlobal}, // IPv4 link-local multicast as 4 bytes + {IPv4(0xe0, 2, 2, 2).To4(), scopeGlobal}, // IPv4 global multicast as 4 bytes + } + for i, tt := range tests { + got := classifyScope(tt.ip) + if got != tt.want { + t.Errorf("%d. classifyScope(%s) = %x; want %x", i, tt.ip, got, tt.want) + } + } +} + +func TestRFC6724CommonPrefixLength(t *testing.T) { + tests := []struct { + a, b IP + want int + }{ + {ParseIP("fe80::1"), ParseIP("fe80::2"), 64}, + {ParseIP("fe81::1"), ParseIP("fe80::2"), 15}, + {ParseIP("127.0.0.1"), ParseIP("fe80::1"), 0}, // diff size + {IPv4(1, 2, 3, 4), IP{1, 2, 3, 4}, 32}, + {IP{1, 2, 255, 255}, IP{1, 2, 0, 0}, 16}, + {IP{1, 2, 127, 255}, IP{1, 2, 0, 0}, 17}, + {IP{1, 2, 63, 255}, IP{1, 2, 0, 0}, 18}, + {IP{1, 2, 31, 255}, IP{1, 2, 0, 0}, 19}, + {IP{1, 2, 15, 255}, IP{1, 2, 0, 0}, 20}, + {IP{1, 2, 7, 255}, IP{1, 2, 0, 0}, 21}, + {IP{1, 2, 3, 255}, IP{1, 2, 0, 0}, 22}, + {IP{1, 2, 1, 255}, IP{1, 2, 0, 0}, 23}, + {IP{1, 2, 0, 255}, IP{1, 2, 0, 0}, 24}, + } + for i, tt := range tests { + got := commonPrefixLen(tt.a, tt.b) + if got != tt.want { + t.Errorf("%d. commonPrefixLen(%s, %s) = %d; want %d", i, tt.a, tt.b, got, tt.want) + } + } + +} diff --git a/libgo/go/net/cgo_android.go b/libgo/go/net/cgo_android.go index 3819ce56a4f..fe9925b840a 100644 --- a/libgo/go/net/cgo_android.go +++ b/libgo/go/net/cgo_android.go @@ -9,6 +9,4 @@ package net //#include import "C" -func cgoAddrInfoFlags() C.int { - return C.AI_CANONNAME -} +const cgoAddrInfoFlags = C.AI_CANONNAME diff --git a/libgo/go/net/cgo_bsd.go b/libgo/go/net/cgo_bsd.go index ce46f2e8c3a..ae1054b39ad 100644 --- a/libgo/go/net/cgo_bsd.go +++ b/libgo/go/net/cgo_bsd.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !netgo -// +build darwin dragonfly freebsd solaris +// +build cgo,!netgo +// +build darwin dragonfly freebsd package net @@ -13,6 +13,4 @@ package net import "syscall" -func cgoAddrInfoFlags() int { - return (syscall.AI_CANONNAME | syscall.AI_V4MAPPED | syscall.AI_ALL) & syscall.AI_MASK -} +const cgoAddrInfoFlags = (syscall.AI_CANONNAME | syscall.AI_V4MAPPED | syscall.AI_ALL) & syscall.AI_MASK diff --git a/libgo/go/net/cgo_linux.go b/libgo/go/net/cgo_linux.go index 0e332261acc..baf207257fa 100644 --- a/libgo/go/net/cgo_linux.go +++ b/libgo/go/net/cgo_linux.go @@ -12,12 +12,10 @@ package net import "syscall" -func cgoAddrInfoFlags() int { - // NOTE(rsc): In theory there are approximately balanced - // arguments for and against including AI_ADDRCONFIG - // in the flags (it includes IPv4 results only on IPv4 systems, - // and similarly for IPv6), but in practice setting it causes - // getaddrinfo to return the wrong canonical name on Linux. - // So definitely leave it out. - return syscall.AI_CANONNAME | syscall.AI_V4MAPPED | syscall.AI_ALL -} +// NOTE(rsc): In theory there are approximately balanced +// arguments for and against including AI_ADDRCONFIG +// in the flags (it includes IPv4 results only on IPv4 systems, +// and similarly for IPv6), but in practice setting it causes +// getaddrinfo to return the wrong canonical name on Linux. +// So definitely leave it out. +const cgoAddrInfoFlags = syscall.AI_CANONNAME | syscall.AI_V4MAPPED | syscall.AI_ALL diff --git a/libgo/go/net/cgo_netbsd.go b/libgo/go/net/cgo_netbsd.go index 3c13103831f..8a16871906d 100644 --- a/libgo/go/net/cgo_netbsd.go +++ b/libgo/go/net/cgo_netbsd.go @@ -9,8 +9,6 @@ package net /* #include */ -import "C" +import "syscall" -func cgoAddrInfoFlags() int { - return C.AI_CANONNAME -} +const cgoAddrInfoFlags = syscall.AI_CANONNAME diff --git a/libgo/go/net/cgo_openbsd.go b/libgo/go/net/cgo_openbsd.go index 09c5ad2d9fd..183091366cb 100644 --- a/libgo/go/net/cgo_openbsd.go +++ b/libgo/go/net/cgo_openbsd.go @@ -11,6 +11,4 @@ package net */ import "C" -func cgoAddrInfoFlags() C.int { - return C.AI_CANONNAME -} +const cgoAddrInfoFlags = C.AI_CANONNAME diff --git a/libgo/go/net/cgo_resnew.go b/libgo/go/net/cgo_resnew.go new file mode 100644 index 00000000000..ebca1bda5a8 --- /dev/null +++ b/libgo/go/net/cgo_resnew.go @@ -0,0 +1,36 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build cgo,!netgo +// +build darwin linux,!android netbsd solaris + +package net + +/* +#include +#include + +#include +*/ + +import ( + "syscall" +) + +//extern getnameinfo +func libc_getnameinfo(*syscall.RawSockaddr, syscall.Socklen_t, *byte, syscall.Size_t, *byte, syscall.Size_t, int) int + +func cgoNameinfoPTR(b []byte, sa *syscall.RawSockaddr, salen syscall.Socklen_t) (int, error) { + syscall.Entersyscall() + gerrno := libc_getnameinfo(sa, salen, &b[0], syscall.Size_t(len(b)), nil, 0, syscall.NI_NAMEREQD) + syscall.Exitsyscall() + var err error + if gerrno == syscall.EAI_SYSTEM { + errno := syscall.GetErrno() + if errno != 0 { + err = errno + } + } + return gerrno, err +} diff --git a/libgo/go/net/cgo_resold.go b/libgo/go/net/cgo_resold.go new file mode 100644 index 00000000000..8e13e4156d0 --- /dev/null +++ b/libgo/go/net/cgo_resold.go @@ -0,0 +1,36 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build cgo,!netgo +// +build android freebsd dragonfly openbsd + +package net + +/* +#include +#include + +#include +*/ + +import ( + "syscall" +) + +//extern getnameinfo +func libc_getnameinfo(*syscall.RawSockaddr, syscall.Socklen_t, *byte, syscall.Size_t, *byte, syscall.Size_t, int) int + +func cgoNameinfoPTR(b []byte, sa *syscall.RawSockaddr, salen syscall.Socklen_t) (int, error) { + syscall.Entersyscall() + gerrno := libc_getnameinfo(sa, salen, &b[0], syscall.Size(len(b)), nil, 0, syscall.NI_NAMEREQD) + syscall.Exitsyscall() + var err error + if gerrno == syscall.EAI_SYSTEM { + errno := syscall.GetErrno() + if errno != 0 { + err = errno + } + } + return gerrno, err +} diff --git a/libgo/go/net/cgo_socknew.go b/libgo/go/net/cgo_socknew.go new file mode 100644 index 00000000000..81816c644f8 --- /dev/null +++ b/libgo/go/net/cgo_socknew.go @@ -0,0 +1,32 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build cgo,!netgo +// +build android linux solaris + +package net + +/* +#include +#include + +#include +*/ + +import ( + "syscall" + "unsafe" +) + +func cgoSockaddrInet4(ip IP) *syscall.RawSockaddr { + sa := syscall.RawSockaddrInet4{Family: syscall.AF_INET} + copy(sa.Addr[:], ip) + return (*syscall.RawSockaddr)(unsafe.Pointer(&sa)) +} + +func cgoSockaddrInet6(ip IP) *syscall.RawSockaddr { + sa := syscall.RawSockaddrInet6{Family: syscall.AF_INET6} + copy(sa.Addr[:], ip) + return (*syscall.RawSockaddr)(unsafe.Pointer(&sa)) +} diff --git a/libgo/go/net/cgo_sockold.go b/libgo/go/net/cgo_sockold.go new file mode 100644 index 00000000000..e80e03b2b1e --- /dev/null +++ b/libgo/go/net/cgo_sockold.go @@ -0,0 +1,32 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build cgo,!netgo +// +build darwin dragonfly freebsd netbsd openbsd + +package net + +/* +#include +#include + +#include +*/ + +import ( + "syscall" + "unsafe" +) + +func cgoSockaddrInet4(ip IP) *syscall.RawSockaddr { + sa := syscall.RawSockaddrInet4{Len: syscall.SizeofSockaddrInet4, Family: syscall.AF_INET} + copy(sa.Addr[:], ip) + return (*syscall.RawSockaddr)(unsafe.Pointer(&sa)) +} + +func cgoSockaddrInet6(ip IP) *syscall.RawSockaddr { + sa := syscall.RawSockaddrInet6{Len: syscall.SizeofSockaddrInet6, Family: syscall.AF_INET6} + copy(sa.Addr[:], ip) + return (*syscall.RawSockaddr)(unsafe.Pointer(&sa)) +} diff --git a/libgo/go/net/cgo_solaris.go b/libgo/go/net/cgo_solaris.go new file mode 100644 index 00000000000..c5a7a3549dd --- /dev/null +++ b/libgo/go/net/cgo_solaris.go @@ -0,0 +1,16 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build cgo,!netgo + +package net + +/* +#cgo LDFLAGS: -lsocket -lnsl +#include +*/ + +import "syscall" + +const cgoAddrInfoFlags = syscall.AI_CANONNAME | syscall.AI_V4MAPPED | syscall.AI_ALL diff --git a/libgo/go/net/cgo_stub.go b/libgo/go/net/cgo_stub.go index f533c14212f..b86ff7daf19 100644 --- a/libgo/go/net/cgo_stub.go +++ b/libgo/go/net/cgo_stub.go @@ -4,10 +4,16 @@ // +build !cgo netgo -// Stub cgo routines for systems that do not use cgo to do network lookups. - package net +func init() { netGo = true } + +type addrinfoErrno int + +func (eai addrinfoErrno) Error() string { return "" } +func (eai addrinfoErrno) Temporary() bool { return false } +func (eai addrinfoErrno) Timeout() bool { return false } + func cgoLookupHost(name string) (addrs []string, err error, completed bool) { return nil, nil, false } @@ -16,10 +22,14 @@ func cgoLookupPort(network, service string) (port int, err error, completed bool return 0, nil, false } -func cgoLookupIP(name string) (addrs []IP, err error, completed bool) { +func cgoLookupIP(name string) (addrs []IPAddr, err error, completed bool) { return nil, nil, false } func cgoLookupCNAME(name string) (cname string, err error, completed bool) { return "", nil, false } + +func cgoLookupPTR(addr string) (ptrs []string, err error, completed bool) { + return nil, nil, false +} diff --git a/libgo/go/net/cgo_unix.go b/libgo/go/net/cgo_unix.go index 0abf43410e1..8eafa8cbd44 100644 --- a/libgo/go/net/cgo_unix.go +++ b/libgo/go/net/cgo_unix.go @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build !netgo -// +build darwin dragonfly freebsd linux netbsd openbsd +// +build cgo,!netgo +// +build darwin dragonfly freebsd linux netbsd openbsd solaris package net @@ -42,24 +42,30 @@ func bytePtrToString(p *byte) string { return string(a[:i]) } -func cgoLookupHost(name string) (addrs []string, err error, completed bool) { - ip, err, completed := cgoLookupIP(name) - for _, p := range ip { - addrs = append(addrs, p.String()) +// An addrinfoErrno represents a getaddrinfo, getnameinfo-specific +// error number. It's a signed number and a zero value is a non-error +// by convention. +type addrinfoErrno int + +func (eai addrinfoErrno) Error() string { return bytePtrToString(libc_gai_strerror(int(eai))) } +func (eai addrinfoErrno) Temporary() bool { return eai == syscall.EAI_AGAIN } +func (eai addrinfoErrno) Timeout() bool { return false } + +func cgoLookupHost(name string) (hosts []string, err error, completed bool) { + addrs, err, completed := cgoLookupIP(name) + for _, addr := range addrs { + hosts = append(hosts, addr.String()) } return } -func cgoLookupPort(net, service string) (port int, err error, completed bool) { +func cgoLookupPort(network, service string) (port int, err error, completed bool) { acquireThread() defer releaseThread() - var res *syscall.Addrinfo var hints syscall.Addrinfo - - switch net { - case "": - // no hints + switch network { + case "": // no hints case "tcp", "tcp4", "tcp6": hints.Ai_socktype = syscall.SOCK_STREAM hints.Ai_protocol = syscall.IPPROTO_TCP @@ -67,10 +73,10 @@ func cgoLookupPort(net, service string) (port int, err error, completed bool) { hints.Ai_socktype = syscall.SOCK_DGRAM hints.Ai_protocol = syscall.IPPROTO_UDP default: - return 0, UnknownNetworkError(net), true + return 0, &DNSError{Err: "unknown network", Name: network + "/" + service}, true } - if len(net) >= 4 { - switch net[3] { + if len(network) >= 4 { + switch network[3] { case '4': hints.Ai_family = syscall.AF_INET case '6': @@ -79,48 +85,56 @@ func cgoLookupPort(net, service string) (port int, err error, completed bool) { } s := syscall.StringBytePtr(service) + var res *syscall.Addrinfo syscall.Entersyscall() gerrno := libc_getaddrinfo(nil, s, &hints, &res) syscall.Exitsyscall() - if gerrno == 0 { - defer libc_freeaddrinfo(res) - for r := res; r != nil; r = r.Ai_next { - switch r.Ai_family { - default: - continue - case syscall.AF_INET: - sa := (*syscall.RawSockaddrInet4)(unsafe.Pointer(r.Ai_addr)) - p := (*[2]byte)(unsafe.Pointer(&sa.Port)) - return int(p[0])<<8 | int(p[1]), nil, true - case syscall.AF_INET6: - sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(r.Ai_addr)) - p := (*[2]byte)(unsafe.Pointer(&sa.Port)) - return int(p[0])<<8 | int(p[1]), nil, true + if gerrno != 0 { + switch gerrno { + case syscall.EAI_SYSTEM: + errno := syscall.GetErrno() + if errno == 0 { // see golang.org/issue/6232 + errno = syscall.EMFILE } + err = errno + default: + err = addrinfoErrno(gerrno) } + return 0, &DNSError{Err: err.Error(), Name: network + "/" + service}, true } - return 0, &AddrError{"unknown port", net + "/" + service}, true + defer libc_freeaddrinfo(res) + + for r := res; r != nil; r = r.Ai_next { + switch r.Ai_family { + case syscall.AF_INET: + sa := (*syscall.RawSockaddrInet4)(unsafe.Pointer(r.Ai_addr)) + p := (*[2]byte)(unsafe.Pointer(&sa.Port)) + return int(p[0])<<8 | int(p[1]), nil, true + case syscall.AF_INET6: + sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(r.Ai_addr)) + p := (*[2]byte)(unsafe.Pointer(&sa.Port)) + return int(p[0])<<8 | int(p[1]), nil, true + } + } + return 0, &DNSError{Err: "unknown port", Name: network + "/" + service}, true } -func cgoLookupIPCNAME(name string) (addrs []IP, cname string, err error, completed bool) { +func cgoLookupIPCNAME(name string) (addrs []IPAddr, cname string, err error, completed bool) { acquireThread() defer releaseThread() - var res *syscall.Addrinfo var hints syscall.Addrinfo - - hints.Ai_flags = int32(cgoAddrInfoFlags()) + hints.Ai_flags = int32(cgoAddrInfoFlags) hints.Ai_socktype = syscall.SOCK_STREAM h := syscall.StringBytePtr(name) + var res *syscall.Addrinfo syscall.Entersyscall() gerrno := libc_getaddrinfo(h, nil, &hints, &res) syscall.Exitsyscall() if gerrno != 0 { - var str string - if gerrno == syscall.EAI_NONAME { - str = noSuchHost - } else if gerrno == syscall.EAI_SYSTEM { + switch gerrno { + case syscall.EAI_SYSTEM: errno := syscall.GetErrno() if errno == 0 { // err should not be nil, but sometimes getaddrinfo returns @@ -132,13 +146,16 @@ func cgoLookupIPCNAME(name string) (addrs []IP, cname string, err error, complet // comes up again. golang.org/issue/6232. errno = syscall.EMFILE } - str = errno.Error() - } else { - str = bytePtrToString(libc_gai_strerror(gerrno)) + err = errno + case syscall.EAI_NONAME: + err = errNoSuchHost + default: + err = addrinfoErrno(gerrno) } - return nil, "", &DNSError{Err: str, Name: name}, true + return nil, "", &DNSError{Err: err.Error(), Name: name}, true } defer libc_freeaddrinfo(res) + if res != nil { cname = bytePtrToString((*byte)(unsafe.Pointer(res.Ai_canonname))) if cname == "" { @@ -154,20 +171,20 @@ func cgoLookupIPCNAME(name string) (addrs []IP, cname string, err error, complet continue } switch r.Ai_family { - default: - continue case syscall.AF_INET: sa := (*syscall.RawSockaddrInet4)(unsafe.Pointer(r.Ai_addr)) - addrs = append(addrs, copyIP(sa.Addr[:])) + addr := IPAddr{IP: copyIP(sa.Addr[:])} + addrs = append(addrs, addr) case syscall.AF_INET6: sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(r.Ai_addr)) - addrs = append(addrs, copyIP(sa.Addr[:])) + addr := IPAddr{IP: copyIP(sa.Addr[:]), Zone: zoneToString(int(sa.Scope_id))} + addrs = append(addrs, addr) } } return addrs, cname, nil, true } -func cgoLookupIP(name string) (addrs []IP, err error, completed bool) { +func cgoLookupIP(name string) (addrs []IPAddr, err error, completed bool) { addrs, _, err, completed = cgoLookupIPCNAME(name) return } @@ -177,6 +194,77 @@ func cgoLookupCNAME(name string) (cname string, err error, completed bool) { return } +// These are roughly enough for the following: +// +// Source Encoding Maximum length of single name entry +// Unicast DNS ASCII or <=253 + a NUL terminator +// Unicode in RFC 5892 252 * total number of labels + delimiters + a NUL terminator +// Multicast DNS UTF-8 in RFC 5198 or <=253 + a NUL terminator +// the same as unicast DNS ASCII <=253 + a NUL terminator +// Local database various depends on implementation +const ( + nameinfoLen = 64 + maxNameinfoLen = 4096 +) + +func cgoLookupPTR(addr string) ([]string, error, bool) { + acquireThread() + defer releaseThread() + + ip := ParseIP(addr) + if ip == nil { + return nil, &DNSError{Err: "invalid address", Name: addr}, true + } + sa, salen := cgoSockaddr(ip) + if sa == nil { + return nil, &DNSError{Err: "invalid address " + ip.String(), Name: addr}, true + } + var err error + var b []byte + var gerrno int + for l := nameinfoLen; l <= maxNameinfoLen; l *= 2 { + b = make([]byte, l) + gerrno, err = cgoNameinfoPTR(b, sa, salen) + if gerrno == 0 || gerrno != syscall.EAI_OVERFLOW { + break + } + } + if gerrno != 0 { + switch gerrno { + case syscall.EAI_SYSTEM: + if err == nil { // see golang.org/issue/6232 + err = syscall.EMFILE + } + default: + err = addrinfoErrno(gerrno) + } + return nil, &DNSError{Err: err.Error(), Name: addr}, true + } + + for i := 0; i < len(b); i++ { + if b[i] == 0 { + b = b[:i] + break + } + } + // Add trailing dot to match pure Go reverse resolver + // and all other lookup routines. See golang.org/issue/12189. + if len(b) > 0 && b[len(b)-1] != '.' { + b = append(b, '.') + } + return []string{string(b)}, nil, true +} + +func cgoSockaddr(ip IP) (*syscall.RawSockaddr, syscall.Socklen_t) { + if ip4 := ip.To4(); ip4 != nil { + return cgoSockaddrInet4(ip4), syscall.Socklen_t(syscall.SizeofSockaddrInet4) + } + if ip6 := ip.To16(); ip6 != nil { + return cgoSockaddrInet6(ip6), syscall.Socklen_t(syscall.SizeofSockaddrInet6) + } + return nil, 0 +} + func copyIP(x IP) IP { if len(x) < 16 { return x.To16() diff --git a/libgo/go/net/cgo_unix_test.go b/libgo/go/net/cgo_unix_test.go index 33566ce9c2e..4d5ab23fd36 100644 --- a/libgo/go/net/cgo_unix_test.go +++ b/libgo/go/net/cgo_unix_test.go @@ -3,7 +3,7 @@ // license that can be found in the LICENSE file. // +build cgo,!netgo -// +build darwin dragonfly freebsd linux netbsd openbsd +// +build darwin dragonfly freebsd linux netbsd openbsd solaris package net @@ -16,9 +16,9 @@ func TestCgoLookupIP(t *testing.T) { t.Errorf("cgoLookupIP must not be a placeholder") } if err != nil { - t.Errorf("cgoLookupIP failed: %v", err) + t.Error(err) } if _, err := goLookupIP(host); err != nil { - t.Errorf("goLookupIP failed: %v", err) + t.Error(err) } } diff --git a/libgo/go/net/cgo_windows.go b/libgo/go/net/cgo_windows.go new file mode 100644 index 00000000000..8968b757a90 --- /dev/null +++ b/libgo/go/net/cgo_windows.go @@ -0,0 +1,13 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build cgo,!netgo + +package net + +type addrinfoErrno int + +func (eai addrinfoErrno) Error() string { return "" } +func (eai addrinfoErrno) Temporary() bool { return false } +func (eai addrinfoErrno) Timeout() bool { return false } diff --git a/libgo/go/net/conf.go b/libgo/go/net/conf.go new file mode 100644 index 00000000000..c92e579d7e6 --- /dev/null +++ b/libgo/go/net/conf.go @@ -0,0 +1,308 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd linux netbsd openbsd solaris + +package net + +import ( + "os" + "runtime" + "strconv" + "sync" + "syscall" +) + +// conf represents a system's network configuration. +type conf struct { + // forceCgoLookupHost forces CGO to always be used, if available. + forceCgoLookupHost bool + + netGo bool // go DNS resolution forced + netCgo bool // cgo DNS resolution forced + + // machine has an /etc/mdns.allow file + hasMDNSAllow bool + + goos string // the runtime.GOOS, to ease testing + dnsDebugLevel int + + nss *nssConf + resolv *dnsConfig +} + +var ( + confOnce sync.Once // guards init of confVal via initConfVal + confVal = &conf{goos: runtime.GOOS} +) + +// systemConf returns the machine's network configuration. +func systemConf() *conf { + confOnce.Do(initConfVal) + return confVal +} + +func initConfVal() { + dnsMode, debugLevel := goDebugNetDNS() + confVal.dnsDebugLevel = debugLevel + confVal.netGo = netGo || dnsMode == "go" + confVal.netCgo = netCgo || dnsMode == "cgo" + + if confVal.dnsDebugLevel > 0 { + defer func() { + switch { + case confVal.netGo: + if netGo { + println("go package net: built with netgo build tag; using Go's DNS resolver") + } else { + println("go package net: GODEBUG setting forcing use of Go's resolver") + } + case confVal.forceCgoLookupHost: + println("go package net: using cgo DNS resolver") + default: + println("go package net: dynamic selection of DNS resolver") + } + }() + } + + // Darwin pops up annoying dialog boxes if programs try to do + // their own DNS requests. So always use cgo instead, which + // avoids that. + if runtime.GOOS == "darwin" { + confVal.forceCgoLookupHost = true + return + } + + // If any environment-specified resolver options are specified, + // force cgo. Note that LOCALDOMAIN can change behavior merely + // by being specified with the empty string. + _, localDomainDefined := syscall.Getenv("LOCALDOMAIN") + if os.Getenv("RES_OPTIONS") != "" || + os.Getenv("HOSTALIASES") != "" || + confVal.netCgo || + localDomainDefined { + confVal.forceCgoLookupHost = true + return + } + + // OpenBSD apparently lets you override the location of resolv.conf + // with ASR_CONFIG. If we notice that, defer to libc. + if runtime.GOOS == "openbsd" && os.Getenv("ASR_CONFIG") != "" { + confVal.forceCgoLookupHost = true + return + } + + if runtime.GOOS != "openbsd" { + confVal.nss = parseNSSConfFile("/etc/nsswitch.conf") + } + + confVal.resolv = dnsReadConfig("/etc/resolv.conf") + if confVal.resolv.err != nil && !os.IsNotExist(confVal.resolv.err) && + !os.IsPermission(confVal.resolv.err) { + // If we can't read the resolv.conf file, assume it + // had something important in it and defer to cgo. + // libc's resolver might then fail too, but at least + // it wasn't our fault. + confVal.forceCgoLookupHost = true + } + + if _, err := os.Stat("/etc/mdns.allow"); err == nil { + confVal.hasMDNSAllow = true + } +} + +// canUseCgo reports whether calling cgo functions is allowed +// for non-hostname lookups. +func (c *conf) canUseCgo() bool { + return c.hostLookupOrder("") == hostLookupCgo +} + +// hostLookupOrder determines which strategy to use to resolve hostname. +func (c *conf) hostLookupOrder(hostname string) (ret hostLookupOrder) { + if c.dnsDebugLevel > 1 { + defer func() { + print("go package net: hostLookupOrder(", hostname, ") = ", ret.String(), "\n") + }() + } + if c.netGo { + return hostLookupFilesDNS + } + if c.forceCgoLookupHost || c.resolv.unknownOpt || c.goos == "android" { + return hostLookupCgo + } + if byteIndex(hostname, '\\') != -1 || byteIndex(hostname, '%') != -1 { + // Don't deal with special form hostnames with backslashes + // or '%'. + return hostLookupCgo + } + + // OpenBSD is unique and doesn't use nsswitch.conf. + // It also doesn't support mDNS. + if c.goos == "openbsd" { + // OpenBSD's resolv.conf manpage says that a non-existent + // resolv.conf means "lookup" defaults to only "files", + // without DNS lookups. + if os.IsNotExist(c.resolv.err) { + return hostLookupFiles + } + lookup := c.resolv.lookup + if len(lookup) == 0 { + // http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man5/resolv.conf.5 + // "If the lookup keyword is not used in the + // system's resolv.conf file then the assumed + // order is 'bind file'" + return hostLookupDNSFiles + } + if len(lookup) < 1 || len(lookup) > 2 { + return hostLookupCgo + } + switch lookup[0] { + case "bind": + if len(lookup) == 2 { + if lookup[1] == "file" { + return hostLookupDNSFiles + } + return hostLookupCgo + } + return hostLookupDNS + case "file": + if len(lookup) == 2 { + if lookup[1] == "bind" { + return hostLookupFilesDNS + } + return hostLookupCgo + } + return hostLookupFiles + default: + return hostLookupCgo + } + } + + hasDot := byteIndex(hostname, '.') != -1 + + // Canonicalize the hostname by removing any trailing dot. + if stringsHasSuffix(hostname, ".") { + hostname = hostname[:len(hostname)-1] + } + if stringsHasSuffixFold(hostname, ".local") { + // Per RFC 6762, the ".local" TLD is special. And + // because Go's native resolver doesn't do mDNS or + // similar local resolution mechanisms, assume that + // libc might (via Avahi, etc) and use cgo. + return hostLookupCgo + } + + nss := c.nss + srcs := nss.sources["hosts"] + // If /etc/nsswitch.conf doesn't exist or doesn't specify any + // sources for "hosts", assume Go's DNS will work fine. + if os.IsNotExist(nss.err) || (nss.err == nil && len(srcs) == 0) { + if c.goos == "solaris" { + // illumos defaults to "nis [NOTFOUND=return] files" + return hostLookupCgo + } + if c.goos == "linux" { + // glibc says the default is "dns [!UNAVAIL=return] files" + // http://www.gnu.org/software/libc/manual/html_node/Notes-on-NSS-Configuration-File.html. + return hostLookupDNSFiles + } + return hostLookupFilesDNS + } + if nss.err != nil { + // We failed to parse or open nsswitch.conf, so + // conservatively assume we should use cgo if it's + // available. + return hostLookupCgo + } + + var mdnsSource, filesSource, dnsSource bool + var first string + for _, src := range srcs { + if src.source == "myhostname" { + if hasDot { + continue + } + return hostLookupCgo + } + if src.source == "files" || src.source == "dns" { + if !src.standardCriteria() { + return hostLookupCgo // non-standard; let libc deal with it. + } + if src.source == "files" { + filesSource = true + } else if src.source == "dns" { + dnsSource = true + } + if first == "" { + first = src.source + } + continue + } + if stringsHasPrefix(src.source, "mdns") { + // e.g. "mdns4", "mdns4_minimal" + // We already returned true before if it was *.local. + // libc wouldn't have found a hit on this anyway. + mdnsSource = true + continue + } + // Some source we don't know how to deal with. + return hostLookupCgo + } + + // We don't parse mdns.allow files. They're rare. If one + // exists, it might list other TLDs (besides .local) or even + // '*', so just let libc deal with it. + if mdnsSource && c.hasMDNSAllow { + return hostLookupCgo + } + + // Cases where Go can handle it without cgo and C thread + // overhead. + switch { + case filesSource && dnsSource: + if first == "files" { + return hostLookupFilesDNS + } else { + return hostLookupDNSFiles + } + case filesSource: + return hostLookupFiles + case dnsSource: + return hostLookupDNS + } + + // Something weird. Let libc deal with it. + return hostLookupCgo +} + +// goDebugNetDNS parses the value of the GODEBUG "netdns" value. +// The netdns value can be of the form: +// 1 // debug level 1 +// 2 // debug level 2 +// cgo // use cgo for DNS lookups +// go // use go for DNS lookups +// cgo+1 // use cgo for DNS lookups + debug level 1 +// 1+cgo // same +// cgo+2 // same, but debug level 2 +// etc. +func goDebugNetDNS() (dnsMode string, debugLevel int) { + goDebug := goDebugString("netdns") + parsePart := func(s string) { + if s == "" { + return + } + if '0' <= s[0] && s[0] <= '9' { + debugLevel, _ = strconv.Atoi(s) + } else { + dnsMode = s + } + } + if i := byteIndex(goDebug, '+'); i != -1 { + parsePart(goDebug[:i]) + parsePart(goDebug[i+1:]) + return + } + parsePart(goDebug) + return +} diff --git a/libgo/go/net/conf_netcgo.go b/libgo/go/net/conf_netcgo.go new file mode 100644 index 00000000000..b66bae37106 --- /dev/null +++ b/libgo/go/net/conf_netcgo.go @@ -0,0 +1,17 @@ +// Copyright 2015 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 netcgo + +package net + +/* + +// Fail if cgo isn't available. + +*/ + +// The build tag "netcgo" forces use of the cgo DNS resolver. +// It is the opposite of "netgo". +func init() { netCgo = true } diff --git a/libgo/go/net/conf_test.go b/libgo/go/net/conf_test.go new file mode 100644 index 00000000000..86904bffde7 --- /dev/null +++ b/libgo/go/net/conf_test.go @@ -0,0 +1,301 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd linux netbsd openbsd solaris + +package net + +import ( + "os" + "strings" + "testing" +) + +type nssHostTest struct { + host string + want hostLookupOrder +} + +func nssStr(s string) *nssConf { return parseNSSConf(strings.NewReader(s)) } + +// represents a dnsConfig returned by parsing a nonexistent resolv.conf +var defaultResolvConf = &dnsConfig{ + servers: defaultNS, + ndots: 1, + timeout: 5, + attempts: 2, + err: os.ErrNotExist, +} + +func TestConfHostLookupOrder(t *testing.T) { + tests := []struct { + name string + c *conf + goos string + hostTests []nssHostTest + }{ + { + name: "force", + c: &conf{ + forceCgoLookupHost: true, + nss: nssStr("foo: bar"), + resolv: defaultResolvConf, + }, + hostTests: []nssHostTest{ + {"foo.local", hostLookupCgo}, + {"google.com", hostLookupCgo}, + }, + }, + { + name: "ubuntu_trusty_avahi", + c: &conf{ + nss: nssStr("hosts: files mdns4_minimal [NOTFOUND=return] dns mdns4"), + resolv: defaultResolvConf, + }, + hostTests: []nssHostTest{ + {"foo.local", hostLookupCgo}, + {"foo.local.", hostLookupCgo}, + {"foo.LOCAL", hostLookupCgo}, + {"foo.LOCAL.", hostLookupCgo}, + {"google.com", hostLookupFilesDNS}, + }, + }, + { + name: "freebsdlinux_no_resolv_conf", + c: &conf{ + goos: "freebsd", + nss: nssStr("foo: bar"), + resolv: defaultResolvConf, + }, + hostTests: []nssHostTest{{"google.com", hostLookupFilesDNS}}, + }, + // On OpenBSD, no resolv.conf means no DNS. + { + name: "openbsd_no_resolv_conf", + c: &conf{ + goos: "openbsd", + resolv: defaultResolvConf, + }, + hostTests: []nssHostTest{{"google.com", hostLookupFiles}}, + }, + { + name: "solaris_no_nsswitch", + c: &conf{ + goos: "solaris", + nss: &nssConf{err: os.ErrNotExist}, + resolv: defaultResolvConf, + }, + hostTests: []nssHostTest{{"google.com", hostLookupCgo}}, + }, + { + name: "openbsd_lookup_bind_file", + c: &conf{ + goos: "openbsd", + resolv: &dnsConfig{lookup: []string{"bind", "file"}}, + }, + hostTests: []nssHostTest{ + {"google.com", hostLookupDNSFiles}, + {"foo.local", hostLookupDNSFiles}, + }, + }, + { + name: "openbsd_lookup_file_bind", + c: &conf{ + goos: "openbsd", + resolv: &dnsConfig{lookup: []string{"file", "bind"}}, + }, + hostTests: []nssHostTest{{"google.com", hostLookupFilesDNS}}, + }, + { + name: "openbsd_lookup_bind", + c: &conf{ + goos: "openbsd", + resolv: &dnsConfig{lookup: []string{"bind"}}, + }, + hostTests: []nssHostTest{{"google.com", hostLookupDNS}}, + }, + { + name: "openbsd_lookup_file", + c: &conf{ + goos: "openbsd", + resolv: &dnsConfig{lookup: []string{"file"}}, + }, + hostTests: []nssHostTest{{"google.com", hostLookupFiles}}, + }, + { + name: "openbsd_lookup_yp", + c: &conf{ + goos: "openbsd", + resolv: &dnsConfig{lookup: []string{"file", "bind", "yp"}}, + }, + hostTests: []nssHostTest{{"google.com", hostLookupCgo}}, + }, + { + name: "openbsd_lookup_two", + c: &conf{ + goos: "openbsd", + resolv: &dnsConfig{lookup: []string{"file", "foo"}}, + }, + hostTests: []nssHostTest{{"google.com", hostLookupCgo}}, + }, + { + name: "openbsd_lookup_empty", + c: &conf{ + goos: "openbsd", + resolv: &dnsConfig{lookup: nil}, + }, + hostTests: []nssHostTest{{"google.com", hostLookupDNSFiles}}, + }, + // glibc lacking an nsswitch.conf, per + // http://www.gnu.org/software/libc/manual/html_node/Notes-on-NSS-Configuration-File.html + { + name: "linux_no_nsswitch.conf", + c: &conf{ + goos: "linux", + nss: &nssConf{err: os.ErrNotExist}, + resolv: defaultResolvConf, + }, + hostTests: []nssHostTest{{"google.com", hostLookupDNSFiles}}, + }, + { + name: "files_mdns_dns", + c: &conf{ + nss: nssStr("hosts: files mdns dns"), + resolv: defaultResolvConf, + }, + hostTests: []nssHostTest{ + {"x.com", hostLookupFilesDNS}, + {"x.local", hostLookupCgo}, + }, + }, + { + name: "dns_special_hostnames", + c: &conf{ + nss: nssStr("hosts: dns"), + resolv: defaultResolvConf, + }, + hostTests: []nssHostTest{ + {"x.com", hostLookupDNS}, + {"x\\.com", hostLookupCgo}, // punt on weird glibc escape + {"foo.com%en0", hostLookupCgo}, // and IPv6 zones + }, + }, + { + name: "mdns_allow", + c: &conf{ + nss: nssStr("hosts: files mdns dns"), + resolv: defaultResolvConf, + hasMDNSAllow: true, + }, + hostTests: []nssHostTest{ + {"x.com", hostLookupCgo}, + {"x.local", hostLookupCgo}, + }, + }, + { + name: "files_dns", + c: &conf{ + nss: nssStr("hosts: files dns"), + resolv: defaultResolvConf, + }, + hostTests: []nssHostTest{ + {"x.com", hostLookupFilesDNS}, + {"x", hostLookupFilesDNS}, + {"x.local", hostLookupCgo}, + }, + }, + { + name: "dns_files", + c: &conf{ + nss: nssStr("hosts: dns files"), + resolv: defaultResolvConf, + }, + hostTests: []nssHostTest{ + {"x.com", hostLookupDNSFiles}, + {"x", hostLookupDNSFiles}, + {"x.local", hostLookupCgo}, + }, + }, + { + name: "something_custom", + c: &conf{ + nss: nssStr("hosts: dns files something_custom"), + resolv: defaultResolvConf, + }, + hostTests: []nssHostTest{ + {"x.com", hostLookupCgo}, + }, + }, + { + name: "myhostname", + c: &conf{ + nss: nssStr("hosts: files dns myhostname"), + resolv: defaultResolvConf, + }, + hostTests: []nssHostTest{ + {"x.com", hostLookupFilesDNS}, + {"somehostname", hostLookupCgo}, + }, + }, + { + name: "ubuntu14.04.02", + c: &conf{ + nss: nssStr("hosts: files myhostname mdns4_minimal [NOTFOUND=return] dns mdns4"), + resolv: defaultResolvConf, + }, + hostTests: []nssHostTest{ + {"x.com", hostLookupFilesDNS}, + {"somehostname", hostLookupCgo}, + }, + }, + // Debian Squeeze is just "dns,files", but lists all + // the default criteria for dns, but then has a + // non-standard but redundant notfound=return for the + // files. + { + name: "debian_squeeze", + c: &conf{ + nss: nssStr("hosts: dns [success=return notfound=continue unavail=continue tryagain=continue] files [notfound=return]"), + resolv: defaultResolvConf, + }, + hostTests: []nssHostTest{ + {"x.com", hostLookupDNSFiles}, + {"somehostname", hostLookupDNSFiles}, + }, + }, + { + name: "resolv.conf-unknown", + c: &conf{ + nss: nssStr("foo: bar"), + resolv: &dnsConfig{servers: defaultNS, ndots: 1, timeout: 5, attempts: 2, unknownOpt: true}, + }, + hostTests: []nssHostTest{{"google.com", hostLookupCgo}}, + }, + // Android should always use cgo. + { + name: "android", + c: &conf{ + goos: "android", + nss: nssStr(""), + resolv: defaultResolvConf, + }, + hostTests: []nssHostTest{ + {"x.com", hostLookupCgo}, + }, + }, + } + for _, tt := range tests { + for _, ht := range tt.hostTests { + gotOrder := tt.c.hostLookupOrder(ht.host) + if gotOrder != ht.want { + t.Errorf("%s: hostLookupOrder(%q) = %v; want %v", tt.name, ht.host, gotOrder, ht.want) + } + } + } + +} + +func TestSystemConf(t *testing.T) { + systemConf() +} diff --git a/libgo/go/net/conn_test.go b/libgo/go/net/conn_test.go index 9c9d1a8057d..6995c110f20 100644 --- a/libgo/go/net/conn_test.go +++ b/libgo/go/net/conn_test.go @@ -8,117 +8,58 @@ package net import ( - "os" - "runtime" "testing" "time" ) -var connTests = []struct { - net string - addr string -}{ - {"tcp", "127.0.0.1:0"}, - {"unix", testUnixAddr()}, - {"unixpacket", testUnixAddr()}, -} - // someTimeout is used just to test that net.Conn implementations // don't explode when their SetFooDeadline methods are called. // It isn't actually used for testing timeouts. const someTimeout = 10 * time.Second func TestConnAndListener(t *testing.T) { - for _, tt := range connTests { - switch tt.net { - case "unix": - switch runtime.GOOS { - case "nacl", "plan9", "windows": - continue - } - case "unixpacket": - switch runtime.GOOS { - case "android", "darwin", "nacl", "openbsd", "plan9", "windows": - continue - case "freebsd": // FreeBSD 8 doesn't support unixpacket - continue - } + for i, network := range []string{"tcp", "unix", "unixpacket"} { + if !testableNetwork(network) { + t.Logf("skipping %s test", network) + continue } - ln, err := Listen(tt.net, tt.addr) + ls, err := newLocalServer(network) if err != nil { - t.Fatalf("Listen failed: %v", err) + t.Fatal(err) } - defer func(ln Listener, net, addr string) { - ln.Close() - switch net { - case "unix", "unixpacket": - os.Remove(addr) - } - }(ln, tt.net, tt.addr) - if ln.Addr().Network() != tt.net { - t.Fatalf("got %v; expected %v", ln.Addr().Network(), tt.net) + defer ls.teardown() + ch := make(chan error, 1) + handler := func(ls *localServer, ln Listener) { transponder(ln, ch) } + if err := ls.buildup(handler); err != nil { + t.Fatal(err) + } + if ls.Listener.Addr().Network() != network { + t.Fatalf("got %s; want %s", ls.Listener.Addr().Network(), network) } - done := make(chan int) - go transponder(t, ln, done) - - c, err := Dial(tt.net, ln.Addr().String()) + c, err := Dial(ls.Listener.Addr().Network(), ls.Listener.Addr().String()) if err != nil { - t.Fatalf("Dial failed: %v", err) + t.Fatal(err) } defer c.Close() - if c.LocalAddr().Network() != tt.net || c.LocalAddr().Network() != tt.net { - t.Fatalf("got %v->%v; expected %v->%v", c.LocalAddr().Network(), c.RemoteAddr().Network(), tt.net, tt.net) + if c.LocalAddr().Network() != network || c.LocalAddr().Network() != network { + t.Fatalf("got %s->%s; want %s->%s", c.LocalAddr().Network(), c.RemoteAddr().Network(), network, network) } c.SetDeadline(time.Now().Add(someTimeout)) c.SetReadDeadline(time.Now().Add(someTimeout)) c.SetWriteDeadline(time.Now().Add(someTimeout)) - if _, err := c.Write([]byte("CONN TEST")); err != nil { - t.Fatalf("Conn.Write failed: %v", err) + if _, err := c.Write([]byte("CONN AND LISTENER TEST")); err != nil { + t.Fatal(err) } rb := make([]byte, 128) if _, err := c.Read(rb); err != nil { - t.Fatalf("Conn.Read failed: %v", err) + t.Fatal(err) } - <-done - } -} - -func transponder(t *testing.T, ln Listener, done chan<- int) { - defer func() { done <- 1 }() - - switch ln := ln.(type) { - case *TCPListener: - ln.SetDeadline(time.Now().Add(someTimeout)) - case *UnixListener: - ln.SetDeadline(time.Now().Add(someTimeout)) - } - c, err := ln.Accept() - if err != nil { - t.Errorf("Listener.Accept failed: %v", err) - return - } - defer c.Close() - network := ln.Addr().Network() - if c.LocalAddr().Network() != network || c.LocalAddr().Network() != network { - t.Errorf("got %v->%v; expected %v->%v", c.LocalAddr().Network(), c.RemoteAddr().Network(), network, network) - return - } - c.SetDeadline(time.Now().Add(someTimeout)) - c.SetReadDeadline(time.Now().Add(someTimeout)) - c.SetWriteDeadline(time.Now().Add(someTimeout)) - - b := make([]byte, 128) - n, err := c.Read(b) - if err != nil { - t.Errorf("Conn.Read failed: %v", err) - return - } - if _, err := c.Write(b[:n]); err != nil { - t.Errorf("Conn.Write failed: %v", err) - return + for err := range ch { + t.Errorf("#%d: %v", i, err) + } } } diff --git a/libgo/go/net/dial.go b/libgo/go/net/dial.go index e6f0436cdd3..cb4ec216d53 100644 --- a/libgo/go/net/dial.go +++ b/libgo/go/net/dial.go @@ -21,6 +21,9 @@ type Dialer struct { // // The default is no timeout. // + // When dialing a name with multiple IP addresses, the timeout + // may be divided between them. + // // With or without a timeout, the operating system may impose // its own earlier timeout. For instance, TCP timeouts are // often around 3 minutes. @@ -38,13 +41,17 @@ type Dialer struct { // If nil, a local address is automatically chosen. LocalAddr Addr - // DualStack allows a single dial to attempt to establish - // multiple IPv4 and IPv6 connections and to return the first - // established connection when the network is "tcp" and the - // destination is a host name that has multiple address family - // DNS records. + // DualStack enables RFC 6555-compliant "Happy Eyeballs" dialing + // when the network is "tcp" and the destination is a host name + // with both IPv4 and IPv6 addresses. This allows a client to + // tolerate networks where one address family is silently broken. DualStack bool + // FallbackDelay specifies the length of time to wait before + // spawning a fallback connection, when DualStack is enabled. + // If zero, a default delay of 300ms is used. + FallbackDelay time.Duration + // KeepAlive specifies the keep-alive period for an active // network connection. // If zero, keep-alives are not enabled. Network protocols @@ -54,11 +61,11 @@ type Dialer struct { // Return either now+Timeout or Deadline, whichever comes first. // Or zero, if neither is set. -func (d *Dialer) deadline() time.Time { +func (d *Dialer) deadline(now time.Time) time.Time { if d.Timeout == 0 { return d.Deadline } - timeoutDeadline := time.Now().Add(d.Timeout) + timeoutDeadline := now.Add(d.Timeout) if d.Deadline.IsZero() || timeoutDeadline.Before(d.Deadline) { return timeoutDeadline } else { @@ -66,6 +73,38 @@ func (d *Dialer) deadline() time.Time { } } +// partialDeadline returns the deadline to use for a single address, +// when multiple addresses are pending. +func partialDeadline(now, deadline time.Time, addrsRemaining int) (time.Time, error) { + if deadline.IsZero() { + return deadline, nil + } + timeRemaining := deadline.Sub(now) + if timeRemaining <= 0 { + return time.Time{}, errTimeout + } + // Tentatively allocate equal time to each remaining address. + timeout := timeRemaining / time.Duration(addrsRemaining) + // If the time per address is too short, steal from the end of the list. + const saneMinimum = 2 * time.Second + if timeout < saneMinimum { + if timeRemaining < saneMinimum { + timeout = timeRemaining + } else { + timeout = saneMinimum + } + } + return now.Add(timeout), nil +} + +func (d *Dialer) fallbackDelay() time.Duration { + if d.FallbackDelay > 0 { + return d.FallbackDelay + } else { + return 300 * time.Millisecond + } +} + func parseNetwork(net string) (afnet string, proto int, err error) { i := last(net, ':') if i < 0 { // no colon @@ -95,7 +134,7 @@ func parseNetwork(net string) (afnet string, proto int, err error) { return "", 0, UnknownNetworkError(net) } -func resolveAddr(op, net, addr string, deadline time.Time) (netaddr, error) { +func resolveAddrList(op, net, addr string, deadline time.Time) (addrList, error) { afnet, _, err := parseNetwork(net) if err != nil { return nil, err @@ -105,9 +144,13 @@ func resolveAddr(op, net, addr string, deadline time.Time) (netaddr, error) { } switch afnet { case "unix", "unixgram", "unixpacket": - return ResolveUnixAddr(afnet, addr) + addr, err := ResolveUnixAddr(afnet, addr) + if err != nil { + return nil, err + } + return addrList{addr}, nil } - return resolveInternetAddr(afnet, addr, deadline) + return internetAddrList(afnet, addr, deadline) } // Dial connects to the address on the named network. @@ -150,100 +193,186 @@ func DialTimeout(network, address string, timeout time.Duration) (Conn, error) { return d.Dial(network, address) } +// dialContext holds common state for all dial operations. +type dialContext struct { + Dialer + network, address string + finalDeadline time.Time +} + // Dial connects to the address on the named network. // // See func Dial for a description of the network and address // parameters. func (d *Dialer) Dial(network, address string) (Conn, error) { - ra, err := resolveAddr("dial", network, address, d.deadline()) + finalDeadline := d.deadline(time.Now()) + addrs, err := resolveAddrList("dial", network, address, finalDeadline) if err != nil { - return nil, &OpError{Op: "dial", Net: network, Addr: nil, Err: err} + return nil, &OpError{Op: "dial", Net: network, Source: nil, Addr: nil, Err: err} } - dialer := func(deadline time.Time) (Conn, error) { - return dialSingle(network, address, d.LocalAddr, ra.toAddr(), deadline) + + ctx := &dialContext{ + Dialer: *d, + network: network, + address: address, + finalDeadline: finalDeadline, } - if ras, ok := ra.(addrList); ok && d.DualStack && network == "tcp" { - dialer = func(deadline time.Time) (Conn, error) { - return dialMulti(network, address, d.LocalAddr, ras, deadline) - } + + var primaries, fallbacks addrList + if d.DualStack && network == "tcp" { + primaries, fallbacks = addrs.partition(isIPv4) + } else { + primaries = addrs } - c, err := dial(network, ra.toAddr(), dialer, d.deadline()) + + var c Conn + if len(fallbacks) == 0 { + // dialParallel can accept an empty fallbacks list, + // but this shortcut avoids the goroutine/channel overhead. + c, err = dialSerial(ctx, primaries, nil) + } else { + c, err = dialParallel(ctx, primaries, fallbacks) + } + if d.KeepAlive > 0 && err == nil { if tc, ok := c.(*TCPConn); ok { - tc.SetKeepAlive(true) - tc.SetKeepAlivePeriod(d.KeepAlive) + setKeepAlive(tc.fd, true) + setKeepAlivePeriod(tc.fd, d.KeepAlive) testHookSetKeepAlive() } } return c, err } -var testHookSetKeepAlive = func() {} // changed by dial_test.go +// dialParallel races two copies of dialSerial, giving the first a +// head start. It returns the first established connection and +// closes the others. Otherwise it returns an error from the first +// primary address. +func dialParallel(ctx *dialContext, primaries, fallbacks addrList) (Conn, error) { + results := make(chan dialResult) // unbuffered, so dialSerialAsync can detect race loss & cleanup + cancel := make(chan struct{}) + defer close(cancel) + + // Spawn the primary racer. + go dialSerialAsync(ctx, primaries, nil, cancel, results) + + // Spawn the fallback racer. + fallbackTimer := time.NewTimer(ctx.fallbackDelay()) + go dialSerialAsync(ctx, fallbacks, fallbackTimer, cancel, results) -// dialMulti attempts to establish connections to each destination of -// the list of addresses. It will return the first established -// connection and close the other connections. Otherwise it returns -// error on the last attempt. -func dialMulti(net, addr string, la Addr, ras addrList, deadline time.Time) (Conn, error) { - type racer struct { - Conn - error + var primaryErr error + for nracers := 2; nracers > 0; nracers-- { + res := <-results + // If we're still waiting for a connection, then hasten the delay. + // Otherwise, disable the Timer and let cancel take over. + if fallbackTimer.Stop() && res.error != nil { + fallbackTimer.Reset(0) + } + if res.error == nil { + return res.Conn, nil + } + if res.primary { + primaryErr = res.error + } } - // Sig controls the flow of dial results on lane. It passes a - // token to the next racer and also indicates the end of flow - // by using closed channel. - sig := make(chan bool, 1) - lane := make(chan racer, 1) - for _, ra := range ras { - go func(ra Addr) { - c, err := dialSingle(net, addr, la, ra, deadline) - if _, ok := <-sig; ok { - lane <- racer{c, err} - } else if err == nil { - // We have to return the resources - // that belong to the other - // connections here for avoiding - // unnecessary resource starvation. - c.Close() - } - }(ra.toAddr()) + return nil, primaryErr +} + +type dialResult struct { + Conn + error + primary bool +} + +// dialSerialAsync runs dialSerial after some delay, and returns the +// resulting connection through a channel. When racing two connections, +// the primary goroutine uses a nil timer to omit the delay. +func dialSerialAsync(ctx *dialContext, ras addrList, timer *time.Timer, cancel <-chan struct{}, results chan<- dialResult) { + if timer != nil { + // We're in the fallback goroutine; sleep before connecting. + select { + case <-timer.C: + case <-cancel: + return + } } - defer close(sig) - lastErr := errTimeout - nracers := len(ras) - for nracers > 0 { - sig <- true - racer := <-lane - if racer.error == nil { - return racer.Conn, nil + c, err := dialSerial(ctx, ras, cancel) + select { + case results <- dialResult{c, err, timer == nil}: + // We won the race. + case <-cancel: + // The other goroutine won the race. + if c != nil { + c.Close() + } + } +} + +// dialSerial connects to a list of addresses in sequence, returning +// either the first successful connection, or the first error. +func dialSerial(ctx *dialContext, ras addrList, cancel <-chan struct{}) (Conn, error) { + var firstErr error // The error from the first address is most relevant. + + for i, ra := range ras { + select { + case <-cancel: + return nil, &OpError{Op: "dial", Net: ctx.network, Source: ctx.LocalAddr, Addr: ra, Err: errCanceled} + default: + } + + partialDeadline, err := partialDeadline(time.Now(), ctx.finalDeadline, len(ras)-i) + if err != nil { + // Ran out of time. + if firstErr == nil { + firstErr = &OpError{Op: "dial", Net: ctx.network, Source: ctx.LocalAddr, Addr: ra, Err: err} + } + break } - lastErr = racer.error - nracers-- + + // dialTCP does not support cancelation (see golang.org/issue/11225), + // so if cancel fires, we'll continue trying to connect until the next + // timeout, or return a spurious connection for the caller to close. + dialer := func(d time.Time) (Conn, error) { + return dialSingle(ctx, ra, d) + } + c, err := dial(ctx.network, ra, dialer, partialDeadline) + if err == nil { + return c, nil + } + if firstErr == nil { + firstErr = err + } + } + + if firstErr == nil { + firstErr = &OpError{Op: "dial", Net: ctx.network, Source: nil, Addr: nil, Err: errMissingAddress} } - return nil, lastErr + return nil, firstErr } // dialSingle attempts to establish and returns a single connection to -// the destination address. -func dialSingle(net, addr string, la, ra Addr, deadline time.Time) (c Conn, err error) { +// the destination address. This must be called through the OS-specific +// dial function, because some OSes don't implement the deadline feature. +func dialSingle(ctx *dialContext, ra Addr, deadline time.Time) (c Conn, err error) { + la := ctx.LocalAddr if la != nil && la.Network() != ra.Network() { - return nil, &OpError{Op: "dial", Net: net, Addr: ra, Err: errors.New("mismatched local address type " + la.Network())} + return nil, &OpError{Op: "dial", Net: ctx.network, Source: la, Addr: ra, Err: errors.New("mismatched local address type " + la.Network())} } switch ra := ra.(type) { case *TCPAddr: la, _ := la.(*TCPAddr) - c, err = dialTCP(net, la, ra, deadline) + c, err = testHookDialTCP(ctx.network, la, ra, deadline) case *UDPAddr: la, _ := la.(*UDPAddr) - c, err = dialUDP(net, la, ra, deadline) + c, err = dialUDP(ctx.network, la, ra, deadline) case *IPAddr: la, _ := la.(*IPAddr) - c, err = dialIP(net, la, ra, deadline) + c, err = dialIP(ctx.network, la, ra, deadline) case *UnixAddr: la, _ := la.(*UnixAddr) - c, err = dialUnix(net, la, ra, deadline) + c, err = dialUnix(ctx.network, la, ra, deadline) default: - return nil, &OpError{Op: "dial", Net: net, Addr: ra, Err: &AddrError{Err: "unexpected address type", Addr: addr}} + return nil, &OpError{Op: "dial", Net: ctx.network, Source: la, Addr: ra, Err: &AddrError{Err: "unexpected address type", Addr: ctx.address}} } if err != nil { return nil, err // c is non-nil interface containing nil pointer @@ -256,18 +385,18 @@ func dialSingle(net, addr string, la, ra Addr, deadline time.Time) (c Conn, err // "tcp6", "unix" or "unixpacket". // See Dial for the syntax of laddr. func Listen(net, laddr string) (Listener, error) { - la, err := resolveAddr("listen", net, laddr, noDeadline) + addrs, err := resolveAddrList("listen", net, laddr, noDeadline) if err != nil { - return nil, &OpError{Op: "listen", Net: net, Addr: nil, Err: err} + return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: nil, Err: err} } var l Listener - switch la := la.toAddr().(type) { + switch la := addrs.first(isIPv4).(type) { case *TCPAddr: l, err = ListenTCP(net, la) case *UnixAddr: l, err = ListenUnix(net, la) default: - return nil, &OpError{Op: "listen", Net: net, Addr: la, Err: &AddrError{Err: "unexpected address type", Addr: laddr}} + return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: la, Err: &AddrError{Err: "unexpected address type", Addr: laddr}} } if err != nil { return nil, err // l is non-nil interface containing nil pointer @@ -280,12 +409,12 @@ func Listen(net, laddr string) (Listener, error) { // "udp6", "ip", "ip4", "ip6" or "unixgram". // See Dial for the syntax of laddr. func ListenPacket(net, laddr string) (PacketConn, error) { - la, err := resolveAddr("listen", net, laddr, noDeadline) + addrs, err := resolveAddrList("listen", net, laddr, noDeadline) if err != nil { - return nil, &OpError{Op: "listen", Net: net, Addr: nil, Err: err} + return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: nil, Err: err} } var l PacketConn - switch la := la.toAddr().(type) { + switch la := addrs.first(isIPv4).(type) { case *UDPAddr: l, err = ListenUDP(net, la) case *IPAddr: @@ -293,7 +422,7 @@ func ListenPacket(net, laddr string) (PacketConn, error) { case *UnixAddr: l, err = ListenUnixgram(net, la) default: - return nil, &OpError{Op: "listen", Net: net, Addr: la, Err: &AddrError{Err: "unexpected address type", Addr: laddr}} + return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: la, Err: &AddrError{Err: "unexpected address type", Addr: laddr}} } if err != nil { return nil, err // l is non-nil interface containing nil pointer diff --git a/libgo/go/net/dial_gen.go b/libgo/go/net/dial_gen.go index ada6233003f..a628f714835 100644 --- a/libgo/go/net/dial_gen.go +++ b/libgo/go/net/dial_gen.go @@ -6,22 +6,18 @@ package net -import ( - "time" -) - -var testingIssue5349 bool // used during tests +import "time" // dialChannel is the simple pure-Go implementation of dial, still // used on operating systems where the deadline hasn't been pushed // down into the pollserver. (Plan 9 and some old versions of Windows) func dialChannel(net string, ra Addr, dialer func(time.Time) (Conn, error), deadline time.Time) (Conn, error) { - var timeout time.Duration - if !deadline.IsZero() { - timeout = deadline.Sub(time.Now()) + if deadline.IsZero() { + return dialer(noDeadline) } + timeout := deadline.Sub(time.Now()) if timeout <= 0 { - return dialer(noDeadline) + return nil, &OpError{Op: "dial", Net: net, Source: nil, Addr: ra, Err: errTimeout} } t := time.NewTimer(timeout) defer t.Stop() @@ -31,15 +27,13 @@ func dialChannel(net string, ra Addr, dialer func(time.Time) (Conn, error), dead } ch := make(chan racer, 1) go func() { - if testingIssue5349 { - time.Sleep(time.Millisecond) - } + testHookDialChannel() c, err := dialer(noDeadline) ch <- racer{c, err} }() select { case <-t.C: - return nil, &OpError{Op: "dial", Net: net, Addr: ra, Err: errTimeout} + return nil, &OpError{Op: "dial", Net: net, Source: nil, Addr: ra, Err: errTimeout} case racer := <-ch: return racer.Conn, racer.error } diff --git a/libgo/go/net/dial_test.go b/libgo/go/net/dial_test.go index 42898d669f7..ed6d7cc42f1 100644 --- a/libgo/go/net/dial_test.go +++ b/libgo/go/net/dial_test.go @@ -5,111 +5,50 @@ package net import ( - "bytes" - "flag" - "fmt" "io" - "os" - "os/exec" - "reflect" - "regexp" + "net/internal/socktest" "runtime" - "strconv" "sync" "testing" "time" ) -func newLocalListener(t *testing.T) Listener { - ln, err := Listen("tcp", "127.0.0.1:0") - if err != nil { - ln, err = Listen("tcp6", "[::1]:0") +var prohibitionaryDialArgTests = []struct { + network string + address string +}{ + {"tcp6", "127.0.0.1"}, + {"tcp6", "::ffff:127.0.0.1"}, +} + +func TestProhibitionaryDialArg(t *testing.T) { + switch runtime.GOOS { + case "plan9": + t.Skipf("not supported on %s", runtime.GOOS) + } + if testing.Short() || !*testExternal { + t.Skip("avoid external network") } + if !supportsIPv4map { + t.Skip("mapping ipv4 address inside ipv6 address not supported") + } + + ln, err := Listen("tcp", "[::]:0") if err != nil { t.Fatal(err) } - return ln -} - -func TestDialTimeout(t *testing.T) { - origBacklog := listenerBacklog - defer func() { - listenerBacklog = origBacklog - }() - listenerBacklog = 1 - - ln := newLocalListener(t) defer ln.Close() - errc := make(chan error) - - numConns := listenerBacklog + 100 + _, port, err := SplitHostPort(ln.Addr().String()) + if err != nil { + t.Fatal(err) + } - // TODO(bradfitz): It's hard to test this in a portable - // way. This is unfortunate, but works for now. - switch runtime.GOOS { - case "linux": - // The kernel will start accepting TCP connections before userspace - // gets a chance to not accept them, so fire off a bunch to fill up - // the kernel's backlog. Then we test we get a failure after that. - for i := 0; i < numConns; i++ { - go func() { - _, err := DialTimeout("tcp", ln.Addr().String(), 200*time.Millisecond) - errc <- err - }() - } - case "darwin", "plan9", "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 - // - go func() { - 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: - // TODO(bradfitz): - // OpenBSD may have a reject route to 127/8 except 127.0.0.1/32 - // by default. FreeBSD likely works, but is untested. - // TODO(rsc): - // The timeout never happens on Windows. Why? Issue 3016. - t.Skipf("skipping test on %q; untested.", runtime.GOOS) - } - - connected := 0 - for { - select { - case <-time.After(15 * time.Second): - t.Fatal("too slow") - case err := <-errc: - if err == nil { - connected++ - if connected == numConns { - t.Fatal("all connections connected; expected some to time out") - } - } else { - terr, ok := err.(timeout) - if !ok { - t.Fatalf("got error %q; want error with timeout interface", err) - } - if !terr.Timeout() { - t.Fatalf("got error %q; not a timeout", err) - } - // Pass. We saw a timeout error. - return - } + for i, tt := range prohibitionaryDialArgTests { + c, err := Dial(tt.network, JoinHostPort(tt.address, port)) + if err == nil { + c.Close() + t.Errorf("#%d: %v", i, err) } } } @@ -117,7 +56,7 @@ func TestDialTimeout(t *testing.T) { func TestSelfConnect(t *testing.T) { if runtime.GOOS == "windows" { // TODO(brainman): do not know why it hangs. - t.Skip("skipping known-broken test on windows") + t.Skip("known-broken test on windows") } // Test that Dial does not honor self-connects. @@ -160,303 +99,518 @@ func TestSelfConnect(t *testing.T) { } } -var runErrorTest = flag.Bool("run_error_test", false, "let TestDialError check for dns errors") +func TestDialTimeoutFDLeak(t *testing.T) { + switch runtime.GOOS { + case "plan9": + t.Skipf("%s does not have full support of socktest", runtime.GOOS) + } -type DialErrorTest struct { - Net string - Raddr string - Pattern string -} + const T = 100 * time.Millisecond -var dialErrorTests = []DialErrorTest{ - { - "datakit", "mh/astro/r70", - "dial datakit mh/astro/r70: unknown network datakit", - }, - { - "tcp", "127.0.0.1:☺", - "dial tcp 127.0.0.1:☺: unknown port tcp/☺", - }, - { - "tcp", "no-such-name.google.com.:80", - "dial tcp no-such-name.google.com.:80: lookup no-such-name.google.com.( on .*)?: no (.*)", - }, - { - "tcp", "no-such-name.no-such-top-level-domain.:80", - "dial tcp no-such-name.no-such-top-level-domain.:80: lookup no-such-name.no-such-top-level-domain.( on .*)?: no (.*)", - }, - { - "tcp", "no-such-name:80", - `dial tcp no-such-name:80: lookup no-such-name\.(.*\.)?( on .*)?: no (.*)`, - }, - { - "tcp", "mh/astro/r70:http", - "dial tcp mh/astro/r70:http: lookup mh/astro/r70: invalid domain name", - }, - { - "unix", "/etc/file-not-found", - "dial unix /etc/file-not-found: no such file or directory", - }, - { - "unix", "/etc/", - "dial unix /etc/: (permission denied|socket operation on non-socket|connection refused)", - }, - { - "unixpacket", "/etc/file-not-found", - "dial unixpacket /etc/file-not-found: no such file or directory", - }, - { - "unixpacket", "/etc/", - "dial unixpacket /etc/: (permission denied|socket operation on non-socket|connection refused)", - }, -} + switch runtime.GOOS { + case "plan9", "windows": + origTestHookDialChannel := testHookDialChannel + testHookDialChannel = func() { time.Sleep(2 * T) } + defer func() { testHookDialChannel = origTestHookDialChannel }() + if runtime.GOOS == "plan9" { + break + } + fallthrough + default: + sw.Set(socktest.FilterConnect, func(so *socktest.Status) (socktest.AfterFilter, error) { + time.Sleep(2 * T) + return nil, errTimeout + }) + defer sw.Set(socktest.FilterConnect, nil) + } + + // Avoid tracking open-close jitterbugs between netFD and + // socket that leads to confusion of information inside + // socktest.Switch. + // It may happen when the Dial call bumps against TCP + // simultaneous open. See selfConnect in tcpsock_posix.go. + defer func() { + sw.Set(socktest.FilterClose, nil) + forceCloseSockets() + }() + var mu sync.Mutex + var attempts int + sw.Set(socktest.FilterClose, func(so *socktest.Status) (socktest.AfterFilter, error) { + mu.Lock() + attempts++ + mu.Unlock() + return nil, errTimedout + }) -var duplicateErrorPattern = `dial (.*) dial (.*)` + const N = 100 + var wg sync.WaitGroup + wg.Add(N) + for i := 0; i < N; i++ { + go func() { + defer wg.Done() + // This dial never starts to send any SYN + // segment because of above socket filter and + // test hook. + c, err := DialTimeout("tcp", "127.0.0.1:0", T) + if err == nil { + t.Errorf("unexpectedly established: tcp:%s->%s", c.LocalAddr(), c.RemoteAddr()) + c.Close() + } + }() + } + wg.Wait() + if attempts < N { + t.Errorf("got %d; want >= %d", attempts, N) + } +} -func TestDialError(t *testing.T) { - if !*runErrorTest { - t.Logf("test disabled; use -run_error_test to enable") - return +func TestDialerDualStackFDLeak(t *testing.T) { + switch runtime.GOOS { + case "plan9": + t.Skipf("%s does not have full support of socktest", runtime.GOOS) + case "windows": + t.Skipf("not implemented a way to cancel dial racers in TCP SYN-SENT state on %s", runtime.GOOS) } - for i, tt := range dialErrorTests { - c, err := Dial(tt.Net, tt.Raddr) - if c != nil { + if !supportsIPv4 || !supportsIPv6 { + t.Skip("both IPv4 and IPv6 are required") + } + + origTestHookLookupIP := testHookLookupIP + defer func() { testHookLookupIP = origTestHookLookupIP }() + testHookLookupIP = lookupLocalhost + handler := func(dss *dualStackServer, ln Listener) { + for { + c, err := ln.Accept() + if err != nil { + return + } c.Close() } - if err == nil { - t.Errorf("#%d: nil error, want match for %#q", i, tt.Pattern) - continue - } - s := err.Error() - match, _ := regexp.MatchString(tt.Pattern, s) - if !match { - t.Errorf("#%d: %q, want match for %#q", i, s, tt.Pattern) - } - match, _ = regexp.MatchString(duplicateErrorPattern, s) - if match { - t.Errorf("#%d: %q, duplicate error return from Dial", i, s) - } + } + dss, err := newDualStackServer([]streamListener{ + {network: "tcp4", address: "127.0.0.1"}, + {network: "tcp6", address: "::1"}, + }) + if err != nil { + t.Fatal(err) + } + defer dss.teardown() + if err := dss.buildup(handler); err != nil { + t.Fatal(err) + } + + before := sw.Sockets() + const T = 100 * time.Millisecond + const N = 10 + var wg sync.WaitGroup + wg.Add(N) + d := &Dialer{DualStack: true, Timeout: T} + for i := 0; i < N; i++ { + go func() { + defer wg.Done() + c, err := d.Dial("tcp", JoinHostPort("localhost", dss.port)) + if err != nil { + t.Error(err) + return + } + c.Close() + }() + } + wg.Wait() + time.Sleep(2 * T) // wait for the dial racers to stop + after := sw.Sockets() + if len(after) != len(before) { + t.Errorf("got %d; want %d", len(after), len(before)) } } -var invalidDialAndListenArgTests = []struct { - net string - addr string - err error -}{ - {"foo", "bar", &OpError{Op: "dial", Net: "foo", Addr: nil, Err: UnknownNetworkError("foo")}}, - {"baz", "", &OpError{Op: "listen", Net: "baz", Addr: nil, Err: UnknownNetworkError("baz")}}, - {"tcp", "", &OpError{Op: "dial", Net: "tcp", Addr: nil, Err: errMissingAddress}}, +// Define a pair of blackholed (IPv4, IPv6) addresses, for which dialTCP is +// expected to hang until the timeout elapses. These addresses are reserved +// for benchmarking by RFC 6890. +const ( + slowDst4 = "192.18.0.254" + slowDst6 = "2001:2::254" + slowTimeout = 1 * time.Second +) + +// In some environments, the slow IPs may be explicitly unreachable, and fail +// more quickly than expected. This test hook prevents dialTCP from returning +// before the deadline. +func slowDialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time) (*TCPConn, error) { + c, err := dialTCP(net, laddr, raddr, deadline) + if ParseIP(slowDst4).Equal(raddr.IP) || ParseIP(slowDst6).Equal(raddr.IP) { + time.Sleep(deadline.Sub(time.Now())) + } + return c, err } -func TestInvalidDialAndListenArgs(t *testing.T) { - for _, tt := range invalidDialAndListenArgTests { - var err error - switch tt.err.(*OpError).Op { - case "dial": - _, err = Dial(tt.net, tt.addr) - case "listen": - _, err = Listen(tt.net, tt.addr) +func dialClosedPort() (actual, expected time.Duration) { + // Estimate the expected time for this platform. + // On Windows, dialing a closed port takes roughly 1 second, + // but other platforms should be instantaneous. + if runtime.GOOS == "windows" { + expected = 1500 * time.Millisecond + } else { + expected = 95 * time.Millisecond + } + + l, err := Listen("tcp", "127.0.0.1:0") + if err != nil { + return 999 * time.Hour, expected + } + addr := l.Addr().String() + l.Close() + // On OpenBSD, interference from TestSelfConnect is mysteriously + // causing the first attempt to hang for a few seconds, so we throw + // away the first result and keep the second. + for i := 1; ; i++ { + startTime := time.Now() + c, err := Dial("tcp", addr) + if err == nil { + c.Close() } - if !reflect.DeepEqual(tt.err, err) { - t.Fatalf("got %#v; expected %#v", err, tt.err) + elapsed := time.Now().Sub(startTime) + if i == 2 { + return elapsed, expected } } } -func TestDialTimeoutFDLeak(t *testing.T) { - if runtime.GOOS != "linux" { - // TODO(bradfitz): test on other platforms - t.Skipf("skipping test on %q", runtime.GOOS) +func TestDialParallel(t *testing.T) { + if testing.Short() || !*testExternal { + t.Skip("avoid external network") + } + if !supportsIPv4 || !supportsIPv6 { + t.Skip("both IPv4 and IPv6 are required") } - ln := newLocalListener(t) - defer ln.Close() - - type connErr struct { - conn Conn - err error + closedPortDelay, expectClosedPortDelay := dialClosedPort() + if closedPortDelay > expectClosedPortDelay { + t.Errorf("got %v; want <= %v", closedPortDelay, expectClosedPortDelay) } - dials := listenerBacklog + 100 - // used to be listenerBacklog + 5, but was found to be unreliable, issue 4384. - maxGoodConnect := listenerBacklog + runtime.NumCPU()*10 - resc := make(chan connErr) - for i := 0; i < dials; i++ { - go func() { - conn, err := DialTimeout("tcp", ln.Addr().String(), 500*time.Millisecond) - resc <- connErr{conn, err} - }() + + const instant time.Duration = 0 + const fallbackDelay = 200 * time.Millisecond + + // Some cases will run quickly when "connection refused" is fast, + // or trigger the fallbackDelay on Windows. This value holds the + // lesser of the two delays. + var closedPortOrFallbackDelay time.Duration + if closedPortDelay < fallbackDelay { + closedPortOrFallbackDelay = closedPortDelay + } else { + closedPortOrFallbackDelay = fallbackDelay } - var firstErr string - var ngood int - var toClose []io.Closer - for i := 0; i < dials; i++ { - ce := <-resc - if ce.err == nil { - ngood++ - if ngood > maxGoodConnect { - t.Errorf("%d good connects; expected at most %d", ngood, maxGoodConnect) - } - toClose = append(toClose, ce.conn) - continue + origTestHookDialTCP := testHookDialTCP + defer func() { testHookDialTCP = origTestHookDialTCP }() + testHookDialTCP = slowDialTCP + + nCopies := func(s string, n int) []string { + out := make([]string, n) + for i := 0; i < n; i++ { + out[i] = s } - err := ce.err - if firstErr == "" { - firstErr = err.Error() - } else if err.Error() != firstErr { - t.Fatalf("inconsistent error messages: first was %q, then later %q", firstErr, err) + return out + } + + var testCases = []struct { + primaries []string + fallbacks []string + teardownNetwork string + expectOk bool + expectElapsed time.Duration + }{ + // These should just work on the first try. + {[]string{"127.0.0.1"}, []string{}, "", true, instant}, + {[]string{"::1"}, []string{}, "", true, instant}, + {[]string{"127.0.0.1", "::1"}, []string{slowDst6}, "tcp6", true, instant}, + {[]string{"::1", "127.0.0.1"}, []string{slowDst4}, "tcp4", true, instant}, + // Primary is slow; fallback should kick in. + {[]string{slowDst4}, []string{"::1"}, "", true, fallbackDelay}, + // Skip a "connection refused" in the primary thread. + {[]string{"127.0.0.1", "::1"}, []string{}, "tcp4", true, closedPortDelay}, + {[]string{"::1", "127.0.0.1"}, []string{}, "tcp6", true, closedPortDelay}, + // Skip a "connection refused" in the fallback thread. + {[]string{slowDst4, slowDst6}, []string{"::1", "127.0.0.1"}, "tcp6", true, fallbackDelay + closedPortDelay}, + // Primary refused, fallback without delay. + {[]string{"127.0.0.1"}, []string{"::1"}, "tcp4", true, closedPortOrFallbackDelay}, + {[]string{"::1"}, []string{"127.0.0.1"}, "tcp6", true, closedPortOrFallbackDelay}, + // Everything is refused. + {[]string{"127.0.0.1"}, []string{}, "tcp4", false, closedPortDelay}, + // Nothing to do; fail instantly. + {[]string{}, []string{}, "", false, instant}, + // Connecting to tons of addresses should not trip the deadline. + {nCopies("::1", 1000), []string{}, "", true, instant}, + } + + handler := func(dss *dualStackServer, ln Listener) { + for { + c, err := ln.Accept() + if err != nil { + return + } + c.Close() } } - for _, c := range toClose { - c.Close() - } - for i := 0; i < 100; i++ { - if got := numFD(); got < dials { - // Test passes. - return + + // Convert a list of IP strings into TCPAddrs. + makeAddrs := func(ips []string, port string) addrList { + var out addrList + for _, ip := range ips { + addr, err := ResolveTCPAddr("tcp", JoinHostPort(ip, port)) + if err != nil { + t.Fatal(err) + } + out = append(out, addr) } - time.Sleep(10 * time.Millisecond) + return out } - if got := numFD(); got >= dials { - t.Errorf("num fds after %d timeouts = %d; want <%d", dials, got, dials) + + for i, tt := range testCases { + dss, err := newDualStackServer([]streamListener{ + {network: "tcp4", address: "127.0.0.1"}, + {network: "tcp6", address: "::1"}, + }) + if err != nil { + t.Fatal(err) + } + defer dss.teardown() + if err := dss.buildup(handler); err != nil { + t.Fatal(err) + } + if tt.teardownNetwork != "" { + // Destroy one of the listening sockets, creating an unreachable port. + dss.teardownNetwork(tt.teardownNetwork) + } + + primaries := makeAddrs(tt.primaries, dss.port) + fallbacks := makeAddrs(tt.fallbacks, dss.port) + d := Dialer{ + FallbackDelay: fallbackDelay, + Timeout: slowTimeout, + } + ctx := &dialContext{ + Dialer: d, + network: "tcp", + address: "?", + finalDeadline: d.deadline(time.Now()), + } + startTime := time.Now() + c, err := dialParallel(ctx, primaries, fallbacks) + elapsed := time.Now().Sub(startTime) + + if c != nil { + c.Close() + } + + if tt.expectOk && err != nil { + t.Errorf("#%d: got %v; want nil", i, err) + } else if !tt.expectOk && err == nil { + t.Errorf("#%d: got nil; want non-nil", i) + } + + expectElapsedMin := tt.expectElapsed - 95*time.Millisecond + expectElapsedMax := tt.expectElapsed + 95*time.Millisecond + if !(elapsed >= expectElapsedMin) { + t.Errorf("#%d: got %v; want >= %v", i, elapsed, expectElapsedMin) + } else if !(elapsed <= expectElapsedMax) { + t.Errorf("#%d: got %v; want <= %v", i, elapsed, expectElapsedMax) + } } + // Wait for any slowDst4/slowDst6 connections to timeout. + time.Sleep(slowTimeout * 3 / 2) } -func numTCP() (ntcp, nopen, nclose int, err error) { - lsof, err := exec.Command("lsof", "-n", "-p", strconv.Itoa(os.Getpid())).Output() - if err != nil { - return 0, 0, 0, err +func lookupSlowFast(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, error) { + switch host { + case "slow6loopback4": + // Returns a slow IPv6 address, and a local IPv4 address. + return []IPAddr{ + {IP: ParseIP(slowDst6)}, + {IP: ParseIP("127.0.0.1")}, + }, nil + default: + return fn(host) } - ntcp += bytes.Count(lsof, []byte("TCP")) - for _, state := range []string{"LISTEN", "SYN_SENT", "SYN_RECEIVED", "ESTABLISHED"} { - nopen += bytes.Count(lsof, []byte(state)) +} + +func TestDialerFallbackDelay(t *testing.T) { + if testing.Short() || !*testExternal { + t.Skip("avoid external network") } - for _, state := range []string{"CLOSED", "CLOSE_WAIT", "LAST_ACK", "FIN_WAIT_1", "FIN_WAIT_2", "CLOSING", "TIME_WAIT"} { - nclose += bytes.Count(lsof, []byte(state)) + if !supportsIPv4 || !supportsIPv6 { + t.Skip("both IPv4 and IPv6 are required") } - return ntcp, nopen, nclose, nil -} -func TestDialMultiFDLeak(t *testing.T) { - t.Skip("flaky test - golang.org/issue/8764") + origTestHookLookupIP := testHookLookupIP + defer func() { testHookLookupIP = origTestHookLookupIP }() + testHookLookupIP = lookupSlowFast - if !supportsIPv4 || !supportsIPv6 { - t.Skip("neither ipv4 nor ipv6 is supported") + origTestHookDialTCP := testHookDialTCP + defer func() { testHookDialTCP = origTestHookDialTCP }() + testHookDialTCP = slowDialTCP + + var testCases = []struct { + dualstack bool + delay time.Duration + expectElapsed time.Duration + }{ + // Use a very brief delay, which should fallback immediately. + {true, 1 * time.Nanosecond, 0}, + // Use a 200ms explicit timeout. + {true, 200 * time.Millisecond, 200 * time.Millisecond}, + // The default is 300ms. + {true, 0, 300 * time.Millisecond}, + // This case is last, in order to wait for hanging slowDst6 connections. + {false, 0, slowTimeout}, } - halfDeadServer := func(dss *dualStackServer, ln Listener) { + handler := func(dss *dualStackServer, ln Listener) { for { - if c, err := ln.Accept(); err != nil { + c, err := ln.Accept() + if err != nil { return - } else { - // It just keeps established - // connections like a half-dead server - // does. - dss.putConn(c) } + c.Close() } } dss, err := newDualStackServer([]streamListener{ - {net: "tcp4", addr: "127.0.0.1"}, - {net: "tcp6", addr: "[::1]"}, + {network: "tcp", address: "127.0.0.1"}, }) if err != nil { - t.Fatalf("newDualStackServer failed: %v", err) + t.Fatal(err) } defer dss.teardown() - if err := dss.buildup(halfDeadServer); err != nil { - t.Fatalf("dualStackServer.buildup failed: %v", err) + if err := dss.buildup(handler); err != nil { + t.Fatal(err) } - _, before, _, err := numTCP() + for i, tt := range testCases { + d := &Dialer{DualStack: tt.dualstack, FallbackDelay: tt.delay, Timeout: slowTimeout} + + startTime := time.Now() + c, err := d.Dial("tcp", JoinHostPort("slow6loopback4", dss.port)) + elapsed := time.Now().Sub(startTime) + if err == nil { + c.Close() + } else if tt.dualstack { + t.Error(err) + } + expectMin := tt.expectElapsed - 1*time.Millisecond + expectMax := tt.expectElapsed + 95*time.Millisecond + if !(elapsed >= expectMin) { + t.Errorf("#%d: got %v; want >= %v", i, elapsed, expectMin) + } + if !(elapsed <= expectMax) { + t.Errorf("#%d: got %v; want <= %v", i, elapsed, expectMax) + } + } +} + +func TestDialSerialAsyncSpuriousConnection(t *testing.T) { + ln, err := newLocalListener("tcp") if err != nil { - t.Skipf("skipping test; error finding or running lsof: %v", err) + t.Fatal(err) } + defer ln.Close() - var wg sync.WaitGroup - portnum, _, _ := dtoi(dss.port, 0) - ras := addrList{ - // Losers that will fail to connect, see RFC 6890. - &TCPAddr{IP: IPv4(198, 18, 0, 254), Port: portnum}, - &TCPAddr{IP: ParseIP("2001:2::254"), Port: portnum}, - - // Winner candidates of this race. - &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: portnum}, - &TCPAddr{IP: IPv6loopback, Port: portnum}, - - // Losers that will have established connections. - &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: portnum}, - &TCPAddr{IP: IPv6loopback, Port: portnum}, - } - const T1 = 10 * time.Millisecond - const T2 = 2 * T1 - const N = 10 - for i := 0; i < N; i++ { - wg.Add(1) - go func() { - defer wg.Done() - if c, err := dialMulti("tcp", "fast failover test", nil, ras, time.Now().Add(T1)); err == nil { - c.Close() - } - }() + d := Dialer{} + ctx := &dialContext{ + Dialer: d, + network: "tcp", + address: "?", + finalDeadline: d.deadline(time.Now()), } - wg.Wait() - time.Sleep(T2) - ntcp, after, nclose, err := numTCP() + results := make(chan dialResult) + cancel := make(chan struct{}) + + // Spawn a connection in the background. + go dialSerialAsync(ctx, addrList{ln.Addr()}, nil, cancel, results) + + // Receive it at the server. + c, err := ln.Accept() if err != nil { - t.Skipf("skipping test; error finding or running lsof: %v", err) + t.Fatal(err) } - t.Logf("tcp sessions: %v, open sessions: %v, closing sessions: %v", ntcp, after, nclose) + defer c.Close() - if after != before { - t.Fatalf("got %v open sessions; expected %v", after, before) + // Tell dialSerialAsync that someone else won the race. + close(cancel) + + // The connection should close itself, without sending data. + c.SetReadDeadline(time.Now().Add(1 * time.Second)) + var b [1]byte + if _, err := c.Read(b[:]); err != io.EOF { + t.Errorf("got %v; want %v", err, io.EOF) } } -func numFD() int { - if runtime.GOOS == "linux" { - f, err := os.Open("/proc/self/fd") - if err != nil { - panic(err) +func TestDialerPartialDeadline(t *testing.T) { + now := time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC) + var testCases = []struct { + now time.Time + deadline time.Time + addrs int + expectDeadline time.Time + expectErr error + }{ + // Regular division. + {now, now.Add(12 * time.Second), 1, now.Add(12 * time.Second), nil}, + {now, now.Add(12 * time.Second), 2, now.Add(6 * time.Second), nil}, + {now, now.Add(12 * time.Second), 3, now.Add(4 * time.Second), nil}, + // Bump against the 2-second sane minimum. + {now, now.Add(12 * time.Second), 999, now.Add(2 * time.Second), nil}, + // Total available is now below the sane minimum. + {now, now.Add(1900 * time.Millisecond), 999, now.Add(1900 * time.Millisecond), nil}, + // Null deadline. + {now, noDeadline, 1, noDeadline, nil}, + // Step the clock forward and cross the deadline. + {now.Add(-1 * time.Millisecond), now, 1, now, nil}, + {now.Add(0 * time.Millisecond), now, 1, noDeadline, errTimeout}, + {now.Add(1 * time.Millisecond), now, 1, noDeadline, errTimeout}, + } + for i, tt := range testCases { + deadline, err := partialDeadline(tt.now, tt.deadline, tt.addrs) + if err != tt.expectErr { + t.Errorf("#%d: got %v; want %v", i, err, tt.expectErr) } - defer f.Close() - names, err := f.Readdirnames(0) - if err != nil { - panic(err) + if deadline != tt.expectDeadline { + t.Errorf("#%d: got %v; want %v", i, deadline, tt.expectDeadline) } - return len(names) } - // All tests using this should be skipped anyway, but: - panic("numFDs not implemented on " + runtime.GOOS) } -func TestDialer(t *testing.T) { - ln, err := Listen("tcp4", "127.0.0.1:0") - if err != nil { - t.Fatalf("Listen failed: %v", err) - } - defer ln.Close() +func TestDialerLocalAddr(t *testing.T) { ch := make(chan error, 1) - go func() { + handler := func(ls *localServer, ln Listener) { c, err := ln.Accept() if err != nil { - ch <- fmt.Errorf("Accept failed: %v", err) + ch <- err return } defer c.Close() ch <- nil - }() + } + ls, err := newLocalServer("tcp") + if err != nil { + t.Fatal(err) + } + defer ls.teardown() + if err := ls.buildup(handler); err != nil { + t.Fatal(err) + } - laddr, err := ResolveTCPAddr("tcp4", "127.0.0.1:0") + laddr, err := ResolveTCPAddr(ls.Listener.Addr().Network(), ls.Listener.Addr().String()) if err != nil { - t.Fatalf("ResolveTCPAddr failed: %v", err) + t.Fatal(err) } + laddr.Port = 0 d := &Dialer{LocalAddr: laddr} - c, err := d.Dial("tcp4", ln.Addr().String()) + c, err := d.Dial(ls.Listener.Addr().Network(), ls.Addr().String()) if err != nil { - t.Fatalf("Dial failed: %v", err) + t.Fatal(err) } defer c.Close() c.Read(make([]byte, 1)) @@ -466,61 +620,64 @@ func TestDialer(t *testing.T) { } } -func TestDialDualStackLocalhost(t *testing.T) { - switch runtime.GOOS { - case "nacl": - t.Skipf("skipping test on %q", runtime.GOOS) +func TestDialerDualStack(t *testing.T) { + if !supportsIPv4 || !supportsIPv6 { + t.Skip("both IPv4 and IPv6 are required") } - if ips, err := LookupIP("localhost"); err != nil { - t.Fatalf("LookupIP failed: %v", err) - } else if len(ips) < 2 || !supportsIPv4 || !supportsIPv6 { - t.Skip("localhost doesn't have a pair of different address family IP addresses") + closedPortDelay, expectClosedPortDelay := dialClosedPort() + if closedPortDelay > expectClosedPortDelay { + t.Errorf("got %v; want <= %v", closedPortDelay, expectClosedPortDelay) } - touchAndByeServer := func(dss *dualStackServer, ln Listener) { + origTestHookLookupIP := testHookLookupIP + defer func() { testHookLookupIP = origTestHookLookupIP }() + testHookLookupIP = lookupLocalhost + handler := func(dss *dualStackServer, ln Listener) { for { - if c, err := ln.Accept(); err != nil { + c, err := ln.Accept() + if err != nil { return - } else { - c.Close() } + c.Close() } } - dss, err := newDualStackServer([]streamListener{ - {net: "tcp4", addr: "127.0.0.1"}, - {net: "tcp6", addr: "[::1]"}, - }) - if err != nil { - t.Fatalf("newDualStackServer failed: %v", err) - } - defer dss.teardown() - if err := dss.buildup(touchAndByeServer); err != nil { - t.Fatalf("dualStackServer.buildup failed: %v", err) - } - d := &Dialer{DualStack: true} - for range dss.lns { - if c, err := d.Dial("tcp", "localhost:"+dss.port); err != nil { - t.Errorf("Dial failed: %v", err) - } else { - if addr := c.LocalAddr().(*TCPAddr); addr.IP.To4() != nil { + var timeout = 100*time.Millisecond + closedPortDelay + for _, dualstack := range []bool{false, true} { + dss, err := newDualStackServer([]streamListener{ + {network: "tcp4", address: "127.0.0.1"}, + {network: "tcp6", address: "::1"}, + }) + if err != nil { + t.Fatal(err) + } + defer dss.teardown() + if err := dss.buildup(handler); err != nil { + t.Fatal(err) + } + + d := &Dialer{DualStack: dualstack, Timeout: timeout} + for range dss.lns { + c, err := d.Dial("tcp", JoinHostPort("localhost", dss.port)) + if err != nil { + t.Error(err) + continue + } + switch addr := c.LocalAddr().(*TCPAddr); { + case addr.IP.To4() != nil: dss.teardownNetwork("tcp4") - } else if addr.IP.To16() != nil && addr.IP.To4() == nil { + case addr.IP.To16() != nil && addr.IP.To4() == nil: dss.teardownNetwork("tcp6") } c.Close() } } + time.Sleep(timeout * 3 / 2) // wait for the dial racers to stop } func TestDialerKeepAlive(t *testing.T) { - ln := newLocalListener(t) - defer ln.Close() - defer func() { - testHookSetKeepAlive = func() {} - }() - go func() { + handler := func(ls *localServer, ln Listener) { for { c, err := ln.Accept() if err != nil { @@ -528,7 +685,17 @@ func TestDialerKeepAlive(t *testing.T) { } c.Close() } - }() + } + ls, err := newLocalServer("tcp") + if err != nil { + t.Fatal(err) + } + defer ls.teardown() + if err := ls.buildup(handler); err != nil { + t.Fatal(err) + } + defer func() { testHookSetKeepAlive = func() {} }() + for _, keepAlive := range []bool{false, true} { got := false testHookSetKeepAlive = func() { got = true } @@ -536,7 +703,7 @@ func TestDialerKeepAlive(t *testing.T) { if keepAlive { d.KeepAlive = 30 * time.Second } - c, err := d.Dial("tcp", ln.Addr().String()) + c, err := d.Dial("tcp", ls.Listener.Addr().String()) if err != nil { t.Fatal(err) } diff --git a/libgo/go/net/dialgoogle_test.go b/libgo/go/net/dialgoogle_test.go deleted file mode 100644 index df5895afa74..00000000000 --- a/libgo/go/net/dialgoogle_test.go +++ /dev/null @@ -1,209 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package net - -import ( - "flag" - "fmt" - "io" - "strings" - "syscall" - "testing" -) - -// If an IPv6 tunnel is running, we can try dialing a real IPv6 address. -var testIPv6 = flag.Bool("ipv6", false, "assume ipv6 tunnel is present") - -func TestResolveGoogle(t *testing.T) { - if testing.Short() || !*testExternal { - t.Skip("skipping test to avoid external network") - } - - for _, network := range []string{"tcp", "tcp4", "tcp6"} { - addr, err := ResolveTCPAddr(network, "www.google.com:http") - if err != nil { - if (network == "tcp" || network == "tcp4") && !supportsIPv4 { - t.Logf("ipv4 is not supported: %v", err) - } else if network == "tcp6" && !supportsIPv6 { - t.Logf("ipv6 is not supported: %v", err) - } else { - t.Errorf("ResolveTCPAddr failed: %v", err) - } - continue - } - if (network == "tcp" || network == "tcp4") && addr.IP.To4() == nil { - t.Errorf("got %v; expected an IPv4 address on %v", addr, network) - } else if network == "tcp6" && (addr.IP.To16() == nil || addr.IP.To4() != nil) { - t.Errorf("got %v; expected an IPv6 address on %v", addr, network) - } - } -} - -func TestDialGoogle(t *testing.T) { - if testing.Short() || !*testExternal { - t.Skip("skipping test to avoid external network") - } - - d := &Dialer{DualStack: true} - for _, network := range []string{"tcp", "tcp4", "tcp6"} { - if network == "tcp" && !supportsIPv4 && !supportsIPv6 { - t.Logf("skipping test; both ipv4 and ipv6 are not supported") - continue - } else if network == "tcp4" && !supportsIPv4 { - t.Logf("skipping test; ipv4 is not supported") - continue - } else if network == "tcp6" && !supportsIPv6 { - t.Logf("skipping test; ipv6 is not supported") - continue - } else if network == "tcp6" && !*testIPv6 { - t.Logf("test disabled; use -ipv6 to enable") - continue - } - if c, err := d.Dial(network, "www.google.com:http"); err != nil { - t.Errorf("Dial failed: %v", err) - } else { - c.Close() - } - } -} - -// fd is already connected to the destination, port 80. -// Run an HTTP request to fetch the appropriate page. -func fetchGoogle(t *testing.T, fd Conn, network, addr string) { - req := []byte("GET /robots.txt HTTP/1.0\r\nHost: www.google.com\r\n\r\n") - n, err := fd.Write(req) - - buf := make([]byte, 1000) - n, err = io.ReadFull(fd, buf) - - if n < 1000 { - t.Errorf("fetchGoogle: short HTTP read from %s %s - %v", network, addr, err) - return - } -} - -func doDial(t *testing.T, network, addr string) { - fd, err := Dial(network, addr) - if err != nil { - t.Errorf("Dial(%q, %q, %q) = _, %v", network, "", addr, err) - return - } - fetchGoogle(t, fd, network, addr) - fd.Close() -} - -var googleaddrsipv4 = []string{ - "%d.%d.%d.%d:80", - "www.google.com:80", - "%d.%d.%d.%d:http", - "www.google.com:http", - "%03d.%03d.%03d.%03d:0080", - "[::ffff:%d.%d.%d.%d]:80", - "[::ffff:%02x%02x:%02x%02x]:80", - "[0:0:0:0:0000:ffff:%d.%d.%d.%d]:80", - "[0:0:0:0:000000:ffff:%d.%d.%d.%d]:80", - "[0:0:0:0::ffff:%d.%d.%d.%d]:80", -} - -func TestDialGoogleIPv4(t *testing.T) { - if testing.Short() || !*testExternal { - t.Skip("skipping test to avoid external network") - } - - // Insert an actual IPv4 address for google.com - // into the table. - addrs, err := LookupIP("www.google.com") - if err != nil { - t.Fatalf("lookup www.google.com: %v", err) - } - var ip IP - for _, addr := range addrs { - if x := addr.To4(); x != nil { - ip = x - break - } - } - if ip == nil { - t.Fatalf("no IPv4 addresses for www.google.com") - } - - for i, s := range googleaddrsipv4 { - if strings.Contains(s, "%") { - googleaddrsipv4[i] = fmt.Sprintf(s, ip[0], ip[1], ip[2], ip[3]) - } - } - - for i := 0; i < len(googleaddrsipv4); i++ { - addr := googleaddrsipv4[i] - if addr == "" { - continue - } - t.Logf("-- %s --", addr) - doDial(t, "tcp", addr) - if addr[0] != '[' { - doDial(t, "tcp4", addr) - if supportsIPv6 { - // make sure syscall.SocketDisableIPv6 flag works. - syscall.SocketDisableIPv6 = true - doDial(t, "tcp", addr) - doDial(t, "tcp4", addr) - syscall.SocketDisableIPv6 = false - } - } - } -} - -var googleaddrsipv6 = []string{ - "[%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:80", - "ipv6.google.com:80", - "[%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:http", - "ipv6.google.com:http", -} - -func TestDialGoogleIPv6(t *testing.T) { - if testing.Short() || !*testExternal { - t.Skip("skipping test to avoid external network") - } - // Only run tcp6 if the kernel will take it. - if !supportsIPv6 { - t.Skip("skipping test; ipv6 is not supported") - } - if !*testIPv6 { - t.Skip("test disabled; use -ipv6 to enable") - } - - // Insert an actual IPv6 address for ipv6.google.com - // into the table. - addrs, err := LookupIP("ipv6.google.com") - if err != nil { - t.Fatalf("lookup ipv6.google.com: %v", err) - } - var ip IP - for _, addr := range addrs { - if x := addr.To16(); x != nil { - ip = x - break - } - } - if ip == nil { - t.Fatalf("no IPv6 addresses for ipv6.google.com") - } - - for i, s := range googleaddrsipv6 { - if strings.Contains(s, "%") { - googleaddrsipv6[i] = fmt.Sprintf(s, ip[0], ip[1], ip[2], ip[3], ip[4], ip[5], ip[6], ip[7], ip[8], ip[9], ip[10], ip[11], ip[12], ip[13], ip[14], ip[15]) - } - } - - for i := 0; i < len(googleaddrsipv6); i++ { - addr := googleaddrsipv6[i] - if addr == "" { - continue - } - t.Logf("-- %s --", addr) - doDial(t, "tcp", addr) - doDial(t, "tcp6", addr) - } -} diff --git a/libgo/go/net/dnsclient.go b/libgo/go/net/dnsclient.go index e8014e4ffc9..ce48521bc60 100644 --- a/libgo/go/net/dnsclient.go +++ b/libgo/go/net/dnsclient.go @@ -9,31 +9,6 @@ import ( "sort" ) -// DNSError represents a DNS lookup error. -type DNSError struct { - Err string // description of the error - Name string // name looked for - Server string // server used - IsTimeout bool -} - -func (e *DNSError) Error() string { - if e == nil { - return "" - } - s := "lookup " + e.Name - if e.Server != "" { - s += " on " + e.Server - } - s += ": " + e.Err - return s -} - -func (e *DNSError) Timeout() bool { return e.IsTimeout } -func (e *DNSError) Temporary() bool { return e.IsTimeout } - -const noSuchHost = "no such host" - // reverseaddr returns the in-addr.arpa. or ip6.arpa. hostname of the IP // address addr suitable for rDNS (PTR) record lookup or an error if it fails // to parse the IP address. @@ -43,8 +18,7 @@ func reverseaddr(addr string) (arpa string, err error) { return "", &DNSError{Err: "unrecognized address", Name: addr} } if ip.To4() != nil { - return itoa(int(ip[15])) + "." + itoa(int(ip[14])) + "." + itoa(int(ip[13])) + "." + - itoa(int(ip[12])) + ".in-addr.arpa.", nil + return uitoa(uint(ip[15])) + "." + uitoa(uint(ip[14])) + "." + uitoa(uint(ip[13])) + "." + uitoa(uint(ip[12])) + ".in-addr.arpa.", nil } // Must be IPv6 buf := make([]byte, 0, len(ip)*4+len("ip6.arpa.")) @@ -67,7 +41,7 @@ func answer(name, server string, dns *dnsMsg, qtype uint16) (cname string, addrs addrs = make([]dnsRR, 0, len(dns.answer)) if dns.rcode == dnsRcodeNameError && dns.recursion_available { - return "", nil, &DNSError{Err: noSuchHost, Name: name} + return "", nil, &DNSError{Err: errNoSuchHost.Error(), Name: name, Server: server} } if dns.rcode != dnsRcodeSuccess { // None of the error codes make sense @@ -94,7 +68,7 @@ Cname: continue } h := rr.Header() - if h.Class == dnsClassINET && h.Name == name { + if h.Class == dnsClassINET && equalASCIILabel(h.Name, name) { switch h.Rrtype { case qtype: addrs = append(addrs, rr) @@ -106,7 +80,7 @@ Cname: } } if len(addrs) == 0 { - return "", nil, &DNSError{Err: noSuchHost, Name: name, Server: server} + return "", nil, &DNSError{Err: errNoSuchHost.Error(), Name: name, Server: server} } return name, addrs, nil } @@ -114,6 +88,26 @@ Cname: return "", nil, &DNSError{Err: "too many redirects", Name: name, Server: server} } +func equalASCIILabel(x, y string) bool { + if len(x) != len(y) { + return false + } + for i := 0; i < len(x); i++ { + a := x[i] + b := y[i] + if 'A' <= a && a <= 'Z' { + a += 0x20 + } + if 'A' <= b && b <= 'Z' { + b += 0x20 + } + if a != b { + return false + } + } + return true +} + func isDomainName(s string) bool { // See RFC 1035, RFC 3696. if len(s) == 0 { @@ -174,13 +168,10 @@ type SRV struct { type byPriorityWeight []*SRV func (s byPriorityWeight) Len() int { return len(s) } - -func (s byPriorityWeight) Swap(i, j int) { s[i], s[j] = s[j], s[i] } - func (s byPriorityWeight) Less(i, j int) bool { - return s[i].Priority < s[j].Priority || - (s[i].Priority == s[j].Priority && s[i].Weight < s[j].Weight) + return s[i].Priority < s[j].Priority || (s[i].Priority == s[j].Priority && s[i].Weight < s[j].Weight) } +func (s byPriorityWeight) Swap(i, j int) { s[i], s[j] = s[j], s[i] } // shuffleByWeight shuffles SRV records by weight using the algorithm // described in RFC 2782. @@ -228,11 +219,9 @@ type MX struct { // byPref implements sort.Interface to sort MX records by preference type byPref []*MX -func (s byPref) Len() int { return len(s) } - +func (s byPref) Len() int { return len(s) } func (s byPref) Less(i, j int) bool { return s[i].Pref < s[j].Pref } - -func (s byPref) Swap(i, j int) { s[i], s[j] = s[j], s[i] } +func (s byPref) Swap(i, j int) { s[i], s[j] = s[j], s[i] } // sort reorders MX records as specified in RFC 5321. func (s byPref) sort() { diff --git a/libgo/go/net/dnsclient_test.go b/libgo/go/net/dnsclient_test.go index 435eb35506e..3ab2b836ef6 100644 --- a/libgo/go/net/dnsclient_test.go +++ b/libgo/go/net/dnsclient_test.go @@ -47,7 +47,7 @@ func testUniformity(t *testing.T, size int, margin float64) { checkDistribution(t, data, margin) } -func TestUniformity(t *testing.T) { +func TestDNSSRVUniformity(t *testing.T) { testUniformity(t, 2, 0.05) testUniformity(t, 3, 0.10) testUniformity(t, 10, 0.20) diff --git a/libgo/go/net/dnsclient_unix.go b/libgo/go/net/dnsclient_unix.go index 7511083f795..c03c1b1159f 100644 --- a/libgo/go/net/dnsclient_unix.go +++ b/libgo/go/net/dnsclient_unix.go @@ -20,6 +20,7 @@ import ( "io" "math/rand" "os" + "strconv" "sync" "time" ) @@ -184,9 +185,9 @@ func tryOneName(cfg *dnsConfig, name string, qtype uint16) (string, []dnsRR, err } continue } - cname, addrs, err := answer(name, server, msg, qtype) - if err == nil || err.(*DNSError).Err == noSuchHost { - return cname, addrs, err + cname, rrs, err := answer(name, server, msg, qtype) + if err == nil || msg.rcode == dnsRcodeSuccess || msg.rcode == dnsRcodeNameError && msg.recursion_available { + return cname, rrs, err } lastErr = err } @@ -194,144 +195,188 @@ func tryOneName(cfg *dnsConfig, name string, qtype uint16) (string, []dnsRR, err return "", nil, lastErr } -func convertRR_A(records []dnsRR) []IP { - addrs := make([]IP, len(records)) - for i, rr := range records { - a := rr.(*dnsRR_A).A - addrs[i] = IPv4(byte(a>>24), byte(a>>16), byte(a>>8), byte(a)) +// addrRecordList converts and returns a list of IP addresses from DNS +// address records (both A and AAAA). Other record types are ignored. +func addrRecordList(rrs []dnsRR) []IPAddr { + addrs := make([]IPAddr, 0, 4) + for _, rr := range rrs { + switch rr := rr.(type) { + case *dnsRR_A: + addrs = append(addrs, IPAddr{IP: IPv4(byte(rr.A>>24), byte(rr.A>>16), byte(rr.A>>8), byte(rr.A))}) + case *dnsRR_AAAA: + ip := make(IP, IPv6len) + copy(ip, rr.AAAA[:]) + addrs = append(addrs, IPAddr{IP: ip}) + } } return addrs } -func convertRR_AAAA(records []dnsRR) []IP { - addrs := make([]IP, len(records)) - for i, rr := range records { - a := make(IP, IPv6len) - copy(a, rr.(*dnsRR_AAAA).AAAA[:]) - addrs[i] = a - } - return addrs -} +// A resolverConfig represents a DNS stub resolver configuration. +type resolverConfig struct { + initOnce sync.Once // guards init of resolverConfig -var cfg struct { - ch chan struct{} - mu sync.RWMutex // protects dnsConfig and dnserr - dnsConfig *dnsConfig - dnserr error -} -var onceLoadConfig sync.Once + // ch is used as a semaphore that only allows one lookup at a + // time to recheck resolv.conf. + ch chan struct{} // guards lastChecked and modTime + lastChecked time.Time // last time resolv.conf was checked + modTime time.Time // time of resolv.conf modification -// Assume dns config file is /etc/resolv.conf here -func loadDefaultConfig() { - loadConfig("/etc/resolv.conf", 5*time.Second, nil) + mu sync.RWMutex // protects dnsConfig + dnsConfig *dnsConfig // parsed resolv.conf structure used in lookups } -func loadConfig(resolvConfPath string, reloadTime time.Duration, quit <-chan chan struct{}) { - var mtime time.Time - cfg.ch = make(chan struct{}, 1) - if fi, err := os.Stat(resolvConfPath); err != nil { - cfg.dnserr = err - } else { - mtime = fi.ModTime() - cfg.dnsConfig, cfg.dnserr = dnsReadConfig(resolvConfPath) - } - go func() { - for { - time.Sleep(reloadTime) - select { - case qresp := <-quit: - qresp <- struct{}{} - return - case <-cfg.ch: - } +var resolvConf resolverConfig - // In case of error, we keep the previous config - fi, err := os.Stat(resolvConfPath) - if err != nil { - continue - } - // If the resolv.conf mtime didn't change, do not reload - m := fi.ModTime() - if m.Equal(mtime) { - continue - } - mtime = m - // In case of error, we keep the previous config - ncfg, err := dnsReadConfig(resolvConfPath) - if err != nil || len(ncfg.servers) == 0 { - continue - } - cfg.mu.Lock() - cfg.dnsConfig = ncfg - cfg.dnserr = nil - cfg.mu.Unlock() - } - }() -} - -func lookup(name string, qtype uint16) (cname string, addrs []dnsRR, err error) { - if !isDomainName(name) { - return name, nil, &DNSError{Err: "invalid domain name", Name: name} +// init initializes conf and is only called via conf.initOnce. +func (conf *resolverConfig) init() { + // Set dnsConfig, modTime, and lastChecked so we don't parse + // resolv.conf twice the first time. + conf.dnsConfig = systemConf().resolv + if conf.dnsConfig == nil { + conf.dnsConfig = dnsReadConfig("/etc/resolv.conf") } - onceLoadConfig.Do(loadDefaultConfig) - select { - case cfg.ch <- struct{}{}: - default: + if fi, err := os.Stat("/etc/resolv.conf"); err == nil { + conf.modTime = fi.ModTime() } + conf.lastChecked = time.Now() + + // Prepare ch so that only one update of resolverConfig may + // run at once. + conf.ch = make(chan struct{}, 1) +} - cfg.mu.RLock() - defer cfg.mu.RUnlock() +// tryUpdate tries to update conf with the named resolv.conf file. +// The name variable only exists for testing. It is otherwise always +// "/etc/resolv.conf". +func (conf *resolverConfig) tryUpdate(name string) { + conf.initOnce.Do(conf.init) - if cfg.dnserr != nil || cfg.dnsConfig == nil { - err = cfg.dnserr + // Ensure only one update at a time checks resolv.conf. + if !conf.tryAcquireSema() { return } - // If name is rooted (trailing dot) or has enough dots, - // try it by itself first. - rooted := len(name) > 0 && name[len(name)-1] == '.' - if rooted || count(name, '.') >= cfg.dnsConfig.ndots { - rname := name - if !rooted { - rname += "." - } - // Can try as ordinary name. - cname, addrs, err = tryOneName(cfg.dnsConfig, rname, qtype) - if rooted || err == nil { - return - } + defer conf.releaseSema() + + now := time.Now() + if conf.lastChecked.After(now.Add(-5 * time.Second)) { + return } + conf.lastChecked = now - // Otherwise, try suffixes. - for i := 0; i < len(cfg.dnsConfig.search); i++ { - rname := name + "." + cfg.dnsConfig.search[i] - if rname[len(rname)-1] != '.' { - rname += "." + if fi, err := os.Stat(name); err == nil { + if fi.ModTime().Equal(conf.modTime) { + return } - cname, addrs, err = tryOneName(cfg.dnsConfig, rname, qtype) - if err == nil { + conf.modTime = fi.ModTime() + } else { + // If modTime wasn't set prior, assume nothing has changed. + if conf.modTime.IsZero() { return } + conf.modTime = time.Time{} } - // Last ditch effort: try unsuffixed only if we haven't already, - // that is, name is not rooted and has less than ndots dots. - if count(name, '.') < cfg.dnsConfig.ndots { - cname, addrs, err = tryOneName(cfg.dnsConfig, name+".", qtype) + dnsConf := dnsReadConfig(name) + conf.mu.Lock() + conf.dnsConfig = dnsConf + conf.mu.Unlock() +} + +func (conf *resolverConfig) tryAcquireSema() bool { + select { + case conf.ch <- struct{}{}: + return true + default: + return false + } +} + +func (conf *resolverConfig) releaseSema() { + <-conf.ch +} + +func lookup(name string, qtype uint16) (cname string, rrs []dnsRR, err error) { + if !isDomainName(name) { + return "", nil, &DNSError{Err: "invalid domain name", Name: name} + } + resolvConf.tryUpdate("/etc/resolv.conf") + resolvConf.mu.RLock() + conf := resolvConf.dnsConfig + resolvConf.mu.RUnlock() + for _, fqdn := range conf.nameList(name) { + cname, rrs, err = tryOneName(conf, fqdn, qtype) if err == nil { - return + break } } - - if e, ok := err.(*DNSError); ok { + if err, ok := err.(*DNSError); ok { // Show original name passed to lookup, not suffixed one. // In general we might have tried many suffixes; showing // just one is misleading. See also golang.org/issue/6324. - e.Name = name + err.Name = name } return } +// nameList returns a list of names for sequential DNS queries. +func (conf *dnsConfig) nameList(name string) []string { + // If name is rooted (trailing dot), try only that name. + rooted := len(name) > 0 && name[len(name)-1] == '.' + if rooted { + return []string{name} + } + // Build list of search choices. + names := make([]string, 0, 1+len(conf.search)) + // If name has enough dots, try unsuffixed first. + if count(name, '.') >= conf.ndots { + names = append(names, name+".") + } + // Try suffixes. + for _, suffix := range conf.search { + suffixed := name + "." + suffix + if suffixed[len(suffixed)-1] != '.' { + suffixed += "." + } + names = append(names, suffixed) + } + // Try unsuffixed, if not tried first above. + if count(name, '.') < conf.ndots { + names = append(names, name+".") + } + return names +} + +// hostLookupOrder specifies the order of LookupHost lookup strategies. +// It is basically a simplified representation of nsswitch.conf. +// "files" means /etc/hosts. +type hostLookupOrder int + +const ( + // hostLookupCgo means defer to cgo. + hostLookupCgo hostLookupOrder = iota + hostLookupFilesDNS // files first + hostLookupDNSFiles // dns first + hostLookupFiles // only files + hostLookupDNS // only DNS +) + +var lookupOrderName = map[hostLookupOrder]string{ + hostLookupCgo: "cgo", + hostLookupFilesDNS: "files,dns", + hostLookupDNSFiles: "dns,files", + hostLookupFiles: "files", + hostLookupDNS: "dns", +} + +func (o hostLookupOrder) String() string { + if s, ok := lookupOrderName[o]; ok { + return s + } + return "hostLookupOrder=" + strconv.Itoa(int(o)) + "??" +} + // goLookupHost is the native Go implementation of LookupHost. // Used only if cgoLookupHost refuses to handle the request // (that is, only if cgoLookupHost is the stub in cgo_stub.go). @@ -339,12 +384,18 @@ func lookup(name string, qtype uint16) (cname string, addrs []dnsRR, err error) // depending on our lookup code, so that Go and C get the same // answers. func goLookupHost(name string) (addrs []string, err error) { - // Use entries from /etc/hosts if they match. - addrs = lookupStaticHost(name) - if len(addrs) > 0 { - return + return goLookupHostOrder(name, hostLookupFilesDNS) +} + +func goLookupHostOrder(name string, order hostLookupOrder) (addrs []string, err error) { + if order == hostLookupFilesDNS || order == hostLookupFiles { + // Use entries from /etc/hosts if they match. + addrs = lookupStaticHost(name) + if len(addrs) > 0 || order == hostLookupFiles { + return + } } - ips, err := goLookupIP(name) + ips, err := goLookupIPOrder(name, order) if err != nil { return } @@ -355,54 +406,79 @@ func goLookupHost(name string) (addrs []string, err error) { return } -// goLookupIP is the native Go implementation of LookupIP. -// Used only if cgoLookupIP refuses to handle the request -// (that is, only if cgoLookupIP is the stub in cgo_stub.go). -// Normally we let cgo use the C library resolver instead of -// depending on our lookup code, so that Go and C get the same -// answers. -func goLookupIP(name string) (addrs []IP, err error) { - // Use entries from /etc/hosts if possible. - haddrs := lookupStaticHost(name) - if len(haddrs) > 0 { - for _, haddr := range haddrs { - if ip := ParseIP(haddr); ip != nil { - addrs = append(addrs, ip) - } +// lookup entries from /etc/hosts +func goLookupIPFiles(name string) (addrs []IPAddr) { + for _, haddr := range lookupStaticHost(name) { + haddr, zone := splitHostZone(haddr) + if ip := ParseIP(haddr); ip != nil { + addr := IPAddr{IP: ip, Zone: zone} + addrs = append(addrs, addr) } - if len(addrs) > 0 { - return + } + sortByRFC6724(addrs) + return +} + +// goLookupIP is the native Go implementation of LookupIP. +// The libc versions are in cgo_*.go. +func goLookupIP(name string) (addrs []IPAddr, err error) { + return goLookupIPOrder(name, hostLookupFilesDNS) +} + +func goLookupIPOrder(name string, order hostLookupOrder) (addrs []IPAddr, err error) { + if order == hostLookupFilesDNS || order == hostLookupFiles { + addrs = goLookupIPFiles(name) + if len(addrs) > 0 || order == hostLookupFiles { + return addrs, nil } } + if !isDomainName(name) { + return nil, &DNSError{Err: "invalid domain name", Name: name} + } + resolvConf.tryUpdate("/etc/resolv.conf") + resolvConf.mu.RLock() + conf := resolvConf.dnsConfig + resolvConf.mu.RUnlock() type racer struct { - qtype uint16 - rrs []dnsRR + rrs []dnsRR error } lane := make(chan racer, 1) qtypes := [...]uint16{dnsTypeA, dnsTypeAAAA} - for _, qtype := range qtypes { - go func(qtype uint16) { - _, rrs, err := lookup(name, qtype) - lane <- racer{qtype, rrs, err} - }(qtype) - } var lastErr error - for range qtypes { - racer := <-lane - if racer.error != nil { - lastErr = racer.error - continue + for _, fqdn := range conf.nameList(name) { + for _, qtype := range qtypes { + go func(qtype uint16) { + _, rrs, err := tryOneName(conf, fqdn, qtype) + lane <- racer{rrs, err} + }(qtype) + } + for range qtypes { + racer := <-lane + if racer.error != nil { + lastErr = racer.error + continue + } + addrs = append(addrs, addrRecordList(racer.rrs)...) } - switch racer.qtype { - case dnsTypeA: - addrs = append(addrs, convertRR_A(racer.rrs)...) - case dnsTypeAAAA: - addrs = append(addrs, convertRR_AAAA(racer.rrs)...) + if len(addrs) > 0 { + break } } - if len(addrs) == 0 && lastErr != nil { - return nil, lastErr + if lastErr, ok := lastErr.(*DNSError); ok { + // Show original name passed to lookup, not suffixed one. + // In general we might have tried many suffixes; showing + // just one is misleading. See also golang.org/issue/6324. + lastErr.Name = name + } + sortByRFC6724(addrs) + if len(addrs) == 0 { + if lastErr != nil { + return nil, lastErr + } + if order == hostLookupDNSFiles { + addrs = goLookupIPFiles(name) + } } return addrs, nil } @@ -414,10 +490,35 @@ func goLookupIP(name string) (addrs []IP, err error) { // depending on our lookup code, so that Go and C get the same // answers. func goLookupCNAME(name string) (cname string, err error) { - _, rr, err := lookup(name, dnsTypeCNAME) + _, rrs, err := lookup(name, dnsTypeCNAME) if err != nil { return } - cname = rr[0].(*dnsRR_CNAME).Cname + cname = rrs[0].(*dnsRR_CNAME).Cname return } + +// goLookupPTR is the native Go implementation of LookupAddr. +// Used only if cgoLookupPTR refuses to handle the request (that is, +// only if cgoLookupPTR is the stub in cgo_stub.go). +// Normally we let cgo use the C library resolver instead of depending +// on our lookup code, so that Go and C get the same answers. +func goLookupPTR(addr string) ([]string, error) { + names := lookupStaticAddr(addr) + if len(names) > 0 { + return names, nil + } + arpa, err := reverseaddr(addr) + if err != nil { + return nil, err + } + _, rrs, err := lookup(arpa, dnsTypePTR) + if err != nil { + return nil, err + } + ptrs := make([]string, len(rrs)) + for i, rr := range rrs { + ptrs[i] = rr.(*dnsRR_PTR).Ptr + } + return ptrs, nil +} diff --git a/libgo/go/net/dnsclient_unix_test.go b/libgo/go/net/dnsclient_unix_test.go index 1167c26b39d..a999f8f0607 100644 --- a/libgo/go/net/dnsclient_unix_test.go +++ b/libgo/go/net/dnsclient_unix_test.go @@ -7,11 +7,13 @@ package net import ( - "io" + "fmt" "io/ioutil" "os" "path" "reflect" + "strings" + "sync" "testing" "time" ) @@ -31,7 +33,7 @@ var dnsTransportFallbackTests = []struct { func TestDNSTransportFallback(t *testing.T) { if testing.Short() || !*testExternal { - t.Skip("skipping test to avoid external network") + t.Skip("avoid external network") } for _, tt := range dnsTransportFallbackTests { @@ -57,13 +59,13 @@ var specialDomainNameTests = []struct { qtype uint16 rcode int }{ - // Name resoltion APIs and libraries should not recongnize the + // Name resolution APIs and libraries should not recognize the // followings as special. {"1.0.168.192.in-addr.arpa.", dnsTypePTR, dnsRcodeNameError}, {"test.", dnsTypeALL, dnsRcodeNameError}, {"example.com.", dnsTypeALL, dnsRcodeSuccess}, - // Name resoltion APIs and libraries should recongnize the + // Name resolution APIs and libraries should recognize the // followings as special and should not send any queries. // Though, we test those names here for verifying nagative // answers at DNS query-response interaction level. @@ -73,7 +75,7 @@ var specialDomainNameTests = []struct { func TestSpecialDomainName(t *testing.T) { if testing.Short() || !*testExternal { - t.Skip("skipping test to avoid external network") + t.Skip("avoid external network") } server := "8.8.8.8:53" @@ -93,154 +95,323 @@ func TestSpecialDomainName(t *testing.T) { } type resolvConfTest struct { - *testing.T - dir string - path string - started bool - quitc chan chan struct{} + dir string + path string + *resolverConfig } -func newResolvConfTest(t *testing.T) *resolvConfTest { - dir, err := ioutil.TempDir("", "resolvConfTest") +func newResolvConfTest() (*resolvConfTest, error) { + dir, err := ioutil.TempDir("", "go-resolvconftest") if err != nil { - t.Fatalf("could not create temp dir: %v", err) + return nil, err } - - // Disable the default loadConfig - onceLoadConfig.Do(func() {}) - - r := &resolvConfTest{ - T: t, - dir: dir, - path: path.Join(dir, "resolv.conf"), - quitc: make(chan chan struct{}), + conf := &resolvConfTest{ + dir: dir, + path: path.Join(dir, "resolv.conf"), + resolverConfig: &resolvConf, } - - return r + conf.initOnce.Do(conf.init) + return conf, nil } -func (r *resolvConfTest) Start() { - loadConfig(r.path, 100*time.Millisecond, r.quitc) - r.started = true -} - -func (r *resolvConfTest) SetConf(s string) { - // Make sure the file mtime will be different once we're done here, - // even on systems with coarse (1s) mtime resolution. - time.Sleep(time.Second) - - f, err := os.OpenFile(r.path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600) +func (conf *resolvConfTest) writeAndUpdate(lines []string) error { + f, err := os.OpenFile(conf.path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600) if err != nil { - r.Fatalf("failed to create temp file %s: %v", r.path, err) + return err } - if _, err := io.WriteString(f, s); err != nil { + if _, err := f.WriteString(strings.Join(lines, "\n")); err != nil { f.Close() - r.Fatalf("failed to write temp file: %v", err) + return err } f.Close() - - if r.started { - cfg.ch <- struct{}{} // fill buffer - cfg.ch <- struct{}{} // wait for reload to begin - cfg.ch <- struct{}{} // wait for reload to complete + if err := conf.forceUpdate(conf.path); err != nil { + return err } + return nil } -func (r *resolvConfTest) WantServers(want []string) { - cfg.mu.RLock() - defer cfg.mu.RUnlock() - if got := cfg.dnsConfig.servers; !reflect.DeepEqual(got, want) { - r.Fatalf("Unexpected dns server loaded, got %v want %v", got, want) +func (conf *resolvConfTest) forceUpdate(name string) error { + dnsConf := dnsReadConfig(name) + conf.mu.Lock() + conf.dnsConfig = dnsConf + conf.mu.Unlock() + for i := 0; i < 5; i++ { + if conf.tryAcquireSema() { + conf.lastChecked = time.Time{} + conf.releaseSema() + return nil + } } + return fmt.Errorf("tryAcquireSema for %s failed", name) } -func (r *resolvConfTest) Close() { - resp := make(chan struct{}) - r.quitc <- resp - <-resp - if err := os.RemoveAll(r.dir); err != nil { - r.Logf("failed to remove temp dir %s: %v", r.dir, err) - } +func (conf *resolvConfTest) servers() []string { + conf.mu.RLock() + servers := conf.dnsConfig.servers + conf.mu.RUnlock() + return servers } -func TestReloadResolvConfFail(t *testing.T) { - if testing.Short() || !*testExternal { - t.Skip("skipping test to avoid external network") - } +func (conf *resolvConfTest) teardown() error { + err := conf.forceUpdate("/etc/resolv.conf") + os.RemoveAll(conf.dir) + return err +} - r := newResolvConfTest(t) - defer r.Close() +var updateResolvConfTests = []struct { + name string // query name + lines []string // resolver configuration lines + servers []string // expected name servers +}{ + { + name: "golang.org", + lines: []string{"nameserver 8.8.8.8"}, + servers: []string{"8.8.8.8"}, + }, + { + name: "", + lines: nil, // an empty resolv.conf should use defaultNS as name servers + servers: defaultNS, + }, + { + name: "www.example.com", + lines: []string{"nameserver 8.8.4.4"}, + servers: []string{"8.8.4.4"}, + }, +} - // resolv.conf.tmp does not exist yet - r.Start() - if _, err := goLookupIP("golang.org"); err == nil { - t.Fatal("goLookupIP(missing) succeeded") +func TestUpdateResolvConf(t *testing.T) { + if testing.Short() || !*testExternal { + t.Skip("avoid external network") } - r.SetConf("nameserver 8.8.8.8") - if _, err := goLookupIP("golang.org"); err != nil { - t.Fatalf("goLookupIP(missing; good) failed: %v", err) + conf, err := newResolvConfTest() + if err != nil { + t.Fatal(err) } + defer conf.teardown() - // Using a bad resolv.conf while we had a good - // one before should not update the config - r.SetConf("") - if _, err := goLookupIP("golang.org"); err != nil { - t.Fatalf("goLookupIP(missing; good; bad) failed: %v", err) + for i, tt := range updateResolvConfTests { + if err := conf.writeAndUpdate(tt.lines); err != nil { + t.Error(err) + continue + } + if tt.name != "" { + var wg sync.WaitGroup + const N = 10 + wg.Add(N) + for j := 0; j < N; j++ { + go func(name string) { + defer wg.Done() + ips, err := goLookupIP(name) + if err != nil { + t.Error(err) + return + } + if len(ips) == 0 { + t.Errorf("no records for %s", name) + return + } + }(tt.name) + } + wg.Wait() + } + servers := conf.servers() + if !reflect.DeepEqual(servers, tt.servers) { + t.Errorf("#%d: got %v; want %v", i, servers, tt.servers) + continue + } } } -func TestReloadResolvConfChange(t *testing.T) { +var goLookupIPWithResolverConfigTests = []struct { + name string + lines []string // resolver configuration lines + error + a, aaaa bool // whether response contains A, AAAA-record +}{ + // no records, transport timeout + { + "jgahvsekduiv9bw4b3qhn4ykdfgj0493iohkrjfhdvhjiu4j", + []string{ + "options timeout:1 attempts:1", + "nameserver 255.255.255.255", // please forgive us for abuse of limited broadcast address + }, + &DNSError{Name: "jgahvsekduiv9bw4b3qhn4ykdfgj0493iohkrjfhdvhjiu4j", Server: "255.255.255.255:53", IsTimeout: true}, + false, false, + }, + + // no records, non-existent domain + { + "jgahvsekduiv9bw4b3qhn4ykdfgj0493iohkrjfhdvhjiu4j", + []string{ + "options timeout:3 attempts:1", + "nameserver 8.8.8.8", + }, + &DNSError{Name: "jgahvsekduiv9bw4b3qhn4ykdfgj0493iohkrjfhdvhjiu4j", Server: "8.8.8.8:53", IsTimeout: false}, + false, false, + }, + + // a few A records, no AAAA records + { + "ipv4.google.com.", + []string{ + "nameserver 8.8.8.8", + "nameserver 2001:4860:4860::8888", + }, + nil, + true, false, + }, + { + "ipv4.google.com", + []string{ + "domain golang.org", + "nameserver 2001:4860:4860::8888", + "nameserver 8.8.8.8", + }, + nil, + true, false, + }, + { + "ipv4.google.com", + []string{ + "search x.golang.org y.golang.org", + "nameserver 2001:4860:4860::8888", + "nameserver 8.8.8.8", + }, + nil, + true, false, + }, + + // no A records, a few AAAA records + { + "ipv6.google.com.", + []string{ + "nameserver 2001:4860:4860::8888", + "nameserver 8.8.8.8", + }, + nil, + false, true, + }, + { + "ipv6.google.com", + []string{ + "domain golang.org", + "nameserver 8.8.8.8", + "nameserver 2001:4860:4860::8888", + }, + nil, + false, true, + }, + { + "ipv6.google.com", + []string{ + "search x.golang.org y.golang.org", + "nameserver 8.8.8.8", + "nameserver 2001:4860:4860::8888", + }, + nil, + false, true, + }, + + // both A and AAAA records + { + "hostname.as112.net", // see RFC 7534 + []string{ + "domain golang.org", + "nameserver 2001:4860:4860::8888", + "nameserver 8.8.8.8", + }, + nil, + true, true, + }, + { + "hostname.as112.net", // see RFC 7534 + []string{ + "search x.golang.org y.golang.org", + "nameserver 2001:4860:4860::8888", + "nameserver 8.8.8.8", + }, + nil, + true, true, + }, +} + +func TestGoLookupIPWithResolverConfig(t *testing.T) { if testing.Short() || !*testExternal { - t.Skip("skipping test to avoid external network") + t.Skip("avoid external network") } - r := newResolvConfTest(t) - defer r.Close() - - r.SetConf("nameserver 8.8.8.8") - r.Start() - - if _, err := goLookupIP("golang.org"); err != nil { - t.Fatalf("goLookupIP(good) failed: %v", err) + conf, err := newResolvConfTest() + if err != nil { + t.Fatal(err) } - r.WantServers([]string{"8.8.8.8"}) + defer conf.teardown() - // Using a bad resolv.conf when we had a good one - // before should not update the config - r.SetConf("") - if _, err := goLookupIP("golang.org"); err != nil { - t.Fatalf("goLookupIP(good; bad) failed: %v", err) + for _, tt := range goLookupIPWithResolverConfigTests { + if err := conf.writeAndUpdate(tt.lines); err != nil { + t.Error(err) + continue + } + conf.tryUpdate(conf.path) + addrs, err := goLookupIP(tt.name) + if err != nil { + if err, ok := err.(*DNSError); !ok || (err.Name != tt.error.(*DNSError).Name || err.Server != tt.error.(*DNSError).Server || err.IsTimeout != tt.error.(*DNSError).IsTimeout) { + t.Errorf("got %v; want %v", err, tt.error) + } + continue + } + if len(addrs) == 0 { + t.Errorf("no records for %s", tt.name) + } + if !tt.a && !tt.aaaa && len(addrs) > 0 { + t.Errorf("unexpected %v for %s", addrs, tt.name) + } + for _, addr := range addrs { + if !tt.a && addr.IP.To4() != nil { + t.Errorf("got %v; must not be IPv4 address", addr) + } + if !tt.aaaa && addr.IP.To16() != nil && addr.IP.To4() == nil { + t.Errorf("got %v; must not be IPv6 address", addr) + } + } } - - // A new good config should get picked up - r.SetConf("nameserver 8.8.4.4") - r.WantServers([]string{"8.8.4.4"}) } func BenchmarkGoLookupIP(b *testing.B) { + testHookUninstaller.Do(uninstallTestHooks) + for i := 0; i < b.N; i++ { goLookupIP("www.example.com") } } func BenchmarkGoLookupIPNoSuchHost(b *testing.B) { + testHookUninstaller.Do(uninstallTestHooks) + for i := 0; i < b.N; i++ { goLookupIP("some.nonexistent") } } func BenchmarkGoLookupIPWithBrokenNameServer(b *testing.B) { - onceLoadConfig.Do(loadDefaultConfig) - if cfg.dnserr != nil || cfg.dnsConfig == nil { - b.Fatalf("loadConfig failed: %v", cfg.dnserr) - } - // This looks ugly but it's safe as long as benchmarks are run - // sequentially in package testing. - orig := cfg.dnsConfig - cfg.dnsConfig.servers = append([]string{"203.0.113.254"}, cfg.dnsConfig.servers...) // use TEST-NET-3 block, see RFC 5737 + testHookUninstaller.Do(uninstallTestHooks) + + conf, err := newResolvConfTest() + if err != nil { + b.Fatal(err) + } + defer conf.teardown() + + lines := []string{ + "nameserver 203.0.113.254", // use TEST-NET-3 block, see RFC 5737 + "nameserver 8.8.8.8", + } + if err := conf.writeAndUpdate(lines); err != nil { + b.Fatal(err) + } + for i := 0; i < b.N; i++ { goLookupIP("www.example.com") } - cfg.dnsConfig = orig } diff --git a/libgo/go/net/dnsconfig_unix.go b/libgo/go/net/dnsconfig_unix.go index 66ab7c4dd30..6073fdb6d83 100644 --- a/libgo/go/net/dnsconfig_unix.go +++ b/libgo/go/net/dnsconfig_unix.go @@ -8,30 +8,41 @@ package net +var defaultNS = []string{"127.0.0.1", "::1"} + type dnsConfig struct { - servers []string // servers to use - search []string // suffixes to append to local name - ndots int // number of dots in name to trigger absolute lookup - timeout int // seconds before giving up on packet - attempts int // lost packets before giving up on server - rotate bool // round robin among servers + servers []string // servers to use + search []string // suffixes to append to local name + ndots int // number of dots in name to trigger absolute lookup + timeout int // seconds before giving up on packet + attempts int // lost packets before giving up on server + rotate bool // round robin among servers + unknownOpt bool // anything unknown was encountered + lookup []string // OpenBSD top-level database "lookup" order + err error // any error that occurs during open of resolv.conf } // See resolv.conf(5) on a Linux machine. // TODO(rsc): Supposed to call uname() and chop the beginning // of the host name to get the default search domain. -func dnsReadConfig(filename string) (*dnsConfig, error) { - file, err := open(filename) - if err != nil { - return nil, &DNSConfigError{err} - } - defer file.close() +func dnsReadConfig(filename string) *dnsConfig { conf := &dnsConfig{ ndots: 1, timeout: 5, attempts: 2, } + file, err := open(filename) + if err != nil { + conf.servers = defaultNS + conf.err = err + return conf + } + defer file.close() for line, ok := file.readLine(); ok; line, ok = file.readLine() { + if len(line) > 0 && (line[0] == ';' || line[0] == '#') { + // comment. + continue + } f := getFields(line) if len(f) < 1 { continue @@ -61,8 +72,7 @@ func dnsReadConfig(filename string) (*dnsConfig, error) { } case "options": // magic options - for i := 1; i < len(f); i++ { - s := f[i] + for _, s := range f[1:] { switch { case hasPrefix(s, "ndots:"): n, _, _ := dtoi(s, 6) @@ -84,11 +94,25 @@ func dnsReadConfig(filename string) (*dnsConfig, error) { conf.attempts = n case s == "rotate": conf.rotate = true + default: + conf.unknownOpt = true } } + + case "lookup": + // OpenBSD option: + // http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man5/resolv.conf.5 + // "the legal space-separated values are: bind, file, yp" + conf.lookup = f[1:] + + default: + conf.unknownOpt = true } } - return conf, nil + if len(conf.servers) == 0 { + conf.servers = defaultNS + } + return conf } func hasPrefix(s, prefix string) bool { diff --git a/libgo/go/net/dnsconfig_unix_test.go b/libgo/go/net/dnsconfig_unix_test.go index 94fb0c32e24..c8eed618904 100644 --- a/libgo/go/net/dnsconfig_unix_test.go +++ b/libgo/go/net/dnsconfig_unix_test.go @@ -7,28 +7,30 @@ package net import ( + "os" "reflect" "testing" ) var dnsReadConfigTests = []struct { name string - conf dnsConfig + want *dnsConfig }{ { name: "testdata/resolv.conf", - conf: dnsConfig{ - servers: []string{"8.8.8.8", "2001:4860:4860::8888", "fe80::1%lo0"}, - search: []string{"localdomain"}, - ndots: 5, - timeout: 10, - attempts: 3, - rotate: true, + want: &dnsConfig{ + servers: []string{"8.8.8.8", "2001:4860:4860::8888", "fe80::1%lo0"}, + search: []string{"localdomain"}, + ndots: 5, + timeout: 10, + attempts: 3, + rotate: true, + unknownOpt: true, // the "options attempts 3" line }, }, { name: "testdata/domain-resolv.conf", - conf: dnsConfig{ + want: &dnsConfig{ servers: []string{"8.8.8.8"}, search: []string{"localdomain"}, ndots: 1, @@ -38,7 +40,7 @@ var dnsReadConfigTests = []struct { }, { name: "testdata/search-resolv.conf", - conf: dnsConfig{ + want: &dnsConfig{ servers: []string{"8.8.8.8"}, search: []string{"test", "invalid"}, ndots: 1, @@ -48,22 +50,51 @@ var dnsReadConfigTests = []struct { }, { name: "testdata/empty-resolv.conf", - conf: dnsConfig{ + want: &dnsConfig{ + servers: defaultNS, + ndots: 1, + timeout: 5, + attempts: 2, + }, + }, + { + name: "testdata/openbsd-resolv.conf", + want: &dnsConfig{ ndots: 1, timeout: 5, attempts: 2, + lookup: []string{"file", "bind"}, + servers: []string{"169.254.169.254", "10.240.0.1"}, + search: []string{"c.symbolic-datum-552.internal."}, }, }, } func TestDNSReadConfig(t *testing.T) { for _, tt := range dnsReadConfigTests { - conf, err := dnsReadConfig(tt.name) - if err != nil { - t.Fatal(err) + conf := dnsReadConfig(tt.name) + if conf.err != nil { + t.Fatal(conf.err) } - if !reflect.DeepEqual(conf, &tt.conf) { - t.Errorf("got %v; want %v", conf, &tt.conf) + if !reflect.DeepEqual(conf, tt.want) { + t.Errorf("%s:\ngot: %+v\nwant: %+v", tt.name, conf, tt.want) } } } + +func TestDNSReadMissingFile(t *testing.T) { + conf := dnsReadConfig("a-nonexistent-file") + if !os.IsNotExist(conf.err) { + t.Errorf("missing resolv.conf:\ngot: %v\nwant: %v", conf.err, os.ErrNotExist) + } + conf.err = nil + want := &dnsConfig{ + servers: defaultNS, + ndots: 1, + timeout: 5, + attempts: 2, + } + if !reflect.DeepEqual(conf, want) { + t.Errorf("missing resolv.conf:\ngot: %+v\nwant: %+v", conf, want) + } +} diff --git a/libgo/go/net/dnsmsg.go b/libgo/go/net/dnsmsg.go index 161afb2a556..6ecaa948230 100644 --- a/libgo/go/net/dnsmsg.go +++ b/libgo/go/net/dnsmsg.go @@ -306,7 +306,23 @@ func (rr *dnsRR_TXT) Header() *dnsRR_Header { } func (rr *dnsRR_TXT) Walk(f func(v interface{}, name, tag string) bool) bool { - return rr.Hdr.Walk(f) && f(&rr.Txt, "Txt", "") + if !rr.Hdr.Walk(f) { + return false + } + var n uint16 = 0 + for n < rr.Hdr.Rdlength { + var txt string + if !f(&txt, "Txt", "") { + return false + } + // more bytes than rr.Hdr.Rdlength said there woudld be + if rr.Hdr.Rdlength-n < uint16(len(txt))+1 { + return false + } + n += uint16(len(txt)) + 1 + rr.Txt += txt + } + return true } type dnsRR_SRV struct { diff --git a/libgo/go/net/dnsmsg_test.go b/libgo/go/net/dnsmsg_test.go index c39dbdb049d..1078d77ceb9 100644 --- a/libgo/go/net/dnsmsg_test.go +++ b/libgo/go/net/dnsmsg_test.go @@ -18,7 +18,7 @@ func TestDNSParseSRVReply(t *testing.T) { msg := new(dnsMsg) ok := msg.Unpack(data) if !ok { - t.Fatalf("unpacking packet failed") + t.Fatal("unpacking packet failed") } msg.String() // exercise this code path if g, e := len(msg.answer), 5; g != e { @@ -32,13 +32,19 @@ func TestDNSParseSRVReply(t *testing.T) { t.Errorf("answer[%d] = %T; want *dnsRR_SRV", idx, rr) } } - _, addrs, err := answer("_xmpp-server._tcp.google.com.", "foo:53", msg, uint16(dnsTypeSRV)) - if err != nil { - t.Fatalf("answer: %v", err) - } - if g, e := len(addrs), 5; g != e { - t.Errorf("len(addrs) = %d; want %d", g, e) - t.Logf("addrs = %#v", addrs) + for _, name := range [...]string{ + "_xmpp-server._tcp.google.com.", + "_XMPP-Server._TCP.Google.COM.", + "_XMPP-SERVER._TCP.GOOGLE.COM.", + } { + _, addrs, err := answer(name, "foo:53", msg, uint16(dnsTypeSRV)) + if err != nil { + t.Error(err) + } + if g, e := len(addrs), 5; g != e { + t.Errorf("len(addrs) = %d; want %d", g, e) + t.Logf("addrs = %#v", addrs) + } } // repack and unpack. data2, ok := msg.Pack() @@ -46,9 +52,9 @@ func TestDNSParseSRVReply(t *testing.T) { msg2.Unpack(data2) switch { case !ok: - t.Errorf("failed to repack message") + t.Error("failed to repack message") case !reflect.DeepEqual(msg, msg2): - t.Errorf("repacked message differs from original") + t.Error("repacked message differs from original") } } @@ -60,7 +66,7 @@ func TestDNSParseCorruptSRVReply(t *testing.T) { msg := new(dnsMsg) ok := msg.Unpack(data) if !ok { - t.Fatalf("unpacking packet failed") + t.Fatal("unpacking packet failed") } msg.String() // exercise this code path if g, e := len(msg.answer), 5; g != e { @@ -90,6 +96,93 @@ func TestDNSParseCorruptSRVReply(t *testing.T) { } } +func TestDNSParseTXTReply(t *testing.T) { + expectedTxt1 := "v=spf1 redirect=_spf.google.com" + expectedTxt2 := "v=spf1 ip4:69.63.179.25 ip4:69.63.178.128/25 ip4:69.63.184.0/25 " + + "ip4:66.220.144.128/25 ip4:66.220.155.0/24 " + + "ip4:69.171.232.0/25 ip4:66.220.157.0/25 " + + "ip4:69.171.244.0/24 mx -all" + + replies := []string{dnsTXTReply1, dnsTXTReply2} + expectedTxts := []string{expectedTxt1, expectedTxt2} + + for i := range replies { + data, err := hex.DecodeString(replies[i]) + if err != nil { + t.Fatal(err) + } + + msg := new(dnsMsg) + ok := msg.Unpack(data) + if !ok { + t.Errorf("test %d: unpacking packet failed", i) + continue + } + + if len(msg.answer) != 1 { + t.Errorf("test %d: len(rr.answer) = %d; want 1", i, len(msg.answer)) + continue + } + + rr := msg.answer[0] + rrTXT, ok := rr.(*dnsRR_TXT) + if !ok { + t.Errorf("test %d: answer[0] = %T; want *dnsRR_TXT", i, rr) + continue + } + + if rrTXT.Txt != expectedTxts[i] { + t.Errorf("test %d: Txt = %s; want %s", i, rrTXT.Txt, expectedTxts[i]) + } + } +} + +func TestDNSParseTXTCorruptDataLengthReply(t *testing.T) { + replies := []string{dnsTXTCorruptDataLengthReply1, dnsTXTCorruptDataLengthReply2} + + for i := range replies { + data, err := hex.DecodeString(replies[i]) + if err != nil { + t.Fatal(err) + } + + msg := new(dnsMsg) + ok := msg.Unpack(data) + if ok { + t.Errorf("test %d: expected to fail on unpacking corrupt packet", i) + } + } +} + +func TestDNSParseTXTCorruptTXTLengthReply(t *testing.T) { + replies := []string{dnsTXTCorruptTXTLengthReply1, dnsTXTCorruptTXTLengthReply2} + + for i := range replies { + data, err := hex.DecodeString(replies[i]) + if err != nil { + t.Fatal(err) + } + + msg := new(dnsMsg) + ok := msg.Unpack(data) + // Unpacking should succeed, but we should just get the header. + if !ok { + t.Errorf("test %d: unpacking packet failed", i) + continue + } + + if len(msg.answer) != 1 { + t.Errorf("test %d: len(rr.answer) = %d; want 1", i, len(msg.answer)) + continue + } + + rr := msg.answer[0] + if _, justHeader := rr.(*dnsRR_Header); !justHeader { + t.Errorf("test %d: rr = %T; expected *dnsRR_Header", i, rr) + } + } +} + // Valid DNS SRV reply const dnsSRVReply = "0901818000010005000000000c5f786d70702d736572766572045f74637006676f6f67" + "6c6503636f6d0000210001c00c002100010000012c00210014000014950c786d70702d" + @@ -111,3 +204,63 @@ const dnsSRVCorruptReply = "0901818000010005000000000c5f786d70702d73657276657204 "6503636f6d00c00c002100010000012c00200005000014950b786d70702d7365727665" + "72016c06676f6f676c6503636f6d00c00c002100010000012c00FF0014000014950c78" + "6d70702d73657276657231016c06676f6f676c6503636f6d00" + +// TXT reply with one +const dnsTXTReply1 = "b3458180000100010004000505676d61696c03636f6d0000100001c00c001000010000012c00" + + "201f763d737066312072656469726563743d5f7370662e676f6f676c652e636f6dc00" + + "c0002000100025d4c000d036e733406676f6f676c65c012c00c0002000100025d4c00" + + "06036e7331c057c00c0002000100025d4c0006036e7333c057c00c0002000100025d4" + + "c0006036e7332c057c06c00010001000248b50004d8ef200ac09000010001000248b5" + + "0004d8ef220ac07e00010001000248b50004d8ef240ac05300010001000248b50004d" + + "8ef260a0000291000000000000000" + +// TXT reply with more than one . +// See https://tools.ietf.org/html/rfc1035#section-3.3.14 +const dnsTXTReply2 = "a0a381800001000100020002045f7370660866616365626f6f6b03636f6d0000100001c00c0010000" + + "100000e1000af7f763d73706631206970343a36392e36332e3137392e3235206970343a36392e" + + "36332e3137382e3132382f3235206970343a36392e36332e3138342e302f3235206970343a363" + + "62e3232302e3134342e3132382f3235206970343a36362e3232302e3135352e302f3234206970" + + "343a36392e3137312e3233322e302f323520692e70343a36362e3232302e3135372e302f32352" + + "06970343a36392e3137312e3234342e302f3234206d78202d616c6cc0110002000100025d1500" + + "070161026e73c011c0110002000100025d1500040162c0ecc0ea0001000100025d15000445abe" + + "f0cc0fd0001000100025d15000445abff0c" + +// DataLength field should be sum of all TXT fields. In this case it's less. +const dnsTXTCorruptDataLengthReply1 = "a0a381800001000100020002045f7370660866616365626f6f6b03636f6d0000100001c00c0010000" + + "100000e1000967f763d73706631206970343a36392e36332e3137392e3235206970343a36392e" + + "36332e3137382e3132382f3235206970343a36392e36332e3138342e302f3235206970343a363" + + "62e3232302e3134342e3132382f3235206970343a36362e3232302e3135352e302f3234206970" + + "343a36392e3137312e3233322e302f323520692e70343a36362e3232302e3135372e302f32352" + + "06970343a36392e3137312e3234342e302f3234206d78202d616c6cc0110002000100025d1500" + + "070161026e73c011c0110002000100025d1500040162c0ecc0ea0001000100025d15000445abe" + + "f0cc0fd0001000100025d15000445abff0c" + +// Same as above but DataLength is more than sum of TXT fields. +const dnsTXTCorruptDataLengthReply2 = "a0a381800001000100020002045f7370660866616365626f6f6b03636f6d0000100001c00c0010000" + + "100000e1001227f763d73706631206970343a36392e36332e3137392e3235206970343a36392e" + + "36332e3137382e3132382f3235206970343a36392e36332e3138342e302f3235206970343a363" + + "62e3232302e3134342e3132382f3235206970343a36362e3232302e3135352e302f3234206970" + + "343a36392e3137312e3233322e302f323520692e70343a36362e3232302e3135372e302f32352" + + "06970343a36392e3137312e3234342e302f3234206d78202d616c6cc0110002000100025d1500" + + "070161026e73c011c0110002000100025d1500040162c0ecc0ea0001000100025d15000445abe" + + "f0cc0fd0001000100025d15000445abff0c" + +// TXT Length field is less than actual length. +const dnsTXTCorruptTXTLengthReply1 = "a0a381800001000100020002045f7370660866616365626f6f6b03636f6d0000100001c00c0010000" + + "100000e1000af7f763d73706631206970343a36392e36332e3137392e3235206970343a36392e" + + "36332e3137382e3132382f3235206970343a36392e36332e3138342e302f3235206970343a363" + + "62e3232302e3134342e3132382f3235206970343a36362e3232302e3135352e302f3234206970" + + "343a36392e3137312e3233322e302f323520691470343a36362e3232302e3135372e302f32352" + + "06970343a36392e3137312e3234342e302f3234206d78202d616c6cc0110002000100025d1500" + + "070161026e73c011c0110002000100025d1500040162c0ecc0ea0001000100025d15000445abe" + + "f0cc0fd0001000100025d15000445abff0c" + +// TXT Length field is more than actual length. +const dnsTXTCorruptTXTLengthReply2 = "a0a381800001000100020002045f7370660866616365626f6f6b03636f6d0000100001c00c0010000" + + "100000e1000af7f763d73706631206970343a36392e36332e3137392e3235206970343a36392e" + + "36332e3137382e3132382f3235206970343a36392e36332e3138342e302f3235206970343a363" + + "62e3232302e3134342e3132382f3235206970343a36362e3232302e3135352e302f3234206970" + + "343a36392e3137312e3233322e302f323520693370343a36362e3232302e3135372e302f32352" + + "06970343a36392e3137312e3234342e302f3234206d78202d616c6cc0110002000100025d1500" + + "070161026e73c011c0110002000100025d1500040162c0ecc0ea0001000100025d15000445abe" + + "f0cc0fd0001000100025d15000445abff0c" diff --git a/libgo/go/net/dnsname_test.go b/libgo/go/net/dnsname_test.go index 57dd25fe4c6..be07dc6a16f 100644 --- a/libgo/go/net/dnsname_test.go +++ b/libgo/go/net/dnsname_test.go @@ -9,12 +9,12 @@ import ( "testing" ) -type testCase struct { +type dnsNameTest struct { name string result bool } -var tests = []testCase{ +var dnsNameTests = []dnsNameTest{ // RFC2181, section 11. {"_xmpp-server._tcp.google.com", true}, {"foo.com", true}, @@ -30,7 +30,7 @@ var tests = []testCase{ {"b.com.", true}, } -func getTestCases(ch chan<- testCase) { +func emitDNSNameTest(ch chan<- dnsNameTest) { defer close(ch) var char59 = "" var char63 = "" @@ -41,35 +41,36 @@ func getTestCases(ch chan<- testCase) { char63 = char59 + "aaaa" char64 = char63 + "a" - for _, tc := range tests { + for _, tc := range dnsNameTests { ch <- tc } - ch <- testCase{char63 + ".com", true} - ch <- testCase{char64 + ".com", false} + ch <- dnsNameTest{char63 + ".com", true} + ch <- dnsNameTest{char64 + ".com", false} // 255 char name is fine: - ch <- testCase{char59 + "." + char63 + "." + char63 + "." + + ch <- dnsNameTest{char59 + "." + char63 + "." + char63 + "." + char63 + ".com", true} // 256 char name is bad: - ch <- testCase{char59 + "a." + char63 + "." + char63 + "." + + ch <- dnsNameTest{char59 + "a." + char63 + "." + char63 + "." + char63 + ".com", false} } -func TestDNSNames(t *testing.T) { - ch := make(chan testCase) - go getTestCases(ch) +func TestDNSName(t *testing.T) { + ch := make(chan dnsNameTest) + go emitDNSNameTest(ch) for tc := range ch { if isDomainName(tc.name) != tc.result { - t.Errorf("isDomainName(%v) failed: Should be %v", - tc.name, tc.result) + t.Errorf("isDomainName(%q) = %v; want %v", tc.name, !tc.result, tc.result) } } } -func BenchmarkDNSNames(b *testing.B) { - benchmarks := append(tests, []testCase{ +func BenchmarkDNSName(b *testing.B) { + testHookUninstaller.Do(uninstallTestHooks) + + benchmarks := append(dnsNameTests, []dnsNameTest{ {strings.Repeat("a", 63), true}, {strings.Repeat("a", 64), false}, }...) diff --git a/libgo/go/net/error_plan9_test.go b/libgo/go/net/error_plan9_test.go new file mode 100644 index 00000000000..495ea965343 --- /dev/null +++ b/libgo/go/net/error_plan9_test.go @@ -0,0 +1,17 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package net + +import "syscall" + +var ( + errTimedout = syscall.ETIMEDOUT + errOpNotSupported = syscall.EPLAN9 +) + +func isPlatformError(err error) bool { + _, ok := err.(syscall.ErrorString) + return ok +} diff --git a/libgo/go/net/error_posix_test.go b/libgo/go/net/error_posix_test.go new file mode 100644 index 00000000000..981cc837ba4 --- /dev/null +++ b/libgo/go/net/error_posix_test.go @@ -0,0 +1,44 @@ +// Copyright 2015 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 !plan9 + +package net + +import ( + "os" + "syscall" + "testing" +) + +var ( + errTimedout = syscall.ETIMEDOUT + errOpNotSupported = syscall.EOPNOTSUPP +) + +func isPlatformError(err error) bool { + _, ok := err.(syscall.Errno) + return ok +} + +func TestSpuriousENOTAVAIL(t *testing.T) { + for _, tt := range []struct { + error + ok bool + }{ + {syscall.EADDRNOTAVAIL, true}, + {&os.SyscallError{Syscall: "syscall", Err: syscall.EADDRNOTAVAIL}, true}, + {&OpError{Op: "op", Err: syscall.EADDRNOTAVAIL}, true}, + {&OpError{Op: "op", Err: &os.SyscallError{Syscall: "syscall", Err: syscall.EADDRNOTAVAIL}}, true}, + + {syscall.EINVAL, false}, + {&os.SyscallError{Syscall: "syscall", Err: syscall.EINVAL}, false}, + {&OpError{Op: "op", Err: syscall.EINVAL}, false}, + {&OpError{Op: "op", Err: &os.SyscallError{Syscall: "syscall", Err: syscall.EINVAL}}, false}, + } { + if ok := spuriousENOTAVAIL(tt.error); ok != tt.ok { + t.Errorf("spuriousENOTAVAIL(%v) = %v; want %v", tt.error, ok, tt.ok) + } + } +} diff --git a/libgo/go/net/error_test.go b/libgo/go/net/error_test.go new file mode 100644 index 00000000000..bf95ff6108c --- /dev/null +++ b/libgo/go/net/error_test.go @@ -0,0 +1,673 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package net + +import ( + "fmt" + "io" + "io/ioutil" + "net/internal/socktest" + "os" + "runtime" + "testing" + "time" +) + +func (e *OpError) isValid() error { + if e.Op == "" { + return fmt.Errorf("OpError.Op is empty: %v", e) + } + if e.Net == "" { + return fmt.Errorf("OpError.Net is empty: %v", e) + } + for _, addr := range []Addr{e.Source, e.Addr} { + switch addr := addr.(type) { + case nil: + case *TCPAddr: + if addr == nil { + return fmt.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr, e) + } + case *UDPAddr: + if addr == nil { + return fmt.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr, e) + } + case *IPAddr: + if addr == nil { + return fmt.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr, e) + } + case *IPNet: + if addr == nil { + return fmt.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr, e) + } + case *UnixAddr: + if addr == nil { + return fmt.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr, e) + } + case *pipeAddr: + if addr == nil { + return fmt.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr, e) + } + case fileAddr: + if addr == "" { + return fmt.Errorf("OpError.Source or Addr is empty: %#v, %v", addr, e) + } + default: + return fmt.Errorf("OpError.Source or Addr is unknown type: %T, %v", addr, e) + } + } + if e.Err == nil { + return fmt.Errorf("OpError.Err is empty: %v", e) + } + return nil +} + +// parseDialError parses nestedErr and reports whether it is a valid +// error value from Dial, Listen functions. +// It returns nil when nestedErr is valid. +func parseDialError(nestedErr error) error { + if nestedErr == nil { + return nil + } + + switch err := nestedErr.(type) { + case *OpError: + if err := err.isValid(); err != nil { + return err + } + nestedErr = err.Err + goto second + } + return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr) + +second: + if isPlatformError(nestedErr) { + return nil + } + switch err := nestedErr.(type) { + case *AddrError, addrinfoErrno, *DNSError, InvalidAddrError, *ParseError, *timeoutError, UnknownNetworkError: + return nil + case *os.SyscallError: + nestedErr = err.Err + goto third + } + switch nestedErr { + case errClosing, errMissingAddress: + return nil + } + return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr) + +third: + if isPlatformError(nestedErr) { + return nil + } + return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr) +} + +var dialErrorTests = []struct { + network, address string +}{ + {"foo", ""}, + {"bar", "baz"}, + {"datakit", "mh/astro/r70"}, + {"tcp", ""}, + {"tcp", "127.0.0.1:☺"}, + {"tcp", "no-such-name:80"}, + {"tcp", "mh/astro/r70:http"}, + + {"tcp", "127.0.0.1:0"}, + {"udp", "127.0.0.1:0"}, + {"ip:icmp", "127.0.0.1"}, + + {"unix", "/path/to/somewhere"}, + {"unixgram", "/path/to/somewhere"}, + {"unixpacket", "/path/to/somewhere"}, +} + +func TestDialError(t *testing.T) { + switch runtime.GOOS { + case "plan9": + t.Skipf("%s does not have full support of socktest", runtime.GOOS) + } + + origTestHookLookupIP := testHookLookupIP + defer func() { testHookLookupIP = origTestHookLookupIP }() + testHookLookupIP = func(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, error) { + return nil, &DNSError{Err: "dial error test", Name: "name", Server: "server", IsTimeout: true} + } + sw.Set(socktest.FilterConnect, func(so *socktest.Status) (socktest.AfterFilter, error) { + return nil, errOpNotSupported + }) + defer sw.Set(socktest.FilterConnect, nil) + + d := Dialer{Timeout: someTimeout} + for i, tt := range dialErrorTests { + c, err := d.Dial(tt.network, tt.address) + if err == nil { + t.Errorf("#%d: should fail; %s:%s->%s", i, tt.network, c.LocalAddr(), c.RemoteAddr()) + c.Close() + continue + } + if c != nil { + t.Errorf("Dial returned non-nil interface %T(%v) with err != nil", c, c) + } + if err = parseDialError(err); err != nil { + t.Errorf("#%d: %v", i, err) + continue + } + } +} + +func TestProtocolDialError(t *testing.T) { + switch runtime.GOOS { + case "nacl", "solaris": + t.Skipf("not supported on %s", runtime.GOOS) + } + + for _, network := range []string{"tcp", "udp", "ip:4294967296", "unix", "unixpacket", "unixgram"} { + var err error + switch network { + case "tcp": + _, err = DialTCP(network, nil, &TCPAddr{Port: 1 << 16}) + case "udp": + _, err = DialUDP(network, nil, &UDPAddr{Port: 1 << 16}) + case "ip:4294967296": + _, err = DialIP(network, nil, nil) + case "unix", "unixpacket", "unixgram": + _, err = DialUnix(network, nil, &UnixAddr{Name: "//"}) + } + if err == nil { + t.Errorf("%s: should fail", network) + continue + } + if err = parseDialError(err); err != nil { + t.Errorf("%s: %v", network, err) + continue + } + } +} + +var listenErrorTests = []struct { + network, address string +}{ + {"foo", ""}, + {"bar", "baz"}, + {"datakit", "mh/astro/r70"}, + {"tcp", "127.0.0.1:☺"}, + {"tcp", "no-such-name:80"}, + {"tcp", "mh/astro/r70:http"}, + + {"tcp", "127.0.0.1:0"}, + + {"unix", "/path/to/somewhere"}, + {"unixpacket", "/path/to/somewhere"}, +} + +func TestListenError(t *testing.T) { + switch runtime.GOOS { + case "plan9": + t.Skipf("%s does not have full support of socktest", runtime.GOOS) + } + + origTestHookLookupIP := testHookLookupIP + defer func() { testHookLookupIP = origTestHookLookupIP }() + testHookLookupIP = func(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, error) { + return nil, &DNSError{Err: "listen error test", Name: "name", Server: "server", IsTimeout: true} + } + sw.Set(socktest.FilterListen, func(so *socktest.Status) (socktest.AfterFilter, error) { + return nil, errOpNotSupported + }) + defer sw.Set(socktest.FilterListen, nil) + + for i, tt := range listenErrorTests { + ln, err := Listen(tt.network, tt.address) + if err == nil { + t.Errorf("#%d: should fail; %s:%s->", i, tt.network, ln.Addr()) + ln.Close() + continue + } + if ln != nil { + t.Errorf("Listen returned non-nil interface %T(%v) with err != nil", ln, ln) + } + if err = parseDialError(err); err != nil { + t.Errorf("#%d: %v", i, err) + continue + } + } +} + +var listenPacketErrorTests = []struct { + network, address string +}{ + {"foo", ""}, + {"bar", "baz"}, + {"datakit", "mh/astro/r70"}, + {"udp", "127.0.0.1:☺"}, + {"udp", "no-such-name:80"}, + {"udp", "mh/astro/r70:http"}, +} + +func TestListenPacketError(t *testing.T) { + switch runtime.GOOS { + case "plan9": + t.Skipf("%s does not have full support of socktest", runtime.GOOS) + } + + origTestHookLookupIP := testHookLookupIP + defer func() { testHookLookupIP = origTestHookLookupIP }() + testHookLookupIP = func(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, error) { + return nil, &DNSError{Err: "listen error test", Name: "name", Server: "server", IsTimeout: true} + } + + for i, tt := range listenPacketErrorTests { + c, err := ListenPacket(tt.network, tt.address) + if err == nil { + t.Errorf("#%d: should fail; %s:%s->", i, tt.network, c.LocalAddr()) + c.Close() + continue + } + if c != nil { + t.Errorf("ListenPacket returned non-nil interface %T(%v) with err != nil", c, c) + } + if err = parseDialError(err); err != nil { + t.Errorf("#%d: %v", i, err) + continue + } + } +} + +func TestProtocolListenError(t *testing.T) { + switch runtime.GOOS { + case "nacl", "plan9": + t.Skipf("not supported on %s", runtime.GOOS) + } + + for _, network := range []string{"tcp", "udp", "ip:4294967296", "unix", "unixpacket", "unixgram"} { + var err error + switch network { + case "tcp": + _, err = ListenTCP(network, &TCPAddr{Port: 1 << 16}) + case "udp": + _, err = ListenUDP(network, &UDPAddr{Port: 1 << 16}) + case "ip:4294967296": + _, err = ListenIP(network, nil) + case "unix", "unixpacket": + _, err = ListenUnix(network, &UnixAddr{Name: "//"}) + case "unixgram": + _, err = ListenUnixgram(network, &UnixAddr{Name: "//"}) + } + if err == nil { + t.Errorf("%s: should fail", network) + continue + } + if err = parseDialError(err); err != nil { + t.Errorf("%s: %v", network, err) + continue + } + } +} + +// parseReadError parses nestedErr and reports whether it is a valid +// error value from Read functions. +// It returns nil when nestedErr is valid. +func parseReadError(nestedErr error) error { + if nestedErr == nil { + return nil + } + + switch err := nestedErr.(type) { + case *OpError: + if err := err.isValid(); err != nil { + return err + } + nestedErr = err.Err + goto second + } + if nestedErr == io.EOF { + return nil + } + return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr) + +second: + if isPlatformError(nestedErr) { + return nil + } + switch err := nestedErr.(type) { + case *os.SyscallError: + nestedErr = err.Err + goto third + } + switch nestedErr { + case errClosing, errTimeout: + return nil + } + return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr) + +third: + if isPlatformError(nestedErr) { + return nil + } + return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr) +} + +// parseWriteError parses nestedErr and reports whether it is a valid +// error value from Write functions. +// It returns nil when nestedErr is valid. +func parseWriteError(nestedErr error) error { + if nestedErr == nil { + return nil + } + + switch err := nestedErr.(type) { + case *OpError: + if err := err.isValid(); err != nil { + return err + } + nestedErr = err.Err + goto second + } + return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr) + +second: + if isPlatformError(nestedErr) { + return nil + } + switch err := nestedErr.(type) { + case *AddrError, addrinfoErrno, *DNSError, InvalidAddrError, *ParseError, *timeoutError, UnknownNetworkError: + return nil + case *os.SyscallError: + nestedErr = err.Err + goto third + } + switch nestedErr { + case errClosing, errTimeout, ErrWriteToConnected, io.ErrUnexpectedEOF: + return nil + } + return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr) + +third: + if isPlatformError(nestedErr) { + return nil + } + return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr) +} + +// parseCloseError parses nestedErr and reports whether it is a valid +// error value from Close functions. +// It returns nil when nestedErr is valid. +func parseCloseError(nestedErr error) error { + if nestedErr == nil { + return nil + } + + switch err := nestedErr.(type) { + case *OpError: + if err := err.isValid(); err != nil { + return err + } + nestedErr = err.Err + goto second + } + return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr) + +second: + if isPlatformError(nestedErr) { + return nil + } + switch err := nestedErr.(type) { + case *os.SyscallError: + nestedErr = err.Err + goto third + case *os.PathError: // for Plan 9 + nestedErr = err.Err + goto third + } + switch nestedErr { + case errClosing: + return nil + } + return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr) + +third: + if isPlatformError(nestedErr) { + return nil + } + return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr) +} + +func TestCloseError(t *testing.T) { + ln, err := newLocalListener("tcp") + if err != nil { + t.Fatal(err) + } + defer ln.Close() + c, err := Dial(ln.Addr().Network(), ln.Addr().String()) + if err != nil { + t.Fatal(err) + } + defer c.Close() + + for i := 0; i < 3; i++ { + err = c.(*TCPConn).CloseRead() + if perr := parseCloseError(err); perr != nil { + t.Errorf("#%d: %v", i, perr) + } + } + for i := 0; i < 3; i++ { + err = c.(*TCPConn).CloseWrite() + if perr := parseCloseError(err); perr != nil { + t.Errorf("#%d: %v", i, perr) + } + } + for i := 0; i < 3; i++ { + err = c.Close() + if perr := parseCloseError(err); perr != nil { + t.Errorf("#%d: %v", i, perr) + } + err = ln.Close() + if perr := parseCloseError(err); perr != nil { + t.Errorf("#%d: %v", i, perr) + } + } + + pc, err := ListenPacket("udp", "127.0.0.1:0") + if err != nil { + t.Fatal(err) + } + defer pc.Close() + + for i := 0; i < 3; i++ { + err = pc.Close() + if perr := parseCloseError(err); perr != nil { + t.Errorf("#%d: %v", i, perr) + } + } +} + +// parseAcceptError parses nestedErr and reports whether it is a valid +// error value from Accept functions. +// It returns nil when nestedErr is valid. +func parseAcceptError(nestedErr error) error { + if nestedErr == nil { + return nil + } + + switch err := nestedErr.(type) { + case *OpError: + if err := err.isValid(); err != nil { + return err + } + nestedErr = err.Err + goto second + } + return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr) + +second: + if isPlatformError(nestedErr) { + return nil + } + switch err := nestedErr.(type) { + case *os.SyscallError: + nestedErr = err.Err + goto third + } + switch nestedErr { + case errClosing, errTimeout: + return nil + } + return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr) + +third: + if isPlatformError(nestedErr) { + return nil + } + return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr) +} + +func TestAcceptError(t *testing.T) { + handler := func(ls *localServer, ln Listener) { + for { + ln.(*TCPListener).SetDeadline(time.Now().Add(5 * time.Millisecond)) + c, err := ln.Accept() + if perr := parseAcceptError(err); perr != nil { + t.Error(perr) + } + if err != nil { + if c != nil { + t.Errorf("Accept returned non-nil interface %T(%v) with err != nil", c, c) + } + if nerr, ok := err.(Error); !ok || (!nerr.Timeout() && !nerr.Temporary()) { + return + } + continue + } + c.Close() + } + } + ls, err := newLocalServer("tcp") + if err != nil { + t.Fatal(err) + } + if err := ls.buildup(handler); err != nil { + ls.teardown() + t.Fatal(err) + } + + time.Sleep(100 * time.Millisecond) + ls.teardown() +} + +// parseCommonError parses nestedErr and reports whether it is a valid +// error value from miscellaneous functions. +// It returns nil when nestedErr is valid. +func parseCommonError(nestedErr error) error { + if nestedErr == nil { + return nil + } + + switch err := nestedErr.(type) { + case *OpError: + if err := err.isValid(); err != nil { + return err + } + nestedErr = err.Err + goto second + } + return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr) + +second: + if isPlatformError(nestedErr) { + return nil + } + switch err := nestedErr.(type) { + case *os.SyscallError: + nestedErr = err.Err + goto third + case *os.LinkError: + nestedErr = err.Err + goto third + case *os.PathError: + nestedErr = err.Err + goto third + } + switch nestedErr { + case errClosing: + return nil + } + return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr) + +third: + if isPlatformError(nestedErr) { + return nil + } + return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr) +} + +func TestFileError(t *testing.T) { + switch runtime.GOOS { + case "windows": + t.Skipf("not supported on %s", runtime.GOOS) + } + + f, err := ioutil.TempFile("", "go-nettest") + if err != nil { + t.Fatal(err) + } + defer os.Remove(f.Name()) + defer f.Close() + + c, err := FileConn(f) + if err != nil { + if c != nil { + t.Errorf("FileConn returned non-nil interface %T(%v) with err != nil", c, c) + } + if perr := parseCommonError(err); perr != nil { + t.Error(perr) + } + } else { + c.Close() + t.Error("should fail") + } + ln, err := FileListener(f) + if err != nil { + if ln != nil { + t.Errorf("FileListener returned non-nil interface %T(%v) with err != nil", ln, ln) + } + if perr := parseCommonError(err); perr != nil { + t.Error(perr) + } + } else { + ln.Close() + t.Error("should fail") + } + pc, err := FilePacketConn(f) + if err != nil { + if pc != nil { + t.Errorf("FilePacketConn returned non-nil interface %T(%v) with err != nil", pc, pc) + } + if perr := parseCommonError(err); perr != nil { + t.Error(perr) + } + } else { + pc.Close() + t.Error("should fail") + } + + ln, err = newLocalListener("tcp") + if err != nil { + t.Fatal(err) + } + + for i := 0; i < 3; i++ { + f, err := ln.(*TCPListener).File() + if err != nil { + if perr := parseCommonError(err); perr != nil { + t.Error(perr) + } + } else { + f.Close() + } + ln.Close() + } +} diff --git a/libgo/go/net/external_test.go b/libgo/go/net/external_test.go new file mode 100644 index 00000000000..d5ff2be20a3 --- /dev/null +++ b/libgo/go/net/external_test.go @@ -0,0 +1,167 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package net + +import ( + "fmt" + "io" + "strings" + "testing" +) + +func TestResolveGoogle(t *testing.T) { + if testing.Short() || !*testExternal { + t.Skip("avoid external network") + } + if !supportsIPv4 || !supportsIPv6 || !*testIPv4 || !*testIPv6 { + t.Skip("both IPv4 and IPv6 are required") + } + + for _, network := range []string{"tcp", "tcp4", "tcp6"} { + addr, err := ResolveTCPAddr(network, "www.google.com:http") + if err != nil { + t.Error(err) + continue + } + switch { + case network == "tcp" && addr.IP.To4() == nil: + fallthrough + case network == "tcp4" && addr.IP.To4() == nil: + t.Errorf("got %v; want an IPv4 address on %s", addr, network) + case network == "tcp6" && (addr.IP.To16() == nil || addr.IP.To4() != nil): + t.Errorf("got %v; want an IPv6 address on %s", addr, network) + } + } +} + +var dialGoogleTests = []struct { + dial func(string, string) (Conn, error) + unreachableNetwork string + networks []string + addrs []string +}{ + { + dial: (&Dialer{DualStack: true}).Dial, + networks: []string{"tcp", "tcp4", "tcp6"}, + addrs: []string{"www.google.com:http"}, + }, + { + dial: Dial, + unreachableNetwork: "tcp6", + networks: []string{"tcp", "tcp4"}, + }, + { + dial: Dial, + unreachableNetwork: "tcp4", + networks: []string{"tcp", "tcp6"}, + }, +} + +func TestDialGoogle(t *testing.T) { + if testing.Short() || !*testExternal { + t.Skip("avoid external network") + } + if !supportsIPv4 || !supportsIPv6 || !*testIPv4 || !*testIPv6 { + t.Skip("both IPv4 and IPv6 are required") + } + + var err error + dialGoogleTests[1].addrs, dialGoogleTests[2].addrs, err = googleLiteralAddrs() + if err != nil { + t.Error(err) + } + for _, tt := range dialGoogleTests { + for _, network := range tt.networks { + disableSocketConnect(tt.unreachableNetwork) + for _, addr := range tt.addrs { + if err := fetchGoogle(tt.dial, network, addr); err != nil { + t.Error(err) + } + } + enableSocketConnect() + } + } +} + +var ( + literalAddrs4 = [...]string{ + "%d.%d.%d.%d:80", + "www.google.com:80", + "%d.%d.%d.%d:http", + "www.google.com:http", + "%03d.%03d.%03d.%03d:0080", + "[::ffff:%d.%d.%d.%d]:80", + "[::ffff:%02x%02x:%02x%02x]:80", + "[0:0:0:0:0000:ffff:%d.%d.%d.%d]:80", + "[0:0:0:0:000000:ffff:%d.%d.%d.%d]:80", + "[0:0:0:0::ffff:%d.%d.%d.%d]:80", + } + literalAddrs6 = [...]string{ + "[%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:80", + "ipv6.google.com:80", + "[%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:http", + "ipv6.google.com:http", + } +) + +func googleLiteralAddrs() (lits4, lits6 []string, err error) { + ips, err := LookupIP("www.google.com") + if err != nil { + return nil, nil, err + } + if len(ips) == 0 { + return nil, nil, nil + } + var ip4, ip6 IP + for _, ip := range ips { + if ip4 == nil && ip.To4() != nil { + ip4 = ip.To4() + } + if ip6 == nil && ip.To16() != nil && ip.To4() == nil { + ip6 = ip.To16() + } + if ip4 != nil && ip6 != nil { + break + } + } + if ip4 != nil { + for i, lit4 := range literalAddrs4 { + if strings.Contains(lit4, "%") { + literalAddrs4[i] = fmt.Sprintf(lit4, ip4[0], ip4[1], ip4[2], ip4[3]) + } + } + lits4 = literalAddrs4[:] + } + if ip6 != nil { + for i, lit6 := range literalAddrs6 { + if strings.Contains(lit6, "%") { + literalAddrs6[i] = fmt.Sprintf(lit6, ip6[0], ip6[1], ip6[2], ip6[3], ip6[4], ip6[5], ip6[6], ip6[7], ip6[8], ip6[9], ip6[10], ip6[11], ip6[12], ip6[13], ip6[14], ip6[15]) + } + } + lits6 = literalAddrs6[:] + } + return +} + +func fetchGoogle(dial func(string, string) (Conn, error), network, address string) error { + c, err := dial(network, address) + if err != nil { + return err + } + defer c.Close() + req := []byte("GET /robots.txt HTTP/1.0\r\nHost: www.google.com\r\n\r\n") + if _, err := c.Write(req); err != nil { + return err + } + b := make([]byte, 1000) + n, err := io.ReadFull(c, b) + if err != nil { + return err + } + if n < 1000 { + return fmt.Errorf("short read from %s:%s->%s", network, c.RemoteAddr(), c.LocalAddr()) + } + return nil +} diff --git a/libgo/go/net/fd_plan9.go b/libgo/go/net/fd_plan9.go index 5fe8effc295..32766f53b58 100644 --- a/libgo/go/net/fd_plan9.go +++ b/libgo/go/net/fd_plan9.go @@ -11,13 +11,13 @@ import ( "time" ) -// Network file descritor. +// Network file descriptor. type netFD struct { // locking/lifetime of sysfd + serialize access to Read and Write methods fdmu fdMutex // immutable until Close - proto string + net string n string dir string ctl, data *os.File @@ -38,8 +38,8 @@ func dial(net string, ra Addr, dialer func(time.Time) (Conn, error), deadline ti return dialChannel(net, ra, dialer, deadline) } -func newFD(proto, name string, ctl, data *os.File, laddr, raddr Addr) (*netFD, error) { - return &netFD{proto: proto, n: name, dir: netdir + "/" + proto + "/" + name, ctl: ctl, data: data, laddr: laddr, raddr: raddr}, nil +func newFD(net, name string, ctl, data *os.File, laddr, raddr Addr) (*netFD, error) { + return &netFD{net: net, n: name, dir: netdir + "/" + net + "/" + name, ctl: ctl, data: data, laddr: laddr, raddr: raddr}, nil } func (fd *netFD) init() error { @@ -55,7 +55,7 @@ func (fd *netFD) name() string { if fd.raddr != nil { rs = fd.raddr.String() } - return fd.proto + ":" + ls + "->" + rs + return fd.net + ":" + ls + "->" + rs } func (fd *netFD) ok() bool { return fd != nil && fd.ctl != nil } @@ -132,7 +132,7 @@ func (fd *netFD) Read(b []byte) (n int, err error) { } defer fd.readUnlock() n, err = fd.data.Read(b) - if fd.proto == "udp" && err == io.EOF { + if fd.net == "udp" && err == io.EOF { n = 0 err = nil } @@ -202,7 +202,7 @@ func (fd *netFD) file(f *os.File, s string) (*os.File, error) { dfd, err := syscall.Dup(int(f.Fd()), -1) syscall.ForkLock.RUnlock() if err != nil { - return nil, &OpError{"dup", s, fd.laddr, err} + return nil, os.NewSyscallError("dup", err) } return os.NewFile(uintptr(dfd), s), nil } @@ -226,7 +226,3 @@ func setReadBuffer(fd *netFD, bytes int) error { func setWriteBuffer(fd *netFD, bytes int) error { return syscall.EPLAN9 } - -func skipRawSocketTests() (skip bool, skipmsg string, err error) { - return true, "skipping test on plan9", nil -} diff --git a/libgo/go/net/fd_poll_nacl.go b/libgo/go/net/fd_poll_nacl.go index a3701f87648..cdf14e32ce8 100644 --- a/libgo/go/net/fd_poll_nacl.go +++ b/libgo/go/net/fd_poll_nacl.go @@ -18,18 +18,11 @@ func (pd *pollDesc) Init(fd *netFD) error { pd.fd = fd; return nil } func (pd *pollDesc) Close() {} -func (pd *pollDesc) Lock() {} - -func (pd *pollDesc) Unlock() {} - -func (pd *pollDesc) Wakeup() {} - -func (pd *pollDesc) Evict() bool { +func (pd *pollDesc) Evict() { pd.closing = true if pd.fd != nil { syscall.StopIO(pd.fd.sysfd) } - return false } func (pd *pollDesc) Prepare(mode int) error { diff --git a/libgo/go/net/fd_poll_runtime.go b/libgo/go/net/fd_poll_runtime.go index 2bddc836c75..8522ccebfb3 100644 --- a/libgo/go/net/fd_poll_runtime.go +++ b/libgo/go/net/fd_poll_runtime.go @@ -48,23 +48,12 @@ func (pd *pollDesc) Close() { pd.runtimeCtx = 0 } -func (pd *pollDesc) Lock() { -} - -func (pd *pollDesc) Unlock() { -} - -func (pd *pollDesc) Wakeup() { -} - // Evict evicts fd from the pending list, unblocking any I/O running on fd. -// Return value is whether the pollServer should be woken up. -func (pd *pollDesc) Evict() bool { +func (pd *pollDesc) Evict() { if pd.runtimeCtx == 0 { - return false + return } runtime_pollUnblock(pd.runtimeCtx) - return false } func (pd *pollDesc) Prepare(mode int) error { diff --git a/libgo/go/net/fd_posix.go b/libgo/go/net/fd_posix.go new file mode 100644 index 00000000000..b4b908abacf --- /dev/null +++ b/libgo/go/net/fd_posix.go @@ -0,0 +1,21 @@ +// 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 darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows + +package net + +import ( + "io" + "syscall" +) + +// eofError returns io.EOF when fd is available for reading end of +// file. +func (fd *netFD) eofError(n int, err error) error { + if n == 0 && err == nil && fd.sotype != syscall.SOCK_DGRAM && fd.sotype != syscall.SOCK_RAW { + return io.EOF + } + return err +} diff --git a/libgo/go/net/fd_posix_test.go b/libgo/go/net/fd_posix_test.go new file mode 100644 index 00000000000..85711ef1b70 --- /dev/null +++ b/libgo/go/net/fd_posix_test.go @@ -0,0 +1,57 @@ +// 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 darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows + +package net + +import ( + "io" + "syscall" + "testing" +) + +var eofErrorTests = []struct { + n int + err error + fd *netFD + expected error +}{ + {100, nil, &netFD{sotype: syscall.SOCK_STREAM}, nil}, + {100, io.EOF, &netFD{sotype: syscall.SOCK_STREAM}, io.EOF}, + {100, errClosing, &netFD{sotype: syscall.SOCK_STREAM}, errClosing}, + {0, nil, &netFD{sotype: syscall.SOCK_STREAM}, io.EOF}, + {0, io.EOF, &netFD{sotype: syscall.SOCK_STREAM}, io.EOF}, + {0, errClosing, &netFD{sotype: syscall.SOCK_STREAM}, errClosing}, + + {100, nil, &netFD{sotype: syscall.SOCK_DGRAM}, nil}, + {100, io.EOF, &netFD{sotype: syscall.SOCK_DGRAM}, io.EOF}, + {100, errClosing, &netFD{sotype: syscall.SOCK_DGRAM}, errClosing}, + {0, nil, &netFD{sotype: syscall.SOCK_DGRAM}, nil}, + {0, io.EOF, &netFD{sotype: syscall.SOCK_DGRAM}, io.EOF}, + {0, errClosing, &netFD{sotype: syscall.SOCK_DGRAM}, errClosing}, + + {100, nil, &netFD{sotype: syscall.SOCK_SEQPACKET}, nil}, + {100, io.EOF, &netFD{sotype: syscall.SOCK_SEQPACKET}, io.EOF}, + {100, errClosing, &netFD{sotype: syscall.SOCK_SEQPACKET}, errClosing}, + {0, nil, &netFD{sotype: syscall.SOCK_SEQPACKET}, io.EOF}, + {0, io.EOF, &netFD{sotype: syscall.SOCK_SEQPACKET}, io.EOF}, + {0, errClosing, &netFD{sotype: syscall.SOCK_SEQPACKET}, errClosing}, + + {100, nil, &netFD{sotype: syscall.SOCK_RAW}, nil}, + {100, io.EOF, &netFD{sotype: syscall.SOCK_RAW}, io.EOF}, + {100, errClosing, &netFD{sotype: syscall.SOCK_RAW}, errClosing}, + {0, nil, &netFD{sotype: syscall.SOCK_RAW}, nil}, + {0, io.EOF, &netFD{sotype: syscall.SOCK_RAW}, io.EOF}, + {0, errClosing, &netFD{sotype: syscall.SOCK_RAW}, errClosing}, +} + +func TestEOFError(t *testing.T) { + for _, tt := range eofErrorTests { + actual := tt.fd.eofError(tt.n, tt.err) + if actual != tt.expected { + t.Errorf("eofError(%v, %v, %v): expected %v, actual %v", tt.n, tt.err, tt.fd.sotype, tt.expected, actual) + } + } +} diff --git a/libgo/go/net/fd_unix.go b/libgo/go/net/fd_unix.go index 45a4eb8f123..465023fb23d 100644 --- a/libgo/go/net/fd_unix.go +++ b/libgo/go/net/fd_unix.go @@ -72,7 +72,7 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time) error { // Do not need to call fd.writeLock here, // because fd is not yet accessible to user, // so no concurrent operations are possible. - switch err := syscall.Connect(fd.sysfd, ra); err { + switch err := connectFunc(fd.sysfd, ra); err { case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR: case nil, syscall.EISCONN: if !deadline.IsZero() && deadline.Before(time.Now()) { @@ -87,13 +87,13 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time) error { // already been accepted and closed by the server. // Treat this as a successful connection--writes to // the socket will see EOF. For details and a test - // case in C see http://golang.org/issue/6828. + // case in C see https://golang.org/issue/6828. if runtime.GOOS == "solaris" { return nil } fallthrough default: - return err + return os.NewSyscallError("connect", err) } if err := fd.init(); err != nil { return err @@ -114,25 +114,25 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time) error { if err := fd.pd.WaitWrite(); err != nil { return err } - nerr, err := syscall.GetsockoptInt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR) + nerr, err := getsockoptIntFunc(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_ERROR) if err != nil { - return err + return os.NewSyscallError("getsockopt", err) } switch err := syscall.Errno(nerr); err { case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR: case syscall.Errno(0), syscall.EISCONN: return nil default: - return err + return os.NewSyscallError("getsockopt", err) } } } func (fd *netFD) destroy() { // Poller may want to unregister fd in readiness notification mechanism, - // so this must be executed before closesocket. + // so this must be executed before closeFunc. fd.pd.Close() - closesocket(fd.sysfd) + closeFunc(fd.sysfd) fd.sysfd = -1 runtime.SetFinalizer(fd, nil) } @@ -187,9 +187,7 @@ func (fd *netFD) writeUnlock() { } func (fd *netFD) Close() error { - fd.pd.Lock() // needed for both fd.incref(true) and pollDesc.Evict if !fd.fdmu.IncrefAndClose() { - fd.pd.Unlock() return errClosing } // Unblock any I/O. Once it all unblocks and returns, @@ -197,12 +195,8 @@ func (fd *netFD) Close() error { // the final decref will close fd.sysfd. This should happen // fairly quickly, since all the I/O is non-blocking, and any // attempts to block in the pollDesc will return errClosing. - doWakeup := fd.pd.Evict() - fd.pd.Unlock() + fd.pd.Evict() fd.decref() - if doWakeup { - fd.pd.Wakeup() - } return nil } @@ -211,11 +205,7 @@ func (fd *netFD) shutdown(how int) error { return err } defer fd.decref() - err := syscall.Shutdown(fd.sysfd, how) - if err != nil { - return &OpError{"shutdown", fd.net, fd.laddr, err} - } - return nil + return os.NewSyscallError("shutdown", syscall.Shutdown(fd.sysfd, how)) } func (fd *netFD) closeRead() error { @@ -232,10 +222,10 @@ func (fd *netFD) Read(p []byte) (n int, err error) { } defer fd.readUnlock() if err := fd.pd.PrepareRead(); err != nil { - return 0, &OpError{"read", fd.net, fd.raddr, err} + return 0, err } for { - n, err = syscall.Read(int(fd.sysfd), p) + n, err = syscall.Read(fd.sysfd, p) if err != nil { n = 0 if err == syscall.EAGAIN { @@ -244,11 +234,11 @@ func (fd *netFD) Read(p []byte) (n int, err error) { } } } - err = chkReadErr(n, err, fd) + err = fd.eofError(n, err) break } - if err != nil && err != io.EOF { - err = &OpError{"read", fd.net, fd.raddr, err} + if _, ok := err.(syscall.Errno); ok { + err = os.NewSyscallError("read", err) } return } @@ -259,7 +249,7 @@ func (fd *netFD) readFrom(p []byte) (n int, sa syscall.Sockaddr, err error) { } defer fd.readUnlock() if err := fd.pd.PrepareRead(); err != nil { - return 0, nil, &OpError{"read", fd.net, fd.laddr, err} + return 0, nil, err } for { n, sa, err = syscall.Recvfrom(fd.sysfd, p, 0) @@ -271,11 +261,11 @@ func (fd *netFD) readFrom(p []byte) (n int, sa syscall.Sockaddr, err error) { } } } - err = chkReadErr(n, err, fd) + err = fd.eofError(n, err) break } - if err != nil && err != io.EOF { - err = &OpError{"read", fd.net, fd.laddr, err} + if _, ok := err.(syscall.Errno); ok { + err = os.NewSyscallError("recvfrom", err) } return } @@ -286,7 +276,7 @@ func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.S } defer fd.readUnlock() if err := fd.pd.PrepareRead(); err != nil { - return 0, 0, 0, nil, &OpError{"read", fd.net, fd.laddr, err} + return 0, 0, 0, nil, err } for { n, oobn, flags, sa, err = syscall.Recvmsg(fd.sysfd, p, oob, 0) @@ -298,33 +288,26 @@ func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.S } } } - err = chkReadErr(n, err, fd) + err = fd.eofError(n, err) break } - if err != nil && err != io.EOF { - err = &OpError{"read", fd.net, fd.laddr, err} + if _, ok := err.(syscall.Errno); ok { + err = os.NewSyscallError("recvmsg", err) } return } -func chkReadErr(n int, err error, fd *netFD) error { - if n == 0 && err == nil && fd.sotype != syscall.SOCK_DGRAM && fd.sotype != syscall.SOCK_RAW { - return io.EOF - } - return err -} - func (fd *netFD) Write(p []byte) (nn int, err error) { if err := fd.writeLock(); err != nil { return 0, err } defer fd.writeUnlock() if err := fd.pd.PrepareWrite(); err != nil { - return 0, &OpError{"write", fd.net, fd.raddr, err} + return 0, err } for { var n int - n, err = syscall.Write(int(fd.sysfd), p[nn:]) + n, err = syscall.Write(fd.sysfd, p[nn:]) if n > 0 { nn += n } @@ -337,7 +320,6 @@ func (fd *netFD) Write(p []byte) (nn int, err error) { } } if err != nil { - n = 0 break } if n == 0 { @@ -345,8 +327,8 @@ func (fd *netFD) Write(p []byte) (nn int, err error) { break } } - if err != nil { - err = &OpError{"write", fd.net, fd.raddr, err} + if _, ok := err.(syscall.Errno); ok { + err = os.NewSyscallError("write", err) } return nn, err } @@ -357,7 +339,7 @@ func (fd *netFD) writeTo(p []byte, sa syscall.Sockaddr) (n int, err error) { } defer fd.writeUnlock() if err := fd.pd.PrepareWrite(); err != nil { - return 0, &OpError{"write", fd.net, fd.raddr, err} + return 0, err } for { err = syscall.Sendto(fd.sysfd, p, 0, sa) @@ -370,8 +352,9 @@ func (fd *netFD) writeTo(p []byte, sa syscall.Sockaddr) (n int, err error) { } if err == nil { n = len(p) - } else { - err = &OpError{"write", fd.net, fd.raddr, err} + } + if _, ok := err.(syscall.Errno); ok { + err = os.NewSyscallError("sendto", err) } return } @@ -382,7 +365,7 @@ func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oob } defer fd.writeUnlock() if err := fd.pd.PrepareWrite(); err != nil { - return 0, 0, &OpError{"write", fd.net, fd.raddr, err} + return 0, 0, err } for { n, err = syscall.SendmsgN(fd.sysfd, p, oob, sa, 0) @@ -395,8 +378,9 @@ func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oob } if err == nil { oobn = len(oob) - } else { - err = &OpError{"write", fd.net, fd.raddr, err} + } + if _, ok := err.(syscall.Errno); ok { + err = os.NewSyscallError("sendmsg", err) } return } @@ -410,27 +394,34 @@ func (fd *netFD) accept() (netfd *netFD, err error) { var s int var rsa syscall.Sockaddr if err = fd.pd.PrepareRead(); err != nil { - return nil, &OpError{"accept", fd.net, fd.laddr, err} + return nil, err } for { s, rsa, err = accept(fd.sysfd) if err != nil { - if err == syscall.EAGAIN { + nerr, ok := err.(*os.SyscallError) + if !ok { + return nil, err + } + switch nerr.Err { + case syscall.EAGAIN: if err = fd.pd.WaitRead(); err == nil { continue } - } else if err == syscall.ECONNABORTED { - // This means that a socket on the listen queue was closed - // before we Accept()ed it; it's a silly error, so try again. + case syscall.ECONNABORTED: + // This means that a socket on the + // listen queue was closed before we + // Accept()ed it; it's a silly error, + // so try again. continue } - return nil, &OpError{"accept", fd.net, fd.laddr, err} + return nil, err } break } if netfd, err = newFD(s, fd.family, fd.sotype, fd.net); err != nil { - closesocket(s) + closeFunc(s) return nil, err } if err = netfd.init(); err != nil { @@ -478,7 +469,7 @@ func dupCloseOnExec(fd int) (newfd int, err error) { // from now on. atomic.StoreInt32(&tryDupCloexec, 0) default: - return -1, e1 + return -1, os.NewSyscallError("fcntl", e1) } } return dupCloseOnExecOld(fd) @@ -491,7 +482,7 @@ func dupCloseOnExecOld(fd int) (newfd int, err error) { defer syscall.ForkLock.RUnlock() newfd, err = syscall.Dup(fd) if err != nil { - return -1, err + return -1, os.NewSyscallError("dup", err) } syscall.CloseOnExec(newfd) return @@ -500,7 +491,7 @@ func dupCloseOnExecOld(fd int) (newfd int, err error) { func (fd *netFD) dup() (f *os.File, err error) { ns, err := dupCloseOnExec(fd.sysfd) if err != nil { - return nil, &OpError{"dup", fd.net, fd.laddr, err} + return nil, err } // We want blocking mode for the new fd, hence the double negative. @@ -508,19 +499,8 @@ func (fd *netFD) dup() (f *os.File, err error) { // I/O will block the thread instead of letting us use the epoll server. // Everything will still work, just with more threads. if err = syscall.SetNonblock(ns, false); err != nil { - return nil, &OpError{"setnonblock", fd.net, fd.laddr, err} + return nil, os.NewSyscallError("setnonblock", err) } return os.NewFile(uintptr(ns), fd.name()), nil } - -func closesocket(s int) error { - return syscall.Close(s) -} - -func skipRawSocketTests() (skip bool, skipmsg string, err error) { - if os.Getuid() != 0 { - return true, "skipping test; must be root", nil - } - return false, "", nil -} diff --git a/libgo/go/net/fd_unix_test.go b/libgo/go/net/fd_unix_test.go deleted file mode 100644 index fe8e8ff6a88..00000000000 --- a/libgo/go/net/fd_unix_test.go +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build darwin dragonfly freebsd linux netbsd openbsd solaris - -package net - -import ( - "io" - "syscall" - "testing" -) - -var chkReadErrTests = []struct { - n int - err error - fd *netFD - expected error -}{ - - {100, nil, &netFD{sotype: syscall.SOCK_STREAM}, nil}, - {100, io.EOF, &netFD{sotype: syscall.SOCK_STREAM}, io.EOF}, - {100, errClosing, &netFD{sotype: syscall.SOCK_STREAM}, errClosing}, - {0, nil, &netFD{sotype: syscall.SOCK_STREAM}, io.EOF}, - {0, io.EOF, &netFD{sotype: syscall.SOCK_STREAM}, io.EOF}, - {0, errClosing, &netFD{sotype: syscall.SOCK_STREAM}, errClosing}, - - {100, nil, &netFD{sotype: syscall.SOCK_DGRAM}, nil}, - {100, io.EOF, &netFD{sotype: syscall.SOCK_DGRAM}, io.EOF}, - {100, errClosing, &netFD{sotype: syscall.SOCK_DGRAM}, errClosing}, - {0, nil, &netFD{sotype: syscall.SOCK_DGRAM}, nil}, - {0, io.EOF, &netFD{sotype: syscall.SOCK_DGRAM}, io.EOF}, - {0, errClosing, &netFD{sotype: syscall.SOCK_DGRAM}, errClosing}, - - {100, nil, &netFD{sotype: syscall.SOCK_SEQPACKET}, nil}, - {100, io.EOF, &netFD{sotype: syscall.SOCK_SEQPACKET}, io.EOF}, - {100, errClosing, &netFD{sotype: syscall.SOCK_SEQPACKET}, errClosing}, - {0, nil, &netFD{sotype: syscall.SOCK_SEQPACKET}, io.EOF}, - {0, io.EOF, &netFD{sotype: syscall.SOCK_SEQPACKET}, io.EOF}, - {0, errClosing, &netFD{sotype: syscall.SOCK_SEQPACKET}, errClosing}, - - {100, nil, &netFD{sotype: syscall.SOCK_RAW}, nil}, - {100, io.EOF, &netFD{sotype: syscall.SOCK_RAW}, io.EOF}, - {100, errClosing, &netFD{sotype: syscall.SOCK_RAW}, errClosing}, - {0, nil, &netFD{sotype: syscall.SOCK_RAW}, nil}, - {0, io.EOF, &netFD{sotype: syscall.SOCK_RAW}, io.EOF}, - {0, errClosing, &netFD{sotype: syscall.SOCK_RAW}, errClosing}, -} - -func TestChkReadErr(t *testing.T) { - for _, tt := range chkReadErrTests { - actual := chkReadErr(tt.n, tt.err, tt.fd) - if actual != tt.expected { - t.Errorf("chkReadError(%v, %v, %v): expected %v, actual %v", tt.n, tt.err, tt.fd.sotype, tt.expected, actual) - } - } -} diff --git a/libgo/go/net/fd_windows.go b/libgo/go/net/fd_windows.go index f3a534a1de0..205daff9e46 100644 --- a/libgo/go/net/fd_windows.go +++ b/libgo/go/net/fd_windows.go @@ -5,8 +5,6 @@ package net import ( - "errors" - "io" "os" "runtime" "sync" @@ -40,7 +38,7 @@ func sysInit() { var d syscall.WSAData e := syscall.WSAStartup(uint32(0x202), &d) if e != nil { - initErr = os.NewSyscallError("WSAStartup", e) + initErr = os.NewSyscallError("wsastartup", e) } canCancelIO = syscall.LoadCancelIoEx() == nil if syscall.LoadGetAddrInfo() == nil { @@ -70,10 +68,6 @@ func sysInit() { } } -func closesocket(s syscall.Handle) error { - return syscall.Closesocket(s) -} - func canUseConnectEx(net string) bool { switch net { case "udp", "udp4", "udp6", "ip", "ip4", "ip6": @@ -159,7 +153,7 @@ func (s *ioSrv) ExecIO(o *operation, name string, submit func(o *operation) erro // Notify runtime netpoll about starting IO. err := fd.pd.Prepare(int(o.mode)) if err != nil { - return 0, &OpError{name, fd.net, fd.laddr, err} + return 0, err } // Start IO. if canCancelIO { @@ -182,7 +176,7 @@ func (s *ioSrv) ExecIO(o *operation, name string, submit func(o *operation) erro // IO started, and we have to wait for its completion. err = nil default: - return 0, &OpError{name, fd.net, fd.laddr, err} + return 0, err } // Wait for our request to complete. err = fd.pd.Wait(int(o.mode)) @@ -190,7 +184,7 @@ func (s *ioSrv) ExecIO(o *operation, name string, submit func(o *operation) erro // All is good. Extract our IO results and return. if o.errno != 0 { err = syscall.Errno(o.errno) - return 0, &OpError{name, fd.net, fd.laddr, err} + return 0, err } return int(o.qty), nil } @@ -221,7 +215,7 @@ func (s *ioSrv) ExecIO(o *operation, name string, submit func(o *operation) erro if err == syscall.ERROR_OPERATION_ABORTED { // IO Canceled err = netpollErr } - return 0, &OpError{name, fd.net, fd.laddr, err} + return 0, err } // We issued cancellation request. But, it seems, IO operation succeeded // before cancellation request run. We need to treat IO operation as @@ -303,7 +297,7 @@ func (fd *netFD) init() error { size := uint32(unsafe.Sizeof(flag)) err := syscall.WSAIoctl(fd.sysfd, syscall.SIO_UDP_CONNRESET, (*byte)(unsafe.Pointer(&flag)), size, nil, 0, &ret, nil, 0) if err != nil { - return os.NewSyscallError("WSAIoctl", err) + return os.NewSyscallError("wsaioctl", err) } } fd.rop.mode = 'r' @@ -337,7 +331,7 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time) error { defer fd.setWriteDeadline(noDeadline) } if !canUseConnectEx(fd.net) { - return syscall.Connect(fd.sysfd, ra) + return os.NewSyscallError("connect", connectFunc(fd.sysfd, ra)) } // ConnectEx windows API requires an unconnected, previously bound socket. if la == nil { @@ -350,20 +344,23 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time) error { panic("unexpected type in connect") } if err := syscall.Bind(fd.sysfd, la); err != nil { - return err + return os.NewSyscallError("bind", err) } } // Call ConnectEx API. o := &fd.wop o.sa = ra _, err := wsrv.ExecIO(o, "ConnectEx", func(o *operation) error { - return syscall.ConnectEx(o.fd.sysfd, o.sa, nil, 0, nil, &o.o) + return connectExFunc(o.fd.sysfd, o.sa, nil, 0, nil, &o.o) }) if err != nil { + if _, ok := err.(syscall.Errno); ok { + err = os.NewSyscallError("connectex", err) + } return err } // Refresh socket properties. - return syscall.Setsockopt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_UPDATE_CONNECT_CONTEXT, (*byte)(unsafe.Pointer(&fd.sysfd)), int32(unsafe.Sizeof(fd.sysfd))) + return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_UPDATE_CONNECT_CONTEXT, (*byte)(unsafe.Pointer(&fd.sysfd)), int32(unsafe.Sizeof(fd.sysfd)))) } func (fd *netFD) destroy() { @@ -371,9 +368,9 @@ func (fd *netFD) destroy() { return } // Poller may want to unregister fd in readiness notification mechanism, - // so this must be executed before closesocket. + // so this must be executed before closeFunc. fd.pd.Close() - closesocket(fd.sysfd) + closeFunc(fd.sysfd) fd.sysfd = syscall.InvalidHandle // no need for a finalizer anymore runtime.SetFinalizer(fd, nil) @@ -443,11 +440,7 @@ func (fd *netFD) shutdown(how int) error { return err } defer fd.decref() - err := syscall.Shutdown(fd.sysfd, how) - if err != nil { - return &OpError{"shutdown", fd.net, fd.laddr, err} - } - return nil + return syscall.Shutdown(fd.sysfd, how) } func (fd *netFD) closeRead() error { @@ -468,16 +461,17 @@ func (fd *netFD) Read(buf []byte) (int, error) { n, err := rsrv.ExecIO(o, "WSARecv", func(o *operation) error { return syscall.WSARecv(o.fd.sysfd, &o.buf, 1, &o.qty, &o.flags, &o.o, nil) }) - if err == nil && n == 0 { - err = io.EOF - } if raceenabled { raceAcquire(unsafe.Pointer(&ioSync)) } + err = fd.eofError(n, err) + if _, ok := err.(syscall.Errno); ok { + err = os.NewSyscallError("wsarecv", err) + } return n, err } -func (fd *netFD) readFrom(buf []byte) (n int, sa syscall.Sockaddr, err error) { +func (fd *netFD) readFrom(buf []byte) (int, syscall.Sockaddr, error) { if len(buf) == 0 { return 0, nil, nil } @@ -487,18 +481,22 @@ func (fd *netFD) readFrom(buf []byte) (n int, sa syscall.Sockaddr, err error) { defer fd.readUnlock() o := &fd.rop o.InitBuf(buf) - n, err = rsrv.ExecIO(o, "WSARecvFrom", func(o *operation) error { + n, err := rsrv.ExecIO(o, "WSARecvFrom", func(o *operation) error { if o.rsa == nil { o.rsa = new(syscall.RawSockaddrAny) } o.rsan = int32(unsafe.Sizeof(*o.rsa)) return syscall.WSARecvFrom(o.fd.sysfd, &o.buf, 1, &o.qty, &o.flags, o.rsa, &o.rsan, &o.o, nil) }) + err = fd.eofError(n, err) + if _, ok := err.(syscall.Errno); ok { + err = os.NewSyscallError("wsarecvfrom", err) + } if err != nil { - return 0, nil, err + return n, nil, err } - sa, _ = o.rsa.Sockaddr() - return + sa, _ := o.rsa.Sockaddr() + return n, sa, nil } func (fd *netFD) Write(buf []byte) (int, error) { @@ -511,9 +509,13 @@ func (fd *netFD) Write(buf []byte) (int, error) { } o := &fd.wop o.InitBuf(buf) - return wsrv.ExecIO(o, "WSASend", func(o *operation) error { + n, err := wsrv.ExecIO(o, "WSASend", func(o *operation) error { return syscall.WSASend(o.fd.sysfd, &o.buf, 1, &o.qty, 0, &o.o, nil) }) + if _, ok := err.(syscall.Errno); ok { + err = os.NewSyscallError("wsasend", err) + } + return n, err } func (fd *netFD) writeTo(buf []byte, sa syscall.Sockaddr) (int, error) { @@ -527,23 +529,27 @@ func (fd *netFD) writeTo(buf []byte, sa syscall.Sockaddr) (int, error) { o := &fd.wop o.InitBuf(buf) o.sa = sa - return wsrv.ExecIO(o, "WSASendto", func(o *operation) error { + n, err := wsrv.ExecIO(o, "WSASendto", func(o *operation) error { return syscall.WSASendto(o.fd.sysfd, &o.buf, 1, &o.qty, 0, o.sa, &o.o, nil) }) + if _, ok := err.(syscall.Errno); ok { + err = os.NewSyscallError("wsasendto", err) + } + return n, err } func (fd *netFD) acceptOne(rawsa []syscall.RawSockaddrAny, o *operation) (*netFD, error) { // Get new socket. s, err := sysSocket(fd.family, fd.sotype, 0) if err != nil { - return nil, &OpError{"socket", fd.net, fd.laddr, err} + return nil, err } // Associate our new socket with IOCP. netfd, err := newFD(s, fd.family, fd.sotype, fd.net) if err != nil { - closesocket(s) - return nil, &OpError{"accept", fd.net, fd.laddr, err} + closeFunc(s) + return nil, err } if err := netfd.init(); err != nil { fd.Close() @@ -558,6 +564,9 @@ func (fd *netFD) acceptOne(rawsa []syscall.RawSockaddrAny, o *operation) (*netFD }) if err != nil { netfd.Close() + if _, ok := err.(syscall.Errno); ok { + err = os.NewSyscallError("acceptex", err) + } return nil, err } @@ -565,7 +574,7 @@ func (fd *netFD) acceptOne(rawsa []syscall.RawSockaddrAny, o *operation) (*netFD err = syscall.Setsockopt(s, syscall.SOL_SOCKET, syscall.SO_UPDATE_ACCEPT_CONTEXT, (*byte)(unsafe.Pointer(&fd.sysfd)), int32(unsafe.Sizeof(fd.sysfd))) if err != nil { netfd.Close() - return nil, &OpError{"Setsockopt", fd.net, fd.laddr, err} + return nil, os.NewSyscallError("setsockopt", err) } return netfd, nil @@ -591,11 +600,11 @@ func (fd *netFD) accept() (*netFD, error) { // before AcceptEx could complete. These errors relate to new // connection, not to AcceptEx, so ignore broken connection and // try AcceptEx again for more connections. - operr, ok := err.(*OpError) + nerr, ok := err.(*os.SyscallError) if !ok { return nil, err } - errno, ok := operr.Err.(syscall.Errno) + errno, ok := nerr.Err.(syscall.Errno) if !ok { return nil, err } @@ -619,38 +628,17 @@ func (fd *netFD) accept() (*netFD, error) { return netfd, nil } -func skipRawSocketTests() (skip bool, skipmsg string, err error) { - // From http://msdn.microsoft.com/en-us/library/windows/desktop/ms740548.aspx: - // Note: To use a socket of type SOCK_RAW requires administrative privileges. - // Users running Winsock applications that use raw sockets must be a member of - // the Administrators group on the local computer, otherwise raw socket calls - // will fail with an error code of WSAEACCES. On Windows Vista and later, access - // for raw sockets is enforced at socket creation. In earlier versions of Windows, - // access for raw sockets is enforced during other socket operations. - s, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, 0) - if err == syscall.WSAEACCES { - return true, "skipping test; no access to raw socket allowed", nil - } - if err != nil { - return true, "", err - } - defer syscall.Closesocket(s) - return false, "", nil -} - // Unimplemented functions. func (fd *netFD) dup() (*os.File, error) { // TODO: Implement this - return nil, os.NewSyscallError("dup", syscall.EWINDOWS) + return nil, syscall.EWINDOWS } -var errNoSupport = errors.New("address family not supported") - func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) { - return 0, 0, 0, nil, errNoSupport + return 0, 0, 0, nil, syscall.EWINDOWS } func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) { - return 0, 0, errNoSupport + return 0, 0, syscall.EWINDOWS } diff --git a/libgo/go/net/file.go b/libgo/go/net/file.go new file mode 100644 index 00000000000..1aad477400c --- /dev/null +++ b/libgo/go/net/file.go @@ -0,0 +1,48 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package net + +import "os" + +type fileAddr string + +func (fileAddr) Network() string { return "file+net" } +func (f fileAddr) String() string { return string(f) } + +// FileConn returns a copy of the network connection corresponding to +// the open file f. +// It is the caller's responsibility to close f when finished. +// Closing c does not affect f, and closing f does not affect c. +func FileConn(f *os.File) (c Conn, err error) { + c, err = fileConn(f) + if err != nil { + err = &OpError{Op: "file", Net: "file+net", Source: nil, Addr: fileAddr(f.Name()), Err: err} + } + return +} + +// FileListener returns a copy of the network listener corresponding +// to the open file f. +// It is the caller's responsibility to close ln when finished. +// Closing ln does not affect f, and closing f does not affect ln. +func FileListener(f *os.File) (ln Listener, err error) { + ln, err = fileListener(f) + if err != nil { + err = &OpError{Op: "file", Net: "file+net", Source: nil, Addr: fileAddr(f.Name()), Err: err} + } + return +} + +// FilePacketConn returns a copy of the packet network connection +// corresponding to the open file f. +// It is the caller's responsibility to close f when finished. +// Closing c does not affect f, and closing f does not affect c. +func FilePacketConn(f *os.File) (c PacketConn, err error) { + c, err = filePacketConn(f) + if err != nil { + err = &OpError{Op: "file", Net: "file+net", Source: nil, Addr: fileAddr(f.Name()), Err: err} + } + return +} diff --git a/libgo/go/net/file_plan9.go b/libgo/go/net/file_plan9.go index 068f0881dd3..892775a024f 100644 --- a/libgo/go/net/file_plan9.go +++ b/libgo/go/net/file_plan9.go @@ -86,7 +86,7 @@ func newFileFD(f *os.File) (net *netFD, err error) { return newFD(comp[1], name, ctl, nil, laddr, nil) } -func newFileConn(f *os.File) (c Conn, err error) { +func fileConn(f *os.File) (Conn, error) { fd, err := newFileFD(f) if err != nil { return nil, err @@ -109,7 +109,7 @@ func newFileConn(f *os.File) (c Conn, err error) { return nil, syscall.EPLAN9 } -func newFileListener(f *os.File) (l Listener, err error) { +func fileListener(f *os.File) (Listener, error) { fd, err := newFileFD(f) if err != nil { return nil, err @@ -132,26 +132,6 @@ func newFileListener(f *os.File) (l Listener, err error) { return &TCPListener{fd}, nil } -// FileConn returns a copy of the network connection corresponding to -// the open file f. It is the caller's responsibility to close f when -// finished. Closing c does not affect f, and closing f does not -// affect c. -func FileConn(f *os.File) (c Conn, err error) { - return newFileConn(f) -} - -// FileListener returns a copy of the network listener corresponding -// to the open file f. It is the caller's responsibility to close l -// when finished. Closing l does not affect f, and closing f does not -// affect l. -func FileListener(f *os.File) (l Listener, err error) { - return newFileListener(f) -} - -// FilePacketConn returns a copy of the packet network connection -// corresponding to the open file f. It is the caller's -// responsibility to close f when finished. Closing c does not affect -// f, and closing f does not affect c. -func FilePacketConn(f *os.File) (c PacketConn, err error) { +func filePacketConn(f *os.File) (PacketConn, error) { return nil, syscall.EPLAN9 } diff --git a/libgo/go/net/file_stub.go b/libgo/go/net/file_stub.go index 4281072ef93..0f7460c7579 100644 --- a/libgo/go/net/file_stub.go +++ b/libgo/go/net/file_stub.go @@ -11,28 +11,6 @@ import ( "syscall" ) -// FileConn returns a copy of the network connection corresponding to -// the open file f. It is the caller's responsibility to close f when -// finished. Closing c does not affect f, and closing f does not -// affect c. -func FileConn(f *os.File) (c Conn, err error) { - return nil, syscall.ENOPROTOOPT - -} - -// FileListener returns a copy of the network listener corresponding -// to the open file f. It is the caller's responsibility to close l -// when finished. Closing l does not affect f, and closing f does not -// affect l. -func FileListener(f *os.File) (l Listener, err error) { - return nil, syscall.ENOPROTOOPT - -} - -// FilePacketConn returns a copy of the packet network connection -// corresponding to the open file f. It is the caller's -// responsibility to close f when finished. Closing c does not affect -// f, and closing f does not affect c. -func FilePacketConn(f *os.File) (c PacketConn, err error) { - return nil, syscall.ENOPROTOOPT -} +func fileConn(f *os.File) (Conn, error) { return nil, syscall.ENOPROTOOPT } +func fileListener(f *os.File) (Listener, error) { return nil, syscall.ENOPROTOOPT } +func filePacketConn(f *os.File) (PacketConn, error) { return nil, syscall.ENOPROTOOPT } diff --git a/libgo/go/net/file_test.go b/libgo/go/net/file_test.go index 6fab06a9c6e..003dbb2ecb7 100644 --- a/libgo/go/net/file_test.go +++ b/libgo/go/net/file_test.go @@ -27,77 +27,69 @@ type connFile interface { } func testFileListener(t *testing.T, net, laddr string) { - switch net { - case "tcp", "tcp4", "tcp6": - laddr += ":0" // any available port - } l, err := Listen(net, laddr) if err != nil { - t.Fatalf("Listen failed: %v", err) + t.Fatal(err) } defer l.Close() lf := l.(listenerFile) f, err := lf.File() if err != nil { - t.Fatalf("File failed: %v", err) + t.Fatal(err) } c, err := FileListener(f) if err != nil { - t.Fatalf("FileListener failed: %v", err) + t.Fatal(err) } if !reflect.DeepEqual(l.Addr(), c.Addr()) { - t.Fatalf("Addrs not equal: %#v != %#v", l.Addr(), c.Addr()) + t.Fatalf("got %#v; want%#v", l.Addr(), c.Addr()) } if err := c.Close(); err != nil { - t.Fatalf("Close failed: %v", err) + t.Fatal(err) } if err := f.Close(); err != nil { - t.Fatalf("Close failed: %v", err) + t.Fatal(err) } } 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: ":0"}, + {net: "tcp", laddr: "0.0.0.0:0"}, + {net: "tcp", laddr: "[::ffff:0.0.0.0]:0"}, + {net: "tcp", laddr: "[::]:0"}, - {net: "tcp", laddr: "127.0.0.1"}, - {net: "tcp", laddr: "[::ffff:127.0.0.1]"}, - {net: "tcp", laddr: "[::1]", ipv6: true}, + {net: "tcp", laddr: "127.0.0.1:0"}, + {net: "tcp", laddr: "[::ffff:127.0.0.1]:0"}, + {net: "tcp", laddr: "[::1]:0"}, - {net: "tcp4", laddr: ""}, - {net: "tcp4", laddr: "0.0.0.0"}, - {net: "tcp4", laddr: "[::ffff:0.0.0.0]"}, + {net: "tcp4", laddr: ":0"}, + {net: "tcp4", laddr: "0.0.0.0:0"}, + {net: "tcp4", laddr: "[::ffff:0.0.0.0]:0"}, - {net: "tcp4", laddr: "127.0.0.1"}, - {net: "tcp4", laddr: "[::ffff:127.0.0.1]"}, + {net: "tcp4", laddr: "127.0.0.1:0"}, + {net: "tcp4", laddr: "[::ffff:127.0.0.1]:0"}, - {net: "tcp6", laddr: "", ipv6: true}, - {net: "tcp6", laddr: "[::]", ipv6: true}, + {net: "tcp6", laddr: ":0"}, + {net: "tcp6", laddr: "[::]:0"}, - {net: "tcp6", laddr: "[::1]", ipv6: true}, + {net: "tcp6", laddr: "[::1]:0"}, - {net: "unix", laddr: "@gotest/net", linux: true}, - {net: "unixpacket", laddr: "@gotest/net", linux: true}, + {net: "unix", laddr: "@gotest/net"}, + {net: "unixpacket", laddr: "@gotest/net"}, } func TestFileListener(t *testing.T) { switch runtime.GOOS { case "nacl", "windows": - t.Skipf("skipping test on %q", runtime.GOOS) + t.Skipf("not supported on %s", runtime.GOOS) } 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) { + if !testableListenArgs(tt.net, tt.laddr, "") { + t.Logf("skipping %s test", tt.net+" "+tt.laddr) continue } testFileListener(t, tt.net, tt.laddr) @@ -107,86 +99,78 @@ func TestFileListener(t *testing.T) { func testFilePacketConn(t *testing.T, pcf packetConnFile, listen bool) { f, err := pcf.File() if err != nil { - t.Fatalf("File failed: %v", err) + t.Fatal(err) } c, err := FilePacketConn(f) if err != nil { - t.Fatalf("FilePacketConn failed: %v", err) + t.Fatal(err) } if !reflect.DeepEqual(pcf.LocalAddr(), c.LocalAddr()) { - t.Fatalf("LocalAddrs not equal: %#v != %#v", pcf.LocalAddr(), c.LocalAddr()) + t.Fatalf("got %#v; want %#v", pcf.LocalAddr(), c.LocalAddr()) } if listen { if _, err := c.WriteTo([]byte{}, c.LocalAddr()); err != nil { - t.Fatalf("WriteTo failed: %v", err) + t.Fatal(err) } } if err := c.Close(); err != nil { - t.Fatalf("Close failed: %v", err) + t.Fatal(err) } if err := f.Close(); err != nil { - t.Fatalf("Close failed: %v", err) + t.Fatal(err) } } 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("ListenPacket failed: %v", err) + t.Fatal(err) } testFilePacketConn(t, l.(packetConnFile), true) if err := l.Close(); err != nil { - t.Fatalf("Close failed: %v", err) + t.Fatal(err) } } 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) + t.Fatal(err) } testFilePacketConn(t, c.(packetConnFile), false) if err := c.Close(); err != nil { - t.Fatalf("Close failed: %v", err) + t.Fatal(err) } } 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 string + addr string }{ - {net: "udp", addr: "127.0.0.1"}, - {net: "udp", addr: "[::ffff:127.0.0.1]"}, - {net: "udp", addr: "[::1]", ipv6: true}, + {net: "udp", addr: "127.0.0.1:0"}, + {net: "udp", addr: "[::ffff:127.0.0.1]:0"}, + {net: "udp", addr: "[::1]:0"}, - {net: "udp4", addr: "127.0.0.1"}, - {net: "udp4", addr: "[::ffff:127.0.0.1]"}, + {net: "udp4", addr: "127.0.0.1:0"}, + {net: "udp4", addr: "[::ffff:127.0.0.1]:0"}, - {net: "udp6", addr: "[::1]", ipv6: true}, + {net: "udp6", addr: "[::1]:0"}, - {net: "ip4:icmp", addr: "127.0.0.1"}, + // TODO(mikioh,bradfitz): reenable once 10730 is fixed + // {net: "ip4:icmp", addr: "127.0.0.1"}, - {net: "unixgram", addr: "@gotest3/net", linux: true}, + {net: "unixgram", addr: "@gotest3/net"}, } func TestFilePacketConn(t *testing.T) { switch runtime.GOOS { case "nacl", "plan9", "windows": - t.Skipf("skipping test on %q", runtime.GOOS) + t.Skipf("not supported on %s", runtime.GOOS) } for _, tt := range filePacketConnTests { - if skipServerTest(tt.net, "unixgram", tt.addr, tt.ipv6, false, tt.linux) { + if !testableListenArgs(tt.net, tt.addr, "") { + t.Logf("skipping %s test", tt.net+" "+tt.addr) continue } if os.Getuid() != 0 && tt.net == "ip4:icmp" { @@ -194,12 +178,16 @@ func TestFilePacketConn(t *testing.T) { 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) + switch tt.net { + case "udp", "udp4", "udp6": + host, _, err := SplitHostPort(tt.addr) + if err != nil { + t.Error(err) + continue } + testFilePacketConnDial(t, tt.net, JoinHostPort(host, "12345")) + case "ip4:icmp": + testFilePacketConnDial(t, tt.net, tt.addr) } } } diff --git a/libgo/go/net/file_unix.go b/libgo/go/net/file_unix.go index 214a4196c8e..5b24c7d09d1 100644 --- a/libgo/go/net/file_unix.go +++ b/libgo/go/net/file_unix.go @@ -11,75 +11,59 @@ import ( "syscall" ) -func newFileFD(f *os.File) (*netFD, error) { - fd, err := dupCloseOnExec(int(f.Fd())) +func dupSocket(f *os.File) (int, error) { + s, err := dupCloseOnExec(int(f.Fd())) if err != nil { - return nil, os.NewSyscallError("dup", err) + return -1, err + } + if err := syscall.SetNonblock(s, true); err != nil { + closeFunc(s) + return -1, os.NewSyscallError("setnonblock", err) } + return s, nil +} - if err = syscall.SetNonblock(fd, true); err != nil { - closesocket(fd) +func newFileFD(f *os.File) (*netFD, error) { + s, err := dupSocket(f) + if err != nil { return nil, err } - - sotype, err := syscall.GetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_TYPE) + family := syscall.AF_UNSPEC + sotype, err := syscall.GetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_TYPE) if err != nil { - closesocket(fd) + closeFunc(s) return nil, os.NewSyscallError("getsockopt", err) } - - family := syscall.AF_UNSPEC - toAddr := sockaddrToTCP - lsa, _ := syscall.Getsockname(fd) + lsa, _ := syscall.Getsockname(s) + rsa, _ := syscall.Getpeername(s) switch lsa.(type) { - default: - closesocket(fd) - return nil, syscall.EINVAL case *syscall.SockaddrInet4: family = syscall.AF_INET - if sotype == syscall.SOCK_DGRAM { - toAddr = sockaddrToUDP - } else if sotype == syscall.SOCK_RAW { - toAddr = sockaddrToIP - } case *syscall.SockaddrInet6: family = syscall.AF_INET6 - if sotype == syscall.SOCK_DGRAM { - toAddr = sockaddrToUDP - } else if sotype == syscall.SOCK_RAW { - toAddr = sockaddrToIP - } case *syscall.SockaddrUnix: family = syscall.AF_UNIX - toAddr = sockaddrToUnix - if sotype == syscall.SOCK_DGRAM { - toAddr = sockaddrToUnixgram - } else if sotype == syscall.SOCK_SEQPACKET { - toAddr = sockaddrToUnixpacket - } + default: + closeFunc(s) + return nil, syscall.EPROTONOSUPPORT } - laddr := toAddr(lsa) - rsa, _ := syscall.Getpeername(fd) - raddr := toAddr(rsa) - - netfd, err := newFD(fd, family, sotype, laddr.Network()) + fd, err := newFD(s, family, sotype, "") if err != nil { - closesocket(fd) + closeFunc(s) return nil, err } - if err := netfd.init(); err != nil { - netfd.Close() + laddr := fd.addrFunc()(lsa) + raddr := fd.addrFunc()(rsa) + fd.net = laddr.Network() + if err := fd.init(); err != nil { + fd.Close() return nil, err } - netfd.setAddr(laddr, raddr) - return netfd, nil + fd.setAddr(laddr, raddr) + return fd, nil } -// FileConn returns a copy of the network connection corresponding to -// the open file f. It is the caller's responsibility to close f when -// finished. Closing c does not affect f, and closing f does not -// affect c. -func FileConn(f *os.File) (c Conn, err error) { +func fileConn(f *os.File) (Conn, error) { fd, err := newFileFD(f) if err != nil { return nil, err @@ -98,11 +82,7 @@ func FileConn(f *os.File) (c Conn, err error) { return nil, syscall.EINVAL } -// FileListener returns a copy of the network listener corresponding -// to the open file f. It is the caller's responsibility to close l -// when finished. Closing l does not affect f, and closing f does not -// affect l. -func FileListener(f *os.File) (l Listener, err error) { +func fileListener(f *os.File) (Listener, error) { fd, err := newFileFD(f) if err != nil { return nil, err @@ -117,11 +97,7 @@ func FileListener(f *os.File) (l Listener, err error) { return nil, syscall.EINVAL } -// FilePacketConn returns a copy of the packet network connection -// corresponding to the open file f. It is the caller's -// responsibility to close f when finished. Closing c does not affect -// f, and closing f does not affect c. -func FilePacketConn(f *os.File) (c PacketConn, err error) { +func filePacketConn(f *os.File) (PacketConn, error) { fd, err := newFileFD(f) if err != nil { return nil, err diff --git a/libgo/go/net/file_windows.go b/libgo/go/net/file_windows.go index ca2b9b2262c..241fa17617c 100644 --- a/libgo/go/net/file_windows.go +++ b/libgo/go/net/file_windows.go @@ -9,29 +9,17 @@ import ( "syscall" ) -// FileConn returns a copy of the network connection corresponding to -// the open file f. It is the caller's responsibility to close f when -// finished. Closing c does not affect f, and closing f does not -// affect c. -func FileConn(f *os.File) (c Conn, err error) { +func fileConn(f *os.File) (Conn, error) { // TODO: Implement this - return nil, os.NewSyscallError("FileConn", syscall.EWINDOWS) + return nil, syscall.EWINDOWS } -// FileListener returns a copy of the network listener corresponding -// to the open file f. It is the caller's responsibility to close l -// when finished. Closing l does not affect f, and closing f does not -// affect l. -func FileListener(f *os.File) (l Listener, err error) { +func fileListener(f *os.File) (Listener, error) { // TODO: Implement this - return nil, os.NewSyscallError("FileListener", syscall.EWINDOWS) + return nil, syscall.EWINDOWS } -// FilePacketConn returns a copy of the packet network connection -// corresponding to the open file f. It is the caller's -// responsibility to close f when finished. Closing c does not affect -// f, and closing f does not affect c. -func FilePacketConn(f *os.File) (c PacketConn, err error) { +func filePacketConn(f *os.File) (PacketConn, error) { // TODO: Implement this - return nil, os.NewSyscallError("FilePacketConn", syscall.EWINDOWS) + return nil, syscall.EWINDOWS } diff --git a/libgo/go/net/hook.go b/libgo/go/net/hook.go new file mode 100644 index 00000000000..9ab34c0e36f --- /dev/null +++ b/libgo/go/net/hook.go @@ -0,0 +1,12 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package net + +var ( + testHookDialTCP = dialTCP + testHookHostsPath = "/etc/hosts" + testHookLookupIP = func(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, error) { return fn(host) } + testHookSetKeepAlive = func() {} +) diff --git a/libgo/go/net/hook_cloexec.go b/libgo/go/net/hook_cloexec.go new file mode 100644 index 00000000000..870f0d78b12 --- /dev/null +++ b/libgo/go/net/hook_cloexec.go @@ -0,0 +1,14 @@ +// Copyright 2015 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 freebsd linux + +package net + +import "syscall" + +var ( + // Placeholders for socket system calls. + accept4Func func(int, int) (int, syscall.Sockaddr, error) = syscall.Accept4 +) diff --git a/libgo/go/net/hook_plan9.go b/libgo/go/net/hook_plan9.go new file mode 100644 index 00000000000..e053348505b --- /dev/null +++ b/libgo/go/net/hook_plan9.go @@ -0,0 +1,9 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package net + +import "time" + +var testHookDialChannel = func() { time.Sleep(time.Millisecond) } // see golang.org/issue/5349 diff --git a/libgo/go/net/hook_unix.go b/libgo/go/net/hook_unix.go new file mode 100644 index 00000000000..361ca5980c3 --- /dev/null +++ b/libgo/go/net/hook_unix.go @@ -0,0 +1,21 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris + +package net + +import "syscall" + +var ( + testHookDialChannel = func() {} // see golang.org/issue/5349 + + // Placeholders for socket system calls. + socketFunc func(int, int, int) (int, error) = syscall.Socket + closeFunc func(int) error = syscall.Close + connectFunc func(int, syscall.Sockaddr) error = syscall.Connect + listenFunc func(int, int) error = syscall.Listen + acceptFunc func(int) (int, syscall.Sockaddr, error) = syscall.Accept + getsockoptIntFunc func(int, int, int) (int, error) = syscall.GetsockoptInt +) diff --git a/libgo/go/net/hook_windows.go b/libgo/go/net/hook_windows.go new file mode 100644 index 00000000000..126b0ebdd10 --- /dev/null +++ b/libgo/go/net/hook_windows.go @@ -0,0 +1,21 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package net + +import ( + "syscall" + "time" +) + +var ( + testHookDialChannel = func() { time.Sleep(time.Millisecond) } // see golang.org/issue/5349 + + // Placeholders for socket system calls. + socketFunc func(int, int, int) (syscall.Handle, error) = syscall.Socket + closeFunc func(syscall.Handle) error = syscall.Closesocket + connectFunc func(syscall.Handle, syscall.Sockaddr) error = syscall.Connect + connectExFunc func(syscall.Handle, syscall.Sockaddr, *byte, uint32, *uint32, *syscall.Overlapped) error = syscall.ConnectEx + listenFunc func(syscall.Handle, int) error = syscall.Listen +) diff --git a/libgo/go/net/hosts.go b/libgo/go/net/hosts.go index 9400503e41e..27958c7cc50 100644 --- a/libgo/go/net/hosts.go +++ b/libgo/go/net/hosts.go @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Read static host/IP entries from /etc/hosts. - package net import ( @@ -13,8 +11,21 @@ import ( const cacheMaxAge = 5 * time.Minute -// hostsPath points to the file with static IP/address entries. -var hostsPath = "/etc/hosts" +func parseLiteralIP(addr string) string { + var ip IP + var zone string + ip = parseIPv4(addr) + if ip == nil { + ip, zone = parseIPv6(addr, true) + } + if ip == nil { + return "" + } + if zone == "" { + return ip.String() + } + return ip.String() + "%" + zone +} // Simple cache. var hosts struct { @@ -27,7 +38,7 @@ var hosts struct { func readHosts() { now := time.Now() - hp := hostsPath + hp := testHookHostsPath if len(hosts.byName) == 0 || now.After(hosts.expire) || hosts.path != hp { hs := make(map[string][]string) is := make(map[string][]string) @@ -41,13 +52,17 @@ func readHosts() { line = line[0:i] } f := getFields(line) - if len(f) < 2 || ParseIP(f[0]) == nil { + if len(f) < 2 { + continue + } + addr := parseLiteralIP(f[0]) + if addr == "" { continue } for i := 1; i < len(f); i++ { h := f[i] - hs[h] = append(hs[h], f[0]) - is[f[0]] = append(is[f[0]], h) + hs[h] = append(hs[h], addr) + is[addr] = append(is[addr], h) } } // Update the data cache. @@ -77,6 +92,10 @@ func lookupStaticAddr(addr string) []string { hosts.Lock() defer hosts.Unlock() readHosts() + addr = parseLiteralIP(addr) + if addr == "" { + return nil + } if len(hosts.byAddr) != 0 { if hosts, ok := hosts.byAddr[addr]; ok { return hosts diff --git a/libgo/go/net/hosts_test.go b/libgo/go/net/hosts_test.go index 2fe358e079c..aca64c38b05 100644 --- a/libgo/go/net/hosts_test.go +++ b/libgo/go/net/hosts_test.go @@ -5,77 +5,116 @@ package net import ( - "sort" + "reflect" "testing" ) -type hostTest struct { - host string - ips []IP +type staticHostEntry struct { + in string + out []string } -var hosttests = []hostTest{ - {"odin", []IP{ - IPv4(127, 0, 0, 2), - IPv4(127, 0, 0, 3), - ParseIP("::2"), - }}, - {"thor", []IP{ - IPv4(127, 1, 1, 1), - }}, - {"loki", []IP{}}, - {"ullr", []IP{ - IPv4(127, 1, 1, 2), - }}, - {"ullrhost", []IP{ - IPv4(127, 1, 1, 2), - }}, +var lookupStaticHostTests = []struct { + name string + ents []staticHostEntry +}{ + { + "testdata/hosts", + []staticHostEntry{ + {"odin", []string{"127.0.0.2", "127.0.0.3", "::2"}}, + {"thor", []string{"127.1.1.1"}}, + {"ullr", []string{"127.1.1.2"}}, + {"ullrhost", []string{"127.1.1.2"}}, + {"localhost", []string{"fe80::1%lo0"}}, + }, + }, + { + "testdata/singleline-hosts", // see golang.org/issue/6646 + []staticHostEntry{ + {"odin", []string{"127.0.0.2"}}, + }, + }, + { + "testdata/ipv4-hosts", // see golang.org/issue/8996 + []staticHostEntry{ + {"localhost", []string{"127.0.0.1", "127.0.0.2", "127.0.0.3"}}, + {"localhost.localdomain", []string{"127.0.0.3"}}, + }, + }, + { + "testdata/ipv6-hosts", // see golang.org/issue/8996 + []staticHostEntry{ + {"localhost", []string{"::1", "fe80::1", "fe80::2%lo0", "fe80::3%lo0"}}, + {"localhost.localdomain", []string{"fe80::3%lo0"}}, + }, + }, } func TestLookupStaticHost(t *testing.T) { - p := hostsPath - hostsPath = "testdata/hosts" - for i := 0; i < len(hosttests); i++ { - tt := hosttests[i] - ips := lookupStaticHost(tt.host) - if len(ips) != len(tt.ips) { - t.Errorf("# of hosts = %v; want %v", - len(ips), len(tt.ips)) - continue - } - for k, v := range ips { - if tt.ips[k].String() != v { - t.Errorf("lookupStaticHost(%q) = %v; want %v", - tt.host, v, tt.ips[k]) + defer func(orig string) { testHookHostsPath = orig }(testHookHostsPath) + + for _, tt := range lookupStaticHostTests { + testHookHostsPath = tt.name + for _, ent := range tt.ents { + addrs := lookupStaticHost(ent.in) + if !reflect.DeepEqual(addrs, ent.out) { + t.Errorf("%s, lookupStaticHost(%s) = %v; want %v", tt.name, ent.in, addrs, ent.out) } } } - hostsPath = p } -// https://code.google.com/p/go/issues/detail?id=6646 -func TestSingleLineHostsFile(t *testing.T) { - p := hostsPath - hostsPath = "testdata/hosts_singleline" - - ips := lookupStaticHost("odin") - if len(ips) != 1 || ips[0] != "127.0.0.2" { - t.Errorf("lookupStaticHost = %v, want %v", ips, []string{"127.0.0.2"}) - } - - hostsPath = p +var lookupStaticAddrTests = []struct { + name string + ents []staticHostEntry +}{ + { + "testdata/hosts", + []staticHostEntry{ + {"255.255.255.255", []string{"broadcasthost"}}, + {"127.0.0.2", []string{"odin"}}, + {"127.0.0.3", []string{"odin"}}, + {"::2", []string{"odin"}}, + {"127.1.1.1", []string{"thor"}}, + {"127.1.1.2", []string{"ullr", "ullrhost"}}, + {"fe80::1%lo0", []string{"localhost"}}, + }, + }, + { + "testdata/singleline-hosts", // see golang.org/issue/6646 + []staticHostEntry{ + {"127.0.0.2", []string{"odin"}}, + }, + }, + { + "testdata/ipv4-hosts", // see golang.org/issue/8996 + []staticHostEntry{ + {"127.0.0.1", []string{"localhost"}}, + {"127.0.0.2", []string{"localhost"}}, + {"127.0.0.3", []string{"localhost", "localhost.localdomain"}}, + }, + }, + { + "testdata/ipv6-hosts", // see golang.org/issue/8996 + []staticHostEntry{ + {"::1", []string{"localhost"}}, + {"fe80::1", []string{"localhost"}}, + {"fe80::2%lo0", []string{"localhost"}}, + {"fe80::3%lo0", []string{"localhost", "localhost.localdomain"}}, + }, + }, } -func TestLookupHost(t *testing.T) { - // Can't depend on this to return anything in particular, - // but if it does return something, make sure it doesn't - // duplicate addresses (a common bug due to the way - // getaddrinfo works). - addrs, _ := LookupHost("localhost") - sort.Strings(addrs) - for i := 0; i+1 < len(addrs); i++ { - if addrs[i] == addrs[i+1] { - t.Fatalf("LookupHost(\"localhost\") = %v, has duplicate addresses", addrs) +func TestLookupStaticAddr(t *testing.T) { + defer func(orig string) { testHookHostsPath = orig }(testHookHostsPath) + + for _, tt := range lookupStaticAddrTests { + testHookHostsPath = tt.name + for _, ent := range tt.ents { + hosts := lookupStaticAddr(ent.in) + if !reflect.DeepEqual(hosts, ent.out) { + t.Errorf("%s, lookupStaticAddr(%s) = %v; want %v", tt.name, ent.in, hosts, ent.out) + } } } } diff --git a/libgo/go/net/http/cgi/child.go b/libgo/go/net/http/cgi/child.go index 45fc2e57cd7..ec101088219 100644 --- a/libgo/go/net/http/cgi/child.go +++ b/libgo/go/net/http/cgi/child.go @@ -132,9 +132,9 @@ func RequestFromMap(params map[string]string) (*http.Request, error) { } // Request.RemoteAddr has its port set by Go's standard http - // server, so we do here too. We don't have one, though, so we - // use a dummy one. - r.RemoteAddr = net.JoinHostPort(params["REMOTE_ADDR"], "0") + // server, so we do here too. + remotePort, _ := strconv.Atoi(params["REMOTE_PORT"]) // zero if unset or invalid + r.RemoteAddr = net.JoinHostPort(params["REMOTE_ADDR"], strconv.Itoa(remotePort)) return r, nil } diff --git a/libgo/go/net/http/cgi/child_test.go b/libgo/go/net/http/cgi/child_test.go index 075d8411bcf..14e0af475f5 100644 --- a/libgo/go/net/http/cgi/child_test.go +++ b/libgo/go/net/http/cgi/child_test.go @@ -22,6 +22,7 @@ func TestRequest(t *testing.T) { "CONTENT_LENGTH": "123", "CONTENT_TYPE": "text/xml", "REMOTE_ADDR": "5.6.7.8", + "REMOTE_PORT": "54321", } req, err := RequestFromMap(env) if err != nil { @@ -60,7 +61,7 @@ func TestRequest(t *testing.T) { if req.TLS != nil { t.Errorf("expected nil TLS") } - if e, g := "5.6.7.8:0", req.RemoteAddr; e != g { + if e, g := "5.6.7.8:54321", req.RemoteAddr; e != g { t.Errorf("RemoteAddr: got %q; want %q", g, e) } } @@ -129,3 +130,21 @@ func TestRequestWithoutRequestURI(t *testing.T) { t.Errorf("URL = %q; want %q", g, e) } } + +func TestRequestWithoutRemotePort(t *testing.T) { + env := map[string]string{ + "SERVER_PROTOCOL": "HTTP/1.1", + "HTTP_HOST": "example.com", + "REQUEST_METHOD": "GET", + "REQUEST_URI": "/path?a=b", + "CONTENT_LENGTH": "123", + "REMOTE_ADDR": "5.6.7.8", + } + req, err := RequestFromMap(env) + if err != nil { + t.Fatalf("RequestFromMap: %v", err) + } + if e, g := "5.6.7.8:0", req.RemoteAddr; e != g { + t.Errorf("RemoteAddr: got %q; want %q", g, e) + } +} diff --git a/libgo/go/net/http/cgi/host.go b/libgo/go/net/http/cgi/host.go index ec95a972c1a..4efbe7abeec 100644 --- a/libgo/go/net/http/cgi/host.go +++ b/libgo/go/net/http/cgi/host.go @@ -19,6 +19,7 @@ import ( "fmt" "io" "log" + "net" "net/http" "os" "os/exec" @@ -128,11 +129,16 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) { "PATH_INFO=" + pathInfo, "SCRIPT_NAME=" + root, "SCRIPT_FILENAME=" + h.Path, - "REMOTE_ADDR=" + req.RemoteAddr, - "REMOTE_HOST=" + req.RemoteAddr, "SERVER_PORT=" + port, } + if remoteIP, remotePort, err := net.SplitHostPort(req.RemoteAddr); err == nil { + env = append(env, "REMOTE_ADDR="+remoteIP, "REMOTE_HOST="+remoteIP, "REMOTE_PORT="+remotePort) + } else { + // could not parse ip:port, let's use whole RemoteAddr and leave REMOTE_PORT undefined + env = append(env, "REMOTE_ADDR="+req.RemoteAddr, "REMOTE_HOST="+req.RemoteAddr) + } + if req.TLS != nil { env = append(env, "HTTPS=on") } diff --git a/libgo/go/net/http/cgi/host_test.go b/libgo/go/net/http/cgi/host_test.go index b514e10e963..f3411105ca9 100644 --- a/libgo/go/net/http/cgi/host_test.go +++ b/libgo/go/net/http/cgi/host_test.go @@ -29,7 +29,7 @@ func newRequest(httpreq string) *http.Request { if err != nil { panic("cgi: bogus http request in test: " + httpreq) } - req.RemoteAddr = "1.2.3.4" + req.RemoteAddr = "1.2.3.4:1234" return req } @@ -37,7 +37,11 @@ func runCgiTest(t *testing.T, h *Handler, httpreq string, expectedMap map[string rw := httptest.NewRecorder() req := newRequest(httpreq) h.ServeHTTP(rw, req) + runResponseChecks(t, rw, expectedMap) + return rw +} +func runResponseChecks(t *testing.T, rw *httptest.ResponseRecorder, expectedMap map[string]string) { // Make a map to hold the test map that the CGI returns. m := make(map[string]string) m["_body"] = rw.Body.String() @@ -75,7 +79,6 @@ readlines: t.Errorf("for key %q got %q; expected %q", key, got, expected) } } - return rw } var cgiTested, cgiWorks bool @@ -108,6 +111,7 @@ func TestCGIBasicGet(t *testing.T) { "env-QUERY_STRING": "foo=bar&a=b", "env-REMOTE_ADDR": "1.2.3.4", "env-REMOTE_HOST": "1.2.3.4", + "env-REMOTE_PORT": "1234", "env-REQUEST_METHOD": "GET", "env-REQUEST_URI": "/test.cgi?foo=bar&a=b", "env-SCRIPT_FILENAME": "testdata/test.cgi", @@ -126,6 +130,39 @@ func TestCGIBasicGet(t *testing.T) { } } +func TestCGIEnvIPv6(t *testing.T) { + check(t) + h := &Handler{ + Path: "testdata/test.cgi", + Root: "/test.cgi", + } + expectedMap := map[string]string{ + "test": "Hello CGI", + "param-a": "b", + "param-foo": "bar", + "env-GATEWAY_INTERFACE": "CGI/1.1", + "env-HTTP_HOST": "example.com", + "env-PATH_INFO": "", + "env-QUERY_STRING": "foo=bar&a=b", + "env-REMOTE_ADDR": "2000::3000", + "env-REMOTE_HOST": "2000::3000", + "env-REMOTE_PORT": "12345", + "env-REQUEST_METHOD": "GET", + "env-REQUEST_URI": "/test.cgi?foo=bar&a=b", + "env-SCRIPT_FILENAME": "testdata/test.cgi", + "env-SCRIPT_NAME": "/test.cgi", + "env-SERVER_NAME": "example.com", + "env-SERVER_PORT": "80", + "env-SERVER_SOFTWARE": "go", + } + + rw := httptest.NewRecorder() + req := newRequest("GET /test.cgi?foo=bar&a=b HTTP/1.0\nHost: example.com\n\n") + req.RemoteAddr = "[2000::3000]:12345" + h.ServeHTTP(rw, req) + runResponseChecks(t, rw, expectedMap) +} + func TestCGIBasicGetAbsPath(t *testing.T) { check(t) pwd, err := os.Getwd() @@ -289,7 +326,7 @@ func TestInternalRedirect(t *testing.T) { } expectedMap := map[string]string{ "basepath": "/foo", - "remoteaddr": "1.2.3.4", + "remoteaddr": "1.2.3.4:1234", } runCgiTest(t, h, "GET /test.cgi?loc=/foo HTTP/1.0\nHost: example.com\n\n", expectedMap) } diff --git a/libgo/go/net/http/cgi/matryoshka_test.go b/libgo/go/net/http/cgi/matryoshka_test.go index 18c4803e71b..32d59c09a3c 100644 --- a/libgo/go/net/http/cgi/matryoshka_test.go +++ b/libgo/go/net/http/cgi/matryoshka_test.go @@ -12,11 +12,11 @@ import ( "bytes" "errors" "fmt" + "internal/testenv" "io" "net/http" "net/http/httptest" "os" - "runtime" "testing" "time" ) @@ -24,9 +24,7 @@ import ( // This test is a CGI host (testing host.go) that runs its own binary // as a child process testing the other half of CGI (child.go). func TestHostingOurselves(t *testing.T) { - if runtime.GOOS == "nacl" { - t.Skip("skipping on nacl") - } + testenv.MustHaveExec(t) h := &Handler{ Path: os.Args[0], @@ -43,6 +41,7 @@ func TestHostingOurselves(t *testing.T) { "env-QUERY_STRING": "foo=bar&a=b", "env-REMOTE_ADDR": "1.2.3.4", "env-REMOTE_HOST": "1.2.3.4", + "env-REMOTE_PORT": "1234", "env-REQUEST_METHOD": "GET", "env-REQUEST_URI": "/test.go?foo=bar&a=b", "env-SCRIPT_FILENAME": os.Args[0], @@ -92,9 +91,7 @@ func (w *limitWriter) Write(p []byte) (n int, err error) { // If there's an error copying the child's output to the parent, test // that we kill the child. func TestKillChildAfterCopyError(t *testing.T) { - if runtime.GOOS == "nacl" { - t.Skip("skipping on nacl") - } + testenv.MustHaveExec(t) defer func() { testHookStartProcess = nil }() proc := make(chan *os.Process, 1) @@ -139,9 +136,7 @@ func TestKillChildAfterCopyError(t *testing.T) { // Test that a child handler writing only headers works. // golang.org/issue/7196 func TestChildOnlyHeaders(t *testing.T) { - if runtime.GOOS == "nacl" { - t.Skip("skipping on nacl") - } + testenv.MustHaveExec(t) h := &Handler{ Path: os.Args[0], diff --git a/libgo/go/net/http/cgi/testdata/test.cgi b/libgo/go/net/http/cgi/testdata/test.cgi index 3214df6f004..ec7ee6f3864 100644 --- a/libgo/go/net/http/cgi/testdata/test.cgi +++ b/libgo/go/net/http/cgi/testdata/test.cgi @@ -45,7 +45,7 @@ foreach my $k (sort keys %ENV) { # NOTE: msys perl returns /c/go/src/... not C:\go\.... my $dir = getcwd(); -if ($^O eq 'MSWin32' || $^O eq 'msys') { +if ($^O eq 'MSWin32' || $^O eq 'msys' || $^O eq 'cygwin') { if ($dir =~ /^.:/) { $dir =~ s!/!\\!g; } else { diff --git a/libgo/go/net/http/client.go b/libgo/go/net/http/client.go index ce884d1f07b..7f2fbb4678e 100644 --- a/libgo/go/net/http/client.go +++ b/libgo/go/net/http/client.go @@ -19,6 +19,7 @@ import ( "net/url" "strings" "sync" + "sync/atomic" "time" ) @@ -211,7 +212,7 @@ func send(req *Request, t RoundTripper) (resp *Response, err error) { req.Header = make(Header) } - if u := req.URL.User; u != nil { + if u := req.URL.User; u != nil && req.Header.Get("Authorization") == "" { username := u.Username() password, _ := u.Password() req.Header.Set("Authorization", "Basic "+basicAuth(username, password)) @@ -256,8 +257,9 @@ func shouldRedirectPost(statusCode int) bool { return false } -// Get issues a GET to the specified URL. If the response is one of the following -// redirect codes, Get follows the redirect, up to a maximum of 10 redirects: +// Get issues a GET to the specified URL. If the response is one of +// the following redirect codes, Get follows the redirect, up to a +// maximum of 10 redirects: // // 301 (Moved Permanently) // 302 (Found) @@ -272,13 +274,16 @@ func shouldRedirectPost(statusCode int) bool { // Caller should close resp.Body when done reading from it. // // Get is a wrapper around DefaultClient.Get. +// +// To make a request with custom headers, use NewRequest and +// DefaultClient.Do. func Get(url string) (resp *Response, err error) { return DefaultClient.Get(url) } -// Get issues a GET to the specified URL. If the response is one of the +// Get issues a GET to the specified URL. If the response is one of the // following redirect codes, Get follows the redirect after calling the -// Client's CheckRedirect function. +// Client's CheckRedirect function: // // 301 (Moved Permanently) // 302 (Found) @@ -291,6 +296,8 @@ func Get(url string) (resp *Response, err error) { // // When err is nil, resp always contains a non-nil resp.Body. // Caller should close resp.Body when done reading from it. +// +// To make a request with custom headers, use NewRequest and Client.Do. func (c *Client) Get(url string) (resp *Response, err error) { req, err := NewRequest("GET", url, nil) if err != nil { @@ -299,6 +306,8 @@ func (c *Client) Get(url string) (resp *Response, err error) { return c.doFollowingRedirects(req, shouldRedirectGet) } +func alwaysFalse() bool { return false } + func (c *Client) doFollowingRedirects(ireq *Request, shouldRedirect func(int) bool) (resp *Response, err error) { var base *url.URL redirectChecker := c.CheckRedirect @@ -316,7 +325,10 @@ func (c *Client) doFollowingRedirects(ireq *Request, shouldRedirect func(int) bo req := ireq var timer *time.Timer + var atomicWasCanceled int32 // atomic bool (1 or 0) + var wasCanceled = alwaysFalse if c.Timeout > 0 { + wasCanceled = func() bool { return atomic.LoadInt32(&atomicWasCanceled) != 0 } type canceler interface { CancelRequest(*Request) } @@ -325,6 +337,7 @@ func (c *Client) doFollowingRedirects(ireq *Request, shouldRedirect func(int) bo return nil, fmt.Errorf("net/http: Client Transport of type %T doesn't support CancelRequest; Timeout not supported", c.transport()) } timer = time.AfterFunc(c.Timeout, func() { + atomic.StoreInt32(&atomicWasCanceled, 1) reqmu.Lock() defer reqmu.Unlock() tr.CancelRequest(req) @@ -365,6 +378,12 @@ func (c *Client) doFollowingRedirects(ireq *Request, shouldRedirect func(int) bo urlStr = req.URL.String() if resp, err = c.send(req); err != nil { + if wasCanceled() { + err = &httpError{ + err: err.Error() + " (Client.Timeout exceeded while awaiting headers)", + timeout: true, + } + } break } @@ -377,7 +396,7 @@ func (c *Client) doFollowingRedirects(ireq *Request, shouldRedirect func(int) bo } resp.Body.Close() if urlStr = resp.Header.Get("Location"); urlStr == "" { - err = errors.New(fmt.Sprintf("%d response missing Location header", resp.StatusCode)) + err = fmt.Errorf("%d response missing Location header", resp.StatusCode) break } base = req.URL @@ -385,7 +404,11 @@ func (c *Client) doFollowingRedirects(ireq *Request, shouldRedirect func(int) bo continue } if timer != nil { - resp.Body = &cancelTimerBody{timer, resp.Body} + resp.Body = &cancelTimerBody{ + t: timer, + rc: resp.Body, + reqWasCanceled: wasCanceled, + } } return resp, nil } @@ -400,7 +423,7 @@ func (c *Client) doFollowingRedirects(ireq *Request, shouldRedirect func(int) bo if redirectFailed { // Special case for Go 1 compatibility: return both the response // and an error if the CheckRedirect function failed. - // See http://golang.org/issue/3795 + // See https://golang.org/issue/3795 return resp, urlErr } @@ -421,7 +444,12 @@ func defaultCheckRedirect(req *Request, via []*Request) error { // // Caller should close resp.Body when done reading from it. // -// Post is a wrapper around DefaultClient.Post +// If the provided body is an io.Closer, it is closed after the +// request. +// +// Post is a wrapper around DefaultClient.Post. +// +// To set custom headers, use NewRequest and DefaultClient.Do. func Post(url string, bodyType string, body io.Reader) (resp *Response, err error) { return DefaultClient.Post(url, bodyType, body) } @@ -430,8 +458,10 @@ func Post(url string, bodyType string, body io.Reader) (resp *Response, err erro // // Caller should close resp.Body when done reading from it. // -// If the provided body is also an io.Closer, it is closed after the +// If the provided body is an io.Closer, it is closed after the // request. +// +// To set custom headers, use NewRequest and Client.Do. func (c *Client) Post(url string, bodyType string, body io.Reader) (resp *Response, err error) { req, err := NewRequest("POST", url, body) if err != nil { @@ -444,16 +474,22 @@ func (c *Client) Post(url string, bodyType string, body io.Reader) (resp *Respon // PostForm issues a POST to the specified URL, with data's keys and // values URL-encoded as the request body. // +// The Content-Type header is set to application/x-www-form-urlencoded. +// To set other headers, use NewRequest and DefaultClient.Do. +// // When err is nil, resp always contains a non-nil resp.Body. // Caller should close resp.Body when done reading from it. // -// PostForm is a wrapper around DefaultClient.PostForm +// PostForm is a wrapper around DefaultClient.PostForm. func PostForm(url string, data url.Values) (resp *Response, err error) { return DefaultClient.PostForm(url, data) } // PostForm issues a POST to the specified URL, -// with data's keys and values urlencoded as the request body. +// with data's keys and values URL-encoded as the request body. +// +// The Content-Type header is set to application/x-www-form-urlencoded. +// To set other headers, use NewRequest and DefaultClient.Do. // // When err is nil, resp always contains a non-nil resp.Body. // Caller should close resp.Body when done reading from it. @@ -461,9 +497,9 @@ func (c *Client) PostForm(url string, data url.Values) (resp *Response, err erro return c.Post(url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode())) } -// Head issues a HEAD to the specified URL. If the response is one of the -// following redirect codes, Head follows the redirect after calling the -// Client's CheckRedirect function. +// Head issues a HEAD to the specified URL. If the response is one of +// the following redirect codes, Head follows the redirect, up to a +// maximum of 10 redirects: // // 301 (Moved Permanently) // 302 (Found) @@ -477,7 +513,7 @@ func Head(url string) (resp *Response, err error) { // Head issues a HEAD to the specified URL. If the response is one of the // following redirect codes, Head follows the redirect after calling the -// Client's CheckRedirect function. +// Client's CheckRedirect function: // // 301 (Moved Permanently) // 302 (Found) @@ -491,15 +527,25 @@ func (c *Client) Head(url string) (resp *Response, err error) { return c.doFollowingRedirects(req, shouldRedirectGet) } +// cancelTimerBody is an io.ReadCloser that wraps rc with two features: +// 1) on Read EOF or Close, the timer t is Stopped, +// 2) On Read failure, if reqWasCanceled is true, the error is wrapped and +// marked as net.Error that hit its timeout. type cancelTimerBody struct { - t *time.Timer - rc io.ReadCloser + t *time.Timer + rc io.ReadCloser + reqWasCanceled func() bool } func (b *cancelTimerBody) Read(p []byte) (n int, err error) { n, err = b.rc.Read(p) if err == io.EOF { b.t.Stop() + } else if err != nil && b.reqWasCanceled() { + return n, &httpError{ + err: err.Error() + " (Client.Timeout exceeded while reading body)", + timeout: true, + } } return } diff --git a/libgo/go/net/http/client_test.go b/libgo/go/net/http/client_test.go index 56b6563c486..7b524d381bc 100644 --- a/libgo/go/net/http/client_test.go +++ b/libgo/go/net/http/client_test.go @@ -258,7 +258,7 @@ func TestClientRedirects(t *testing.T) { t.Errorf("with redirects forbidden, expected a *url.Error with our 'no redirects allowed' error inside; got %#v (%q)", err, err) } if res == nil { - t.Fatalf("Expected a non-nil Response on CheckRedirect failure (http://golang.org/issue/3795)") + t.Fatalf("Expected a non-nil Response on CheckRedirect failure (https://golang.org/issue/3795)") } res.Body.Close() if res.Header.Get("Location") == "" { @@ -334,6 +334,7 @@ var echoCookiesRedirectHandler = HandlerFunc(func(w ResponseWriter, r *Request) }) func TestClientSendsCookieFromJar(t *testing.T) { + defer afterTest(t) tr := &recordingTransport{} client := &Client{Transport: tr} client.Jar = &TestJar{perURL: make(map[string][]*Cookie)} @@ -426,7 +427,7 @@ func TestJarCalls(t *testing.T) { ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { pathSuffix := r.RequestURI[1:] if r.RequestURI == "/nosetcookie" { - return // dont set cookies for this path + return // don't set cookies for this path } SetCookie(w, &Cookie{Name: "name" + pathSuffix, Value: "val" + pathSuffix}) if r.RequestURI == "/" { @@ -738,7 +739,7 @@ func TestResponseSetsTLSConnectionState(t *testing.T) { } } -// Verify Response.ContentLength is populated. http://golang.org/issue/4126 +// Verify Response.ContentLength is populated. https://golang.org/issue/4126 func TestClientHeadContentLength(t *testing.T) { defer afterTest(t) ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { @@ -842,6 +843,47 @@ func TestBasicAuth(t *testing.T) { } } +func TestBasicAuthHeadersPreserved(t *testing.T) { + defer afterTest(t) + tr := &recordingTransport{} + client := &Client{Transport: tr} + + // If Authorization header is provided, username in URL should not override it + url := "http://My%20User@dummy.faketld/" + req, err := NewRequest("GET", url, nil) + if err != nil { + t.Fatal(err) + } + req.SetBasicAuth("My User", "My Pass") + expected := "My User:My Pass" + client.Do(req) + + if tr.req.Method != "GET" { + t.Errorf("got method %q, want %q", tr.req.Method, "GET") + } + if tr.req.URL.String() != url { + t.Errorf("got URL %q, want %q", tr.req.URL.String(), url) + } + if tr.req.Header == nil { + t.Fatalf("expected non-nil request Header") + } + auth := tr.req.Header.Get("Authorization") + if strings.HasPrefix(auth, "Basic ") { + encoded := auth[6:] + decoded, err := base64.StdEncoding.DecodeString(encoded) + if err != nil { + t.Fatal(err) + } + s := string(decoded) + if expected != s { + t.Errorf("Invalid Authorization header. Got %q, wanted %q", s, expected) + } + } else { + t.Errorf("Invalid auth %q", auth) + } + +} + func TestClientTimeout(t *testing.T) { if testing.Short() { t.Skip("skipping in short mode") @@ -899,14 +941,64 @@ func TestClientTimeout(t *testing.T) { select { case err := <-errc: if err == nil { - t.Error("expected error from ReadAll") + t.Fatal("expected error from ReadAll") + } + ne, ok := err.(net.Error) + if !ok { + t.Errorf("error value from ReadAll was %T; expected some net.Error", err) + } else if !ne.Timeout() { + t.Errorf("net.Error.Timeout = false; want true") + } + if got := ne.Error(); !strings.Contains(got, "Client.Timeout exceeded") { + t.Errorf("error string = %q; missing timeout substring", got) } - // Expected error. case <-time.After(failTime): t.Errorf("timeout after %v waiting for timeout of %v", failTime, timeout) } } +// Client.Timeout firing before getting to the body +func TestClientTimeout_Headers(t *testing.T) { + if testing.Short() { + t.Skip("skipping in short mode") + } + defer afterTest(t) + donec := make(chan bool) + ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { + <-donec + })) + defer ts.Close() + // Note that we use a channel send here and not a close. + // The race detector doesn't know that we're waiting for a timeout + // and thinks that the waitgroup inside httptest.Server is added to concurrently + // with us closing it. If we timed out immediately, we could close the testserver + // before we entered the handler. We're not timing out immediately and there's + // no way we would be done before we entered the handler, but the race detector + // doesn't know this, so synchronize explicitly. + defer func() { donec <- true }() + + c := &Client{Timeout: 500 * time.Millisecond} + + _, err := c.Get(ts.URL) + if err == nil { + t.Fatal("got response from Get; expected error") + } + ue, ok := err.(*url.Error) + if !ok { + t.Fatalf("Got error of type %T; want *url.Error", err) + } + ne, ok := ue.Err.(net.Error) + if !ok { + t.Fatalf("Got url.Error.Err of type %T; want some net.Error", err) + } + if !ne.Timeout() { + t.Error("net.Error.Timeout = false; want true") + } + if got := ne.Error(); !strings.Contains(got, "Client.Timeout exceeded") { + t.Errorf("error string = %q; missing timeout substring", got) + } +} + func TestClientRedirectEatsBody(t *testing.T) { defer afterTest(t) saw := make(chan string, 2) @@ -984,24 +1076,12 @@ func TestClientTrailers(t *testing.T) { r.Trailer.Get("Client-Trailer-B")) } - // TODO: golang.org/issue/7759: there's no way yet for - // the server to set trailers without hijacking, so do - // that for now, just to test the client. Later, in - // Go 1.4, it should be implicit that any mutations - // to w.Header() after the initial write are the - // trailers to be sent, if and only if they were - // previously declared with w.Header().Set("Trailer", - // ..keys..) - w.(Flusher).Flush() - conn, buf, _ := w.(Hijacker).Hijack() - t := Header{} - t.Set("Server-Trailer-A", "valuea") - t.Set("Server-Trailer-C", "valuec") // skipping B - buf.WriteString("0\r\n") // eof - t.Write(buf) - buf.WriteString("\r\n") // end of trailers - buf.Flush() - conn.Close() + // How handlers set Trailers: declare it ahead of time + // with the Trailer header, and then mutate the + // Header() of those values later, after the response + // has been written (we wrote to w above). + w.Header().Set("Server-Trailer-A", "valuea") + w.Header().Set("Server-Trailer-C", "valuec") // skipping B })) defer ts.Close() diff --git a/libgo/go/net/http/cookie.go b/libgo/go/net/http/cookie.go index a0d0fdbbd07..648709dd997 100644 --- a/libgo/go/net/http/cookie.go +++ b/libgo/go/net/http/cookie.go @@ -14,19 +14,18 @@ import ( "time" ) -// This implementation is done according to RFC 6265: -// -// http://tools.ietf.org/html/rfc6265 - // A Cookie represents an HTTP cookie as sent in the Set-Cookie header of an // HTTP response or the Cookie header of an HTTP request. +// +// See http://tools.ietf.org/html/rfc6265 for details. type Cookie struct { - Name string - Value string - Path string - Domain string - Expires time.Time - RawExpires string + Name string + Value string + + Path string // optional + Domain string // optional + Expires time.Time // optional + RawExpires string // for reading cookies only // MaxAge=0 means no 'Max-Age' attribute specified. // MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0' @@ -126,14 +125,22 @@ func readSetCookies(h Header) []*Cookie { } // SetCookie adds a Set-Cookie header to the provided ResponseWriter's headers. +// The provided cookie must have a valid Name. Invalid cookies may be +// silently dropped. func SetCookie(w ResponseWriter, cookie *Cookie) { - w.Header().Add("Set-Cookie", cookie.String()) + if v := cookie.String(); v != "" { + w.Header().Add("Set-Cookie", v) + } } // String returns the serialization of the cookie for use in a Cookie // header (if only Name and Value are set) or a Set-Cookie response // header (if other fields are set). +// If c is nil or c.Name is invalid, the empty string is returned. func (c *Cookie) String() string { + if c == nil || !isCookieNameValid(c.Name) { + return "" + } var b bytes.Buffer fmt.Fprintf(&b, "%s=%s", sanitizeCookieName(c.Name), sanitizeCookieValue(c.Value)) if len(c.Path) > 0 { @@ -156,7 +163,7 @@ func (c *Cookie) String() string { } } if c.Expires.Unix() > 0 { - fmt.Fprintf(&b, "; Expires=%s", c.Expires.UTC().Format(time.RFC1123)) + fmt.Fprintf(&b, "; Expires=%s", c.Expires.UTC().Format(TimeFormat)) } if c.MaxAge > 0 { fmt.Fprintf(&b, "; Max-Age=%d", c.MaxAge) @@ -297,7 +304,7 @@ func sanitizeCookieName(n string) string { // We loosen this as spaces and commas are common in cookie values // but we produce a quoted cookie-value in when value starts or ends // with a comma or space. -// See http://golang.org/issue/7243 for the discussion. +// See https://golang.org/issue/7243 for the discussion. func sanitizeCookieValue(v string) string { v = sanitizeOrWarn("Cookie.Value", validCookieValueByte, v) if len(v) == 0 { @@ -359,5 +366,8 @@ func parseCookieValue(raw string, allowDoubleQuote bool) (string, bool) { } func isCookieNameValid(raw string) bool { + if raw == "" { + return false + } return strings.IndexFunc(raw, isNotToken) < 0 } diff --git a/libgo/go/net/http/cookie_test.go b/libgo/go/net/http/cookie_test.go index 98dc2fade0d..d474f313476 100644 --- a/libgo/go/net/http/cookie_test.go +++ b/libgo/go/net/http/cookie_test.go @@ -52,6 +52,10 @@ var writeSetCookiesTests = []struct { &Cookie{Name: "cookie-8", Value: "eight", Domain: "::1"}, "cookie-8=eight", }, + { + &Cookie{Name: "cookie-9", Value: "expiring", Expires: time.Unix(1257894000, 0)}, + "cookie-9=expiring; Expires=Tue, 10 Nov 2009 23:00:00 GMT", + }, // The "special" cookies have values containing commas or spaces which // are disallowed by RFC 6265 but are common in the wild. { @@ -90,6 +94,18 @@ var writeSetCookiesTests = []struct { &Cookie{Name: "empty-value", Value: ""}, `empty-value=`, }, + { + nil, + ``, + }, + { + &Cookie{Name: ""}, + ``, + }, + { + &Cookie{Name: "\t"}, + ``, + }, } func TestWriteSetCookies(t *testing.T) { @@ -349,7 +365,7 @@ func TestSetCookieDoubleQuotes(t *testing.T) { {Name: "quoted3", Value: "both"}, } if len(got) != len(want) { - t.Fatal("got %d cookies, want %d", len(got), len(want)) + t.Fatalf("got %d cookies, want %d", len(got), len(want)) } for i, w := range want { g := got[i] diff --git a/libgo/go/net/http/example_test.go b/libgo/go/net/http/example_test.go index 88b97d9e3d7..1774795d379 100644 --- a/libgo/go/net/http/example_test.go +++ b/libgo/go/net/http/example_test.go @@ -6,6 +6,7 @@ package http_test import ( "fmt" + "io" "io/ioutil" "log" "net/http" @@ -86,3 +87,25 @@ func ExampleServeMux_Handle() { fmt.Fprintf(w, "Welcome to the home page!") }) } + +// HTTP Trailers are a set of key/value pairs like headers that come +// after the HTTP response, instead of before. +func ExampleResponseWriter_trailers() { + mux := http.NewServeMux() + mux.HandleFunc("/sendstrailers", func(w http.ResponseWriter, req *http.Request) { + // Before any call to WriteHeader or Write, declare + // the trailers you will set during the HTTP + // response. These three headers are actually sent in + // the trailer. + w.Header().Set("Trailer", "AtEnd1, AtEnd2") + w.Header().Add("Trailer", "AtEnd3") + + w.Header().Set("Content-Type", "text/plain; charset=utf-8") // normal header + w.WriteHeader(http.StatusOK) + + w.Header().Set("AtEnd1", "value 1") + io.WriteString(w, "This HTTP response has both headers before this text and trailers at the end.\n") + w.Header().Set("AtEnd2", "value 2") + w.Header().Set("AtEnd3", "value 3") // These will appear as trailers. + }) +} diff --git a/libgo/go/net/http/export_test.go b/libgo/go/net/http/export_test.go index 87b6c0773aa..0457be50da6 100644 --- a/libgo/go/net/http/export_test.go +++ b/libgo/go/net/http/export_test.go @@ -10,9 +10,17 @@ package http import ( "net" "net/url" + "sync" "time" ) +func init() { + // We only want to pay for this cost during testing. + // When not under test, these values are always nil + // and never assigned to. + testHookMu = new(sync.Mutex) +} + func NewLoggingConn(baseName string, c net.Conn) net.Conn { return newLoggingConn(baseName, c) } @@ -78,6 +86,20 @@ func (t *Transport) PutIdleTestConn() bool { }) } +func SetInstallConnClosedHook(f func()) { + testHookPersistConnClosedGotRes = f +} + +func SetEnterRoundTripHook(f func()) { + testHookEnterRoundTrip = f +} + +func SetReadLoopBeforeNextReadHook(f func()) { + testHookMu.Lock() + defer testHookMu.Unlock() + testHookReadLoopBeforeNextRead = f +} + func NewTestTimeoutHandler(handler Handler, ch <-chan time.Time) Handler { f := func() <-chan time.Time { return ch @@ -106,3 +128,5 @@ func SetPendingDialHooks(before, after func()) { var ExportServerNewConn = (*Server).newConn var ExportCloseWriteAndWait = (*conn).closeWriteAndWait + +var ExportErrRequestCanceled = errRequestCanceled diff --git a/libgo/go/net/http/fcgi/child.go b/libgo/go/net/http/fcgi/child.go index a3beaa33a86..da824ed717e 100644 --- a/libgo/go/net/http/fcgi/child.go +++ b/libgo/go/net/http/fcgi/child.go @@ -144,6 +144,7 @@ func newChild(rwc io.ReadWriteCloser, handler http.Handler) *child { func (c *child) serve() { defer c.conn.Close() + defer c.cleanUp() var rec record for { if err := rec.read(c.conn.rwc); err != nil { @@ -159,6 +160,14 @@ var errCloseConn = errors.New("fcgi: connection should be closed") var emptyBody = ioutil.NopCloser(strings.NewReader("")) +// ErrRequestAborted is returned by Read when a handler attempts to read the +// body of a request that has been aborted by the web server. +var ErrRequestAborted = errors.New("fcgi: request aborted by web server") + +// ErrConnClosed is returned by Read when a handler attempts to read the body of +// a request after the connection to the web server has been closed. +var ErrConnClosed = errors.New("fcgi: connection to web server closed") + func (c *child) handleRecord(rec *record) error { c.mu.Lock() req, ok := c.requests[rec.h.Id] @@ -227,11 +236,13 @@ func (c *child) handleRecord(rec *record) error { // If the filter role is implemented, read the data stream here. return nil case typeAbortRequest: - println("abort") c.mu.Lock() delete(c.requests, rec.h.Id) c.mu.Unlock() c.conn.writeEndRequest(rec.h.Id, 0, statusRequestComplete) + if req.pw != nil { + req.pw.CloseWithError(ErrRequestAborted) + } if !req.keepConn { // connection will close upon return return errCloseConn @@ -277,6 +288,18 @@ func (c *child) serveRequest(req *request, body io.ReadCloser) { } } +func (c *child) cleanUp() { + c.mu.Lock() + defer c.mu.Unlock() + for _, req := range c.requests { + if req.pw != nil { + // race with call to Close in c.serveRequest doesn't matter because + // Pipe(Reader|Writer).Close are idempotent + req.pw.CloseWithError(ErrConnClosed) + } + } +} + // Serve accepts incoming FastCGI connections on the listener l, creating a new // goroutine for each. The goroutine reads requests and then calls handler // to reply to them. diff --git a/libgo/go/net/http/fcgi/fcgi_test.go b/libgo/go/net/http/fcgi/fcgi_test.go index 6c7e1a9ce83..de0f7f831f6 100644 --- a/libgo/go/net/http/fcgi/fcgi_test.go +++ b/libgo/go/net/http/fcgi/fcgi_test.go @@ -8,6 +8,8 @@ import ( "bytes" "errors" "io" + "io/ioutil" + "net/http" "testing" ) @@ -148,3 +150,107 @@ func TestGetValues(t *testing.T) { t.Errorf(" got: %q\nwant: %q\n", got, want) } } + +func nameValuePair11(nameData, valueData string) []byte { + return bytes.Join( + [][]byte{ + {byte(len(nameData)), byte(len(valueData))}, + []byte(nameData), + []byte(valueData), + }, + nil, + ) +} + +func makeRecord( + recordType recType, + requestId uint16, + contentData []byte, +) []byte { + requestIdB1 := byte(requestId >> 8) + requestIdB0 := byte(requestId) + + contentLength := len(contentData) + contentLengthB1 := byte(contentLength >> 8) + contentLengthB0 := byte(contentLength) + return bytes.Join([][]byte{ + {1, byte(recordType), requestIdB1, requestIdB0, contentLengthB1, + contentLengthB0, 0, 0}, + contentData, + }, + nil) +} + +// a series of FastCGI records that start a request and begin sending the +// request body +var streamBeginTypeStdin = bytes.Join([][]byte{ + // set up request 1 + makeRecord(typeBeginRequest, 1, + []byte{0, byte(roleResponder), 0, 0, 0, 0, 0, 0}), + // add required parameters to request 1 + makeRecord(typeParams, 1, nameValuePair11("REQUEST_METHOD", "GET")), + makeRecord(typeParams, 1, nameValuePair11("SERVER_PROTOCOL", "HTTP/1.1")), + makeRecord(typeParams, 1, nil), + // begin sending body of request 1 + makeRecord(typeStdin, 1, []byte("0123456789abcdef")), +}, + nil) + +var cleanUpTests = []struct { + input []byte + err error +}{ + // confirm that child.handleRecord closes req.pw after aborting req + { + bytes.Join([][]byte{ + streamBeginTypeStdin, + makeRecord(typeAbortRequest, 1, nil), + }, + nil), + ErrRequestAborted, + }, + // confirm that child.serve closes all pipes after error reading record + { + bytes.Join([][]byte{ + streamBeginTypeStdin, + nil, + }, + nil), + ErrConnClosed, + }, +} + +type nopWriteCloser struct { + io.ReadWriter +} + +func (nopWriteCloser) Close() error { + return nil +} + +// Test that child.serve closes the bodies of aborted requests and closes the +// bodies of all requests before returning. Causes deadlock if either condition +// isn't met. See issue 6934. +func TestChildServeCleansUp(t *testing.T) { + for _, tt := range cleanUpTests { + input := make([]byte, len(tt.input)) + copy(input, tt.input) + rc := nopWriteCloser{bytes.NewBuffer(input)} + done := make(chan bool) + c := newChild(rc, http.HandlerFunc(func( + w http.ResponseWriter, + r *http.Request, + ) { + // block on reading body of request + _, err := io.Copy(ioutil.Discard, r.Body) + if err != tt.err { + t.Errorf("Expected %#v, got %#v", tt.err, err) + } + // not reached if body of request isn't closed + done <- true + })) + go c.serve() + // wait for body of request to be closed or all goroutines to block + <-done + } +} diff --git a/libgo/go/net/http/fs.go b/libgo/go/net/http/fs.go index e322f710a5d..75720234c25 100644 --- a/libgo/go/net/http/fs.go +++ b/libgo/go/net/http/fs.go @@ -102,10 +102,10 @@ func dirList(w ResponseWriter, f File) { // The name is otherwise unused; in particular it can be empty and is // never sent in the response. // -// If modtime is not the zero time, ServeContent includes it in a -// Last-Modified header in the response. If the request includes an -// If-Modified-Since header, ServeContent uses modtime to decide -// whether the content needs to be sent at all. +// If modtime is not the zero time or Unix epoch, ServeContent +// includes it in a Last-Modified header in the response. If the +// request includes an If-Modified-Since header, ServeContent uses +// modtime to decide whether the content needs to be sent at all. // // The content's Seek method must work: ServeContent uses // a seek to the end of the content to determine its size. @@ -258,10 +258,15 @@ func serveContent(w ResponseWriter, r *Request, name string, modtime time.Time, } } +var unixEpochTime = time.Unix(0, 0) + // modtime is the modification time of the resource to be served, or IsZero(). // return value is whether this request is now complete. func checkLastModified(w ResponseWriter, r *Request, modtime time.Time) bool { - if modtime.IsZero() { + if modtime.IsZero() || modtime.Equal(unixEpochTime) { + // If the file doesn't have a modtime (IsZero), or the modtime + // is obviously garbage (Unix time == 0), then ignore modtimes + // and don't process the If-Modified-Since header. return false } @@ -353,16 +358,16 @@ func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirec f, err := fs.Open(name) if err != nil { - // TODO expose actual error? - NotFound(w, r) + msg, code := toHTTPError(err) + Error(w, msg, code) return } defer f.Close() d, err1 := f.Stat() if err1 != nil { - // TODO expose actual error? - NotFound(w, r) + msg, code := toHTTPError(err) + Error(w, msg, code) return } @@ -412,6 +417,22 @@ func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirec serveContent(w, r, d.Name(), d.ModTime(), sizeFunc, f) } +// toHTTPError returns a non-specific HTTP error message and status code +// for a given non-nil error value. It's important that toHTTPError does not +// actually return err.Error(), since msg and httpStatus are returned to users, +// and historically Go's ServeContent always returned just "404 Not Found" for +// all errors. We don't want to start leaking information in error messages. +func toHTTPError(err error) (msg string, httpStatus int) { + if os.IsNotExist(err) { + return "404 page not found", StatusNotFound + } + if os.IsPermission(err) { + return "403 Forbidden", StatusForbidden + } + // Default: + return "500 Internal Server Error", StatusInternalServerError +} + // localRedirect gives a Moved Permanently response. // It does not convert relative paths to absolute paths like Redirect does. func localRedirect(w ResponseWriter, r *Request, newPath string) { @@ -422,7 +443,13 @@ func localRedirect(w ResponseWriter, r *Request, newPath string) { w.WriteHeader(StatusMovedPermanently) } -// ServeFile replies to the request with the contents of the named file or directory. +// ServeFile replies to the request with the contents of the named +// file or directory. +// +// As a special case, ServeFile redirects any request where r.URL.Path +// ends in "/index.html" to the same path, without the final +// "index.html". To avoid such redirects either modify the path or +// use ServeContent. func ServeFile(w ResponseWriter, r *Request, name string) { dir, file := filepath.Split(name) serveFile(w, r, Dir(dir), file, false) @@ -439,6 +466,10 @@ type fileHandler struct { // use http.Dir: // // http.Handle("/", http.FileServer(http.Dir("/tmp"))) +// +// As a special case, the returned file server redirects any request +// ending in "/index.html" to the same path, without the final +// "index.html". func FileServer(root FileSystem) Handler { return &fileHandler{root} } @@ -503,7 +534,7 @@ func parseRange(s string, size int64) ([]httpRange, error) { r.length = size - r.start } else { i, err := strconv.ParseInt(start, 10, 64) - if err != nil || i > size || i < 0 { + if err != nil || i >= size || i < 0 { return nil, errors.New("invalid range") } r.start = i diff --git a/libgo/go/net/http/fs_test.go b/libgo/go/net/http/fs_test.go index 2ddd4ca5fe9..538f34d7201 100644 --- a/libgo/go/net/http/fs_test.go +++ b/libgo/go/net/http/fs_test.go @@ -50,15 +50,23 @@ var ServeFileRangeTests = []struct { {r: "bytes=2-", code: StatusPartialContent, ranges: []wantRange{{2, testFileLen}}}, {r: "bytes=-5", code: StatusPartialContent, ranges: []wantRange{{testFileLen - 5, testFileLen}}}, {r: "bytes=3-7", code: StatusPartialContent, ranges: []wantRange{{3, 8}}}, - {r: "bytes=20-", code: StatusRequestedRangeNotSatisfiable}, {r: "bytes=0-0,-2", code: StatusPartialContent, ranges: []wantRange{{0, 1}, {testFileLen - 2, testFileLen}}}, {r: "bytes=0-1,5-8", code: StatusPartialContent, ranges: []wantRange{{0, 2}, {5, 9}}}, {r: "bytes=0-1,5-", code: StatusPartialContent, ranges: []wantRange{{0, 2}, {5, testFileLen}}}, {r: "bytes=5-1000", code: StatusPartialContent, ranges: []wantRange{{5, testFileLen}}}, {r: "bytes=0-,1-,2-,3-,4-", code: StatusOK}, // ignore wasteful range request - {r: "bytes=0-" + itoa(testFileLen-2), code: StatusPartialContent, ranges: []wantRange{{0, testFileLen - 1}}}, - {r: "bytes=0-" + itoa(testFileLen-1), code: StatusPartialContent, ranges: []wantRange{{0, testFileLen}}}, - {r: "bytes=0-" + itoa(testFileLen), code: StatusPartialContent, ranges: []wantRange{{0, testFileLen}}}, + {r: "bytes=0-9", code: StatusPartialContent, ranges: []wantRange{{0, testFileLen - 1}}}, + {r: "bytes=0-10", code: StatusPartialContent, ranges: []wantRange{{0, testFileLen}}}, + {r: "bytes=0-11", code: StatusPartialContent, ranges: []wantRange{{0, testFileLen}}}, + {r: "bytes=10-11", code: StatusPartialContent, ranges: []wantRange{{testFileLen - 1, testFileLen}}}, + {r: "bytes=10-", code: StatusPartialContent, ranges: []wantRange{{testFileLen - 1, testFileLen}}}, + {r: "bytes=11-", code: StatusRequestedRangeNotSatisfiable}, + {r: "bytes=11-12", code: StatusRequestedRangeNotSatisfiable}, + {r: "bytes=12-12", code: StatusRequestedRangeNotSatisfiable}, + {r: "bytes=11-100", code: StatusRequestedRangeNotSatisfiable}, + {r: "bytes=12-100", code: StatusRequestedRangeNotSatisfiable}, + {r: "bytes=100-", code: StatusRequestedRangeNotSatisfiable}, + {r: "bytes=100-1000", code: StatusRequestedRangeNotSatisfiable}, } func TestServeFile(t *testing.T) { @@ -489,6 +497,7 @@ type fakeFileInfo struct { modtime time.Time ents []*fakeFileInfo contents string + err error } func (f *fakeFileInfo) Name() string { return f.basename } @@ -541,6 +550,9 @@ func (fs fakeFS) Open(name string) (File, error) { if !ok { return nil, os.ErrNotExist } + if f.err != nil { + return nil, f.err + } return &fakeFile{ReadSeeker: strings.NewReader(f.contents), fi: f, path: name}, nil } @@ -743,6 +755,12 @@ func TestServeContent(t *testing.T) { wantContentType: "text/css; charset=utf-8", wantLastMod: "Wed, 25 Jun 2014 17:12:18 GMT", }, + "unix_zero_modtime": { + content: strings.NewReader("foo"), + modtime: time.Unix(0, 0), + wantStatus: StatusOK, + wantContentType: "text/html; charset=utf-8", + }, } for testName, tt := range tests { var content io.ReadSeeker @@ -789,6 +807,31 @@ func TestServeContent(t *testing.T) { } } +func TestServeContentErrorMessages(t *testing.T) { + defer afterTest(t) + fs := fakeFS{ + "/500": &fakeFileInfo{ + err: errors.New("random error"), + }, + "/403": &fakeFileInfo{ + err: &os.PathError{Err: os.ErrPermission}, + }, + } + ts := httptest.NewServer(FileServer(fs)) + defer ts.Close() + for _, code := range []int{403, 404, 500} { + res, err := DefaultClient.Get(fmt.Sprintf("%s/%d", ts.URL, code)) + if err != nil { + t.Errorf("Error fetching /%d: %v", code, err) + continue + } + if res.StatusCode != code { + t.Errorf("For /%d, status code = %d; want %d", code, res.StatusCode, code) + } + res.Body.Close() + } +} + // verifies that sendfile is being used on Linux func TestLinuxSendfile(t *testing.T) { defer afterTest(t) diff --git a/libgo/go/net/http/header.go b/libgo/go/net/http/header.go index 153b94370f8..d847b131184 100644 --- a/libgo/go/net/http/header.go +++ b/libgo/go/net/http/header.go @@ -168,6 +168,8 @@ func (h Header) WriteSubset(w io.Writer, exclude map[string]bool) error { // letter and any letter following a hyphen to upper case; // the rest are converted to lowercase. For example, the // canonical key for "accept-encoding" is "Accept-Encoding". +// If s contains a space or invalid header field bytes, it is +// returned without modifications. func CanonicalHeaderKey(s string) string { return textproto.CanonicalMIMEHeaderKey(s) } // hasToken reports whether token appears with v, ASCII diff --git a/libgo/go/net/http/http_test.go b/libgo/go/net/http/http_test.go new file mode 100644 index 00000000000..dead3b04542 --- /dev/null +++ b/libgo/go/net/http/http_test.go @@ -0,0 +1,58 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Tests of internal functions with no better homes. + +package http + +import ( + "reflect" + "testing" +) + +func TestForeachHeaderElement(t *testing.T) { + tests := []struct { + in string + want []string + }{ + {"Foo", []string{"Foo"}}, + {" Foo", []string{"Foo"}}, + {"Foo ", []string{"Foo"}}, + {" Foo ", []string{"Foo"}}, + + {"foo", []string{"foo"}}, + {"anY-cAsE", []string{"anY-cAsE"}}, + + {"", nil}, + {",,,, , ,, ,,, ,", nil}, + + {" Foo,Bar, Baz,lower,,Quux ", []string{"Foo", "Bar", "Baz", "lower", "Quux"}}, + } + for _, tt := range tests { + var got []string + foreachHeaderElement(tt.in, func(v string) { + got = append(got, v) + }) + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("foreachHeaderElement(%q) = %q; want %q", tt.in, got, tt.want) + } + } +} + +func TestCleanHost(t *testing.T) { + tests := []struct { + in, want string + }{ + {"www.google.com", "www.google.com"}, + {"www.google.com foo", "www.google.com"}, + {"www.google.com/foo", "www.google.com"}, + {" first character is a space", ""}, + } + for _, tt := range tests { + got := cleanHost(tt.in) + if tt.want != got { + t.Errorf("cleanHost(%q) = %q, want %q", tt.in, got, tt.want) + } + } +} diff --git a/libgo/go/net/http/httptest/server.go b/libgo/go/net/http/httptest/server.go index 789e7bf41e6..96eb0ef6d2f 100644 --- a/libgo/go/net/http/httptest/server.go +++ b/libgo/go/net/http/httptest/server.go @@ -204,25 +204,35 @@ func (h *waitGroupHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { // "127.0.0.1" and "[::1]", expiring at the last second of 2049 (the end // of ASN.1 time). // generated from src/crypto/tls: -// go run generate_cert.go --rsa-bits 512 --host 127.0.0.1,::1,example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h +// go run generate_cert.go --rsa-bits 1024 --host 127.0.0.1,::1,example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h var localhostCert = []byte(`-----BEGIN CERTIFICATE----- -MIIBdzCCASOgAwIBAgIBADALBgkqhkiG9w0BAQUwEjEQMA4GA1UEChMHQWNtZSBD -bzAeFw03MDAxMDEwMDAwMDBaFw00OTEyMzEyMzU5NTlaMBIxEDAOBgNVBAoTB0Fj -bWUgQ28wWjALBgkqhkiG9w0BAQEDSwAwSAJBAN55NcYKZeInyTuhcCwFMhDHCmwa -IUSdtXdcbItRB/yfXGBhiex00IaLXQnSU+QZPRZWYqeTEbFSgihqi1PUDy8CAwEA -AaNoMGYwDgYDVR0PAQH/BAQDAgCkMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA8GA1Ud -EwEB/wQFMAMBAf8wLgYDVR0RBCcwJYILZXhhbXBsZS5jb22HBH8AAAGHEAAAAAAA -AAAAAAAAAAAAAAEwCwYJKoZIhvcNAQEFA0EAAoQn/ytgqpiLcZu9XKbCJsJcvkgk -Se6AbGXgSlq+ZCEVo0qIwSgeBqmsJxUu7NCSOwVJLYNEBO2DtIxoYVk+MA== +MIICEzCCAXygAwIBAgIQMIMChMLGrR+QvmQvpwAU6zANBgkqhkiG9w0BAQsFADAS +MRAwDgYDVQQKEwdBY21lIENvMCAXDTcwMDEwMTAwMDAwMFoYDzIwODQwMTI5MTYw +MDAwWjASMRAwDgYDVQQKEwdBY21lIENvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB +iQKBgQDuLnQAI3mDgey3VBzWnB2L39JUU4txjeVE6myuDqkM/uGlfjb9SjY1bIw4 +iA5sBBZzHi3z0h1YV8QPuxEbi4nW91IJm2gsvvZhIrCHS3l6afab4pZBl2+XsDul +rKBxKKtD1rGxlG4LjncdabFn9gvLZad2bSysqz/qTAUStTvqJQIDAQABo2gwZjAO +BgNVHQ8BAf8EBAMCAqQwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYDVR0TAQH/BAUw +AwEB/zAuBgNVHREEJzAlggtleGFtcGxlLmNvbYcEfwAAAYcQAAAAAAAAAAAAAAAA +AAAAATANBgkqhkiG9w0BAQsFAAOBgQCEcetwO59EWk7WiJsG4x8SY+UIAA+flUI9 +tyC4lNhbcF2Idq9greZwbYCqTTTr2XiRNSMLCOjKyI7ukPoPjo16ocHj+P3vZGfs +h1fIw3cSS2OolhloGw/XM6RWPWtPAlGykKLciQrBru5NAPvCMsb/I1DAceTiotQM +fblo6RBxUQ== -----END CERTIFICATE-----`) // localhostKey is the private key for localhostCert. var localhostKey = []byte(`-----BEGIN RSA PRIVATE KEY----- -MIIBPAIBAAJBAN55NcYKZeInyTuhcCwFMhDHCmwaIUSdtXdcbItRB/yfXGBhiex0 -0IaLXQnSU+QZPRZWYqeTEbFSgihqi1PUDy8CAwEAAQJBAQdUx66rfh8sYsgfdcvV -NoafYpnEcB5s4m/vSVe6SU7dCK6eYec9f9wpT353ljhDUHq3EbmE4foNzJngh35d -AekCIQDhRQG5Li0Wj8TM4obOnnXUXf1jRv0UkzE9AHWLG5q3AwIhAPzSjpYUDjVW -MCUXgckTpKCuGwbJk7424Nb8bLzf3kllAiA5mUBgjfr/WtFSJdWcPQ4Zt9KTMNKD -EUO0ukpTwEIl6wIhAMbGqZK3zAAFdq8DD2jPx+UJXnh0rnOkZBzDtJ6/iN69AiEA -1Aq8MJgTaYsDQWyU/hDq5YkDJc9e9DSCvUIzqxQWMQE= +MIICXgIBAAKBgQDuLnQAI3mDgey3VBzWnB2L39JUU4txjeVE6myuDqkM/uGlfjb9 +SjY1bIw4iA5sBBZzHi3z0h1YV8QPuxEbi4nW91IJm2gsvvZhIrCHS3l6afab4pZB +l2+XsDulrKBxKKtD1rGxlG4LjncdabFn9gvLZad2bSysqz/qTAUStTvqJQIDAQAB +AoGAGRzwwir7XvBOAy5tM/uV6e+Zf6anZzus1s1Y1ClbjbE6HXbnWWF/wbZGOpet +3Zm4vD6MXc7jpTLryzTQIvVdfQbRc6+MUVeLKwZatTXtdZrhu+Jk7hx0nTPy8Jcb +uJqFk541aEw+mMogY/xEcfbWd6IOkp+4xqjlFLBEDytgbIECQQDvH/E6nk+hgN4H +qzzVtxxr397vWrjrIgPbJpQvBsafG7b0dA4AFjwVbFLmQcj2PprIMmPcQrooz8vp +jy4SHEg1AkEA/v13/5M47K9vCxmb8QeD/asydfsgS5TeuNi8DoUBEmiSJwma7FXY +fFUtxuvL7XvjwjN5B30pNEbc6Iuyt7y4MQJBAIt21su4b3sjXNueLKH85Q+phy2U +fQtuUE9txblTu14q3N7gHRZB4ZMhFYyDy8CKrN2cPg/Fvyt0Xlp/DoCzjA0CQQDU +y2ptGsuSmgUtWj3NM9xuwYPm+Z/F84K6+ARYiZ6PYj013sovGKUFfYAqVXVlxtIX +qyUBnu3X9ps8ZfjLZO7BAkEAlT4R5Yl6cGhaJQYZHOde3JEMhNRcVFMO8dJDaFeo +f9Oeos0UUothgiDktdQHxdNEwLjQf7lJJBzV+5OtwswCWA== -----END RSA PRIVATE KEY-----`) diff --git a/libgo/go/net/http/httputil/dump.go b/libgo/go/net/http/httputil/dump.go index ac8f103f9b9..ca2d1cde924 100644 --- a/libgo/go/net/http/httputil/dump.go +++ b/libgo/go/net/http/httputil/dump.go @@ -98,6 +98,14 @@ func DumpRequestOut(req *http.Request, body bool) ([]byte, error) { defer pr.Close() defer pw.Close() dr := &delegateReader{c: make(chan io.Reader)} + + t := &http.Transport{ + Dial: func(net, addr string) (net.Conn, error) { + return &dumpConn{io.MultiWriter(&buf, pw), dr}, nil + }, + } + defer t.CloseIdleConnections() + // Wait for the request before replying with a dummy response: go func() { req, err := http.ReadRequest(bufio.NewReader(pr)) @@ -107,16 +115,9 @@ func DumpRequestOut(req *http.Request, body bool) ([]byte, error) { io.Copy(ioutil.Discard, req.Body) req.Body.Close() } - dr.c <- strings.NewReader("HTTP/1.1 204 No Content\r\n\r\n") + dr.c <- strings.NewReader("HTTP/1.1 204 No Content\r\nConnection: close\r\n\r\n") }() - t := &http.Transport{ - DisableKeepAlives: true, - Dial: func(net, addr string) (net.Conn, error) { - return &dumpConn{io.MultiWriter(&buf, pw), dr}, nil - }, - } - _, err := t.RoundTrip(reqSend) req.Body = save diff --git a/libgo/go/net/http/httputil/dump_test.go b/libgo/go/net/http/httputil/dump_test.go index 024ee5a86f4..ae67e983ae9 100644 --- a/libgo/go/net/http/httputil/dump_test.go +++ b/libgo/go/net/http/httputil/dump_test.go @@ -71,7 +71,7 @@ var dumpTests = []dumpTest{ WantDumpOut: "GET /foo HTTP/1.1\r\n" + "Host: example.com\r\n" + - "User-Agent: Go 1.1 package http\r\n" + + "User-Agent: Go-http-client/1.1\r\n" + "Accept-Encoding: gzip\r\n\r\n", }, @@ -83,7 +83,7 @@ var dumpTests = []dumpTest{ WantDumpOut: "GET /foo HTTP/1.1\r\n" + "Host: example.com\r\n" + - "User-Agent: Go 1.1 package http\r\n" + + "User-Agent: Go-http-client/1.1\r\n" + "Accept-Encoding: gzip\r\n\r\n", }, @@ -105,7 +105,7 @@ var dumpTests = []dumpTest{ WantDumpOut: "POST / HTTP/1.1\r\n" + "Host: post.tld\r\n" + - "User-Agent: Go 1.1 package http\r\n" + + "User-Agent: Go-http-client/1.1\r\n" + "Content-Length: 6\r\n" + "Accept-Encoding: gzip\r\n\r\n", @@ -130,7 +130,7 @@ var dumpTests = []dumpTest{ WantDumpOut: "POST / HTTP/1.1\r\n" + "Host: post.tld\r\n" + - "User-Agent: Go 1.1 package http\r\n" + + "User-Agent: Go-http-client/1.1\r\n" + "Content-Length: 8193\r\n" + "Accept-Encoding: gzip\r\n\r\n" + strings.Repeat("a", 8193), diff --git a/libgo/go/net/http/httputil/reverseproxy.go b/libgo/go/net/http/httputil/reverseproxy.go index ab463701803..3b7a184d933 100644 --- a/libgo/go/net/http/httputil/reverseproxy.go +++ b/libgo/go/net/http/httputil/reverseproxy.go @@ -100,6 +100,24 @@ var hopHeaders = []string{ "Upgrade", } +type requestCanceler interface { + CancelRequest(*http.Request) +} + +type runOnFirstRead struct { + io.Reader + + fn func() // Run before first Read, then set to nil +} + +func (c *runOnFirstRead) Read(bs []byte) (int, error) { + if c.fn != nil { + c.fn() + c.fn = nil + } + return c.Reader.Read(bs) +} + func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) { transport := p.Transport if transport == nil { @@ -109,6 +127,34 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) { outreq := new(http.Request) *outreq = *req // includes shallow copies of maps, but okay + if closeNotifier, ok := rw.(http.CloseNotifier); ok { + if requestCanceler, ok := transport.(requestCanceler); ok { + reqDone := make(chan struct{}) + defer close(reqDone) + + clientGone := closeNotifier.CloseNotify() + + outreq.Body = struct { + io.Reader + io.Closer + }{ + Reader: &runOnFirstRead{ + Reader: outreq.Body, + fn: func() { + go func() { + select { + case <-clientGone: + requestCanceler.CancelRequest(outreq) + case <-reqDone: + } + }() + }, + }, + Closer: outreq.Body, + } + } + } + p.Director(outreq) outreq.Proto = "HTTP/1.1" outreq.ProtoMajor = 1 @@ -148,7 +194,6 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) { rw.WriteHeader(http.StatusInternalServerError) return } - defer res.Body.Close() for _, h := range hopHeaders { res.Header.Del(h) @@ -156,8 +201,28 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) { copyHeader(rw.Header(), res.Header) + // The "Trailer" header isn't included in the Transport's response, + // at least for *http.Transport. Build it up from Trailer. + if len(res.Trailer) > 0 { + var trailerKeys []string + for k := range res.Trailer { + trailerKeys = append(trailerKeys, k) + } + rw.Header().Add("Trailer", strings.Join(trailerKeys, ", ")) + } + rw.WriteHeader(res.StatusCode) + if len(res.Trailer) > 0 { + // Force chunking if we saw a response trailer. + // This prevents net/http from calculating the length for short + // bodies and adding a Content-Length. + if fl, ok := rw.(http.Flusher); ok { + fl.Flush() + } + } p.copyResponse(rw, res.Body) + res.Body.Close() // close now, instead of defer, to populate res.Trailer + copyHeader(rw.Header(), res.Trailer) } func (p *ReverseProxy) copyResponse(dst io.Writer, src io.Reader) { diff --git a/libgo/go/net/http/httputil/reverseproxy_test.go b/libgo/go/net/http/httputil/reverseproxy_test.go index e9539b44b6e..25947e6a8ab 100644 --- a/libgo/go/net/http/httputil/reverseproxy_test.go +++ b/libgo/go/net/http/httputil/reverseproxy_test.go @@ -8,9 +8,12 @@ package httputil import ( "io/ioutil" + "log" "net/http" "net/http/httptest" "net/url" + "reflect" + "runtime" "strings" "testing" "time" @@ -41,6 +44,7 @@ func TestReverseProxy(t *testing.T) { if g, e := r.Host, "some-name"; g != e { t.Errorf("backend got Host header %q, want %q", g, e) } + w.Header().Set("Trailer", "X-Trailer") w.Header().Set("X-Foo", "bar") w.Header().Set("Upgrade", "foo") w.Header().Set(fakeHopHeader, "foo") @@ -49,6 +53,7 @@ func TestReverseProxy(t *testing.T) { http.SetCookie(w, &http.Cookie{Name: "flavor", Value: "chocolateChip"}) w.WriteHeader(backendStatus) w.Write([]byte(backendResponse)) + w.Header().Set("X-Trailer", "trailer_value") })) defer backend.Close() backendURL, err := url.Parse(backend.URL) @@ -83,6 +88,9 @@ func TestReverseProxy(t *testing.T) { if g, e := len(res.Header["Set-Cookie"]), 1; g != e { t.Fatalf("got %d SetCookies, want %d", g, e) } + if g, e := res.Trailer, (http.Header{"X-Trailer": nil}); !reflect.DeepEqual(g, e) { + t.Errorf("before reading body, Trailer = %#v; want %#v", g, e) + } if cookie := res.Cookies()[0]; cookie.Name != "flavor" { t.Errorf("unexpected cookie %q", cookie.Name) } @@ -90,6 +98,10 @@ func TestReverseProxy(t *testing.T) { if g, e := string(bodyBytes), backendResponse; g != e { t.Errorf("got body %q; expected %q", g, e) } + if g, e := res.Trailer.Get("X-Trailer"), "trailer_value"; g != e { + t.Errorf("Trailer(X-Trailer) = %q ; want %q", g, e) + } + } func TestXForwardedFor(t *testing.T) { @@ -211,3 +223,61 @@ func TestReverseProxyFlushInterval(t *testing.T) { t.Error("maxLatencyWriter flushLoop() never exited") } } + +func TestReverseProxyCancellation(t *testing.T) { + if runtime.GOOS == "plan9" { + t.Skip("skipping test; see https://golang.org/issue/9554") + } + const backendResponse = "I am the backend" + + reqInFlight := make(chan struct{}) + backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + close(reqInFlight) + + select { + case <-time.After(10 * time.Second): + // Note: this should only happen in broken implementations, and the + // closenotify case should be instantaneous. + t.Log("Failed to close backend connection") + t.Fail() + case <-w.(http.CloseNotifier).CloseNotify(): + } + + w.WriteHeader(http.StatusOK) + w.Write([]byte(backendResponse)) + })) + + defer backend.Close() + + backend.Config.ErrorLog = log.New(ioutil.Discard, "", 0) + + backendURL, err := url.Parse(backend.URL) + if err != nil { + t.Fatal(err) + } + + proxyHandler := NewSingleHostReverseProxy(backendURL) + + // Discards errors of the form: + // http: proxy error: read tcp 127.0.0.1:44643: use of closed network connection + proxyHandler.ErrorLog = log.New(ioutil.Discard, "", 0) + + frontend := httptest.NewServer(proxyHandler) + defer frontend.Close() + + getReq, _ := http.NewRequest("GET", frontend.URL, nil) + go func() { + <-reqInFlight + http.DefaultTransport.(*http.Transport).CancelRequest(getReq) + }() + res, err := http.DefaultClient.Do(getReq) + if res != nil { + t.Fatal("Non-nil response") + } + if err == nil { + // This should be an error like: + // Get http://127.0.0.1:58079: read tcp 127.0.0.1:58079: + // use of closed network connection + t.Fatal("DefaultClient.Do() returned nil error") + } +} diff --git a/libgo/go/net/http/internal/chunked.go b/libgo/go/net/http/internal/chunked.go index 9294deb3e5e..6d7c69874d9 100644 --- a/libgo/go/net/http/internal/chunked.go +++ b/libgo/go/net/http/internal/chunked.go @@ -173,8 +173,12 @@ func (cw *chunkedWriter) Write(data []byte) (n int, err error) { err = io.ErrShortWrite return } - _, err = io.WriteString(cw.Wire, "\r\n") - + if _, err = io.WriteString(cw.Wire, "\r\n"); err != nil { + return + } + if bw, ok := cw.Wire.(*FlushAfterChunkWriter); ok { + err = bw.Flush() + } return } @@ -183,6 +187,15 @@ func (cw *chunkedWriter) Close() error { return err } +// FlushAfterChunkWriter signals from the caller of NewChunkedWriter +// that each chunk should be followed by a flush. It is used by the +// http.Transport code to keep the buffering behavior for headers and +// trailers, but flush out chunks aggressively in the middle for +// request bodies which may be generated slowly. See Issue 6574. +type FlushAfterChunkWriter struct { + *bufio.Writer +} + func parseHexUint(v []byte) (n uint64, err error) { for _, b := range v { n <<= 4 diff --git a/libgo/go/net/http/lex.go b/libgo/go/net/http/lex.go index cb33318f49b..50b14f8b325 100644 --- a/libgo/go/net/http/lex.go +++ b/libgo/go/net/http/lex.go @@ -4,6 +4,11 @@ package http +import ( + "strings" + "unicode/utf8" +) + // This file deals with lexical matters of HTTP var isTokenTable = [127]bool{ @@ -94,3 +99,71 @@ func isToken(r rune) bool { func isNotToken(r rune) bool { return !isToken(r) } + +// headerValuesContainsToken reports whether any string in values +// contains the provided token, ASCII case-insensitively. +func headerValuesContainsToken(values []string, token string) bool { + for _, v := range values { + if headerValueContainsToken(v, token) { + return true + } + } + return false +} + +// isOWS reports whether b is an optional whitespace byte, as defined +// by RFC 7230 section 3.2.3. +func isOWS(b byte) bool { return b == ' ' || b == '\t' } + +// trimOWS returns x with all optional whitespace removes from the +// beginning and end. +func trimOWS(x string) string { + // TODO: consider using strings.Trim(x, " \t") instead, + // if and when it's fast enough. See issue 10292. + // But this ASCII-only code will probably always beat UTF-8 + // aware code. + for len(x) > 0 && isOWS(x[0]) { + x = x[1:] + } + for len(x) > 0 && isOWS(x[len(x)-1]) { + x = x[:len(x)-1] + } + return x +} + +// headerValueContainsToken reports whether v (assumed to be a +// 0#element, in the ABNF extension described in RFC 7230 section 7) +// contains token amongst its comma-separated tokens, ASCII +// case-insensitively. +func headerValueContainsToken(v string, token string) bool { + v = trimOWS(v) + if comma := strings.IndexByte(v, ','); comma != -1 { + return tokenEqual(trimOWS(v[:comma]), token) || headerValueContainsToken(v[comma+1:], token) + } + return tokenEqual(v, token) +} + +// lowerASCII returns the ASCII lowercase version of b. +func lowerASCII(b byte) byte { + if 'A' <= b && b <= 'Z' { + return b + ('a' - 'A') + } + return b +} + +// tokenEqual reports whether t1 and t2 are equal, ASCII case-insensitively. +func tokenEqual(t1, t2 string) bool { + if len(t1) != len(t2) { + return false + } + for i, b := range t1 { + if b >= utf8.RuneSelf { + // No UTF-8 or non-ASCII allowed in tokens. + return false + } + if lowerASCII(byte(b)) != lowerASCII(t2[i]) { + return false + } + } + return true +} diff --git a/libgo/go/net/http/lex_test.go b/libgo/go/net/http/lex_test.go index 6d9d294f703..986fda17dcd 100644 --- a/libgo/go/net/http/lex_test.go +++ b/libgo/go/net/http/lex_test.go @@ -29,3 +29,73 @@ func TestIsToken(t *testing.T) { } } } + +func TestHeaderValuesContainsToken(t *testing.T) { + tests := []struct { + vals []string + token string + want bool + }{ + { + vals: []string{"foo"}, + token: "foo", + want: true, + }, + { + vals: []string{"bar", "foo"}, + token: "foo", + want: true, + }, + { + vals: []string{"foo"}, + token: "FOO", + want: true, + }, + { + vals: []string{"foo"}, + token: "bar", + want: false, + }, + { + vals: []string{" foo "}, + token: "FOO", + want: true, + }, + { + vals: []string{"foo,bar"}, + token: "FOO", + want: true, + }, + { + vals: []string{"bar,foo,bar"}, + token: "FOO", + want: true, + }, + { + vals: []string{"bar , foo"}, + token: "FOO", + want: true, + }, + { + vals: []string{"foo ,bar "}, + token: "FOO", + want: true, + }, + { + vals: []string{"bar, foo ,bar"}, + token: "FOO", + want: true, + }, + { + vals: []string{"bar , foo"}, + token: "FOO", + want: true, + }, + } + for _, tt := range tests { + got := headerValuesContainsToken(tt.vals, tt.token) + if got != tt.want { + t.Errorf("headerValuesContainsToken(%q, %q) = %v; want %v", tt.vals, tt.token, got, tt.want) + } + } +} diff --git a/libgo/go/net/http/main_test.go b/libgo/go/net/http/main_test.go index b8c71fd19fd..12eea6f0e11 100644 --- a/libgo/go/net/http/main_test.go +++ b/libgo/go/net/http/main_test.go @@ -56,17 +56,21 @@ func goroutineLeaked() bool { // not counting goroutines for leakage in -short mode return false } - gs := interestingGoroutines() - n := 0 - stackCount := make(map[string]int) - for _, g := range gs { - stackCount[g]++ - n++ - } - - if n == 0 { - return false + var stackCount map[string]int + for i := 0; i < 5; i++ { + n := 0 + stackCount = make(map[string]int) + gs := interestingGoroutines() + for _, g := range gs { + stackCount[g]++ + n++ + } + if n == 0 { + return false + } + // Wait for goroutines to schedule and die off: + time.Sleep(100 * time.Millisecond) } fmt.Fprintf(os.Stderr, "Too many goroutines running after net/http test(s).\n") for stack, count := range stackCount { @@ -75,7 +79,7 @@ func goroutineLeaked() bool { return true } -func afterTest(t *testing.T) { +func afterTest(t testing.TB) { http.DefaultTransport.(*http.Transport).CloseIdleConnections() if testing.Short() { return diff --git a/libgo/go/net/http/npn_test.go b/libgo/go/net/http/npn_test.go index 98b8930d064..e2e911d3dd1 100644 --- a/libgo/go/net/http/npn_test.go +++ b/libgo/go/net/http/npn_test.go @@ -6,6 +6,7 @@ package http_test import ( "bufio" + "bytes" "crypto/tls" "fmt" "io" @@ -17,6 +18,7 @@ import ( ) func TestNextProtoUpgrade(t *testing.T) { + defer afterTest(t) ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) { fmt.Fprintf(w, "path=%s,proto=", r.URL.Path) if r.TLS != nil { @@ -38,12 +40,12 @@ func TestNextProtoUpgrade(t *testing.T) { ts.StartTLS() defer ts.Close() - tr := newTLSTransport(t, ts) - defer tr.CloseIdleConnections() - c := &Client{Transport: tr} - // Normal request, without NPN. { + tr := newTLSTransport(t, ts) + defer tr.CloseIdleConnections() + c := &Client{Transport: tr} + res, err := c.Get(ts.URL) if err != nil { t.Fatal(err) @@ -60,11 +62,17 @@ func TestNextProtoUpgrade(t *testing.T) { // Request to an advertised but unhandled NPN protocol. // Server will hang up. { - tr.CloseIdleConnections() + tr := newTLSTransport(t, ts) tr.TLSClientConfig.NextProtos = []string{"unhandled-proto"} - _, err := c.Get(ts.URL) + defer tr.CloseIdleConnections() + c := &Client{Transport: tr} + + res, err := c.Get(ts.URL) if err == nil { - t.Errorf("expected error on unhandled-proto request") + defer res.Body.Close() + var buf bytes.Buffer + res.Write(&buf) + t.Errorf("expected error on unhandled-proto request; got: %s", buf.Bytes()) } } diff --git a/libgo/go/net/http/pprof/pprof.go b/libgo/go/net/http/pprof/pprof.go index a23f1bc4bc6..8994392b1e4 100644 --- a/libgo/go/net/http/pprof/pprof.go +++ b/libgo/go/net/http/pprof/pprof.go @@ -34,12 +34,16 @@ // // go tool pprof http://localhost:6060/debug/pprof/block // +// Or to collect a 5-second execution trace: +// +// wget http://localhost:6060/debug/pprof/trace?seconds=5 +// // To view all available profiles, open http://localhost:6060/debug/pprof/ // in your browser. // // For a study of the facility in action, visit // -// http://blog.golang.org/2011/06/profiling-go-programs.html +// https://blog.golang.org/2011/06/profiling-go-programs.html // package pprof @@ -64,6 +68,7 @@ func init() { http.Handle("/debug/pprof/cmdline", http.HandlerFunc(Cmdline)) http.Handle("/debug/pprof/profile", http.HandlerFunc(Profile)) http.Handle("/debug/pprof/symbol", http.HandlerFunc(Symbol)) + http.Handle("/debug/pprof/trace", http.HandlerFunc(Trace)) } // Cmdline responds with the running program's @@ -98,6 +103,33 @@ func Profile(w http.ResponseWriter, r *http.Request) { pprof.StopCPUProfile() } +// Trace responds with the execution trace in binary form. +// Tracing lasts for duration specified in seconds GET parameter, or for 1 second if not specified. +// The package initialization registers it as /debug/pprof/trace. +func Trace(w http.ResponseWriter, r *http.Request) { + sec, _ := strconv.ParseInt(r.FormValue("seconds"), 10, 64) + if sec == 0 { + sec = 1 + } + + // Set Content Type assuming trace.Start will work, + // because if it does it starts writing. + w.Header().Set("Content-Type", "application/octet-stream") + w.Write([]byte("tracing not yet supported with gccgo")) + /* + if err := trace.Start(w); err != nil { + // trace.Start failed, so no writes yet. + // Can change header back to text content and send error code. + w.Header().Set("Content-Type", "text/plain; charset=utf-8") + w.WriteHeader(http.StatusInternalServerError) + fmt.Fprintf(w, "Could not enable tracing: %s\n", err) + return + } + time.Sleep(time.Duration(sec) * time.Second) + trace.Stop() + */ +} + // Symbol looks up the program counters listed in the request, // responding with a table mapping program counters to function names. // The package initialization registers it as /debug/pprof/symbol. @@ -193,17 +225,17 @@ var indexTmpl = template.Must(template.New("index").Parse(` /debug/pprof/ + /debug/pprof/

- profiles:
{{range .}} -
{{.Count}}{{.Name}} +
{{.Count}}{{.Name}} {{end}}

-full goroutine stack dump
+full goroutine stack dump
`)) diff --git a/libgo/go/net/http/proxy_test.go b/libgo/go/net/http/proxy_test.go index b6aed3792b6..823d1447ee9 100644 --- a/libgo/go/net/http/proxy_test.go +++ b/libgo/go/net/http/proxy_test.go @@ -18,7 +18,7 @@ var UseProxyTests = []struct { match bool }{ // Never proxy localhost: - {"localhost:80", false}, + {"localhost", false}, {"127.0.0.1", false}, {"127.0.0.2", false}, {"[::1]", false}, diff --git a/libgo/go/net/http/readrequest_test.go b/libgo/go/net/http/readrequest_test.go index e930d99af62..60e2be41d17 100644 --- a/libgo/go/net/http/readrequest_test.go +++ b/libgo/go/net/http/readrequest_test.go @@ -9,6 +9,7 @@ import ( "bytes" "fmt" "io" + "io/ioutil" "net/url" "reflect" "strings" @@ -177,6 +178,36 @@ var reqTests = []reqTest{ noError, }, + // Tests chunked body and a bogus Content-Length which should be deleted. + { + "POST / HTTP/1.1\r\n" + + "Host: foo.com\r\n" + + "Transfer-Encoding: chunked\r\n" + + "Content-Length: 9999\r\n\r\n" + // to be removed. + "3\r\nfoo\r\n" + + "3\r\nbar\r\n" + + "0\r\n" + + "\r\n", + &Request{ + Method: "POST", + URL: &url.URL{ + Path: "/", + }, + TransferEncoding: []string{"chunked"}, + Proto: "HTTP/1.1", + ProtoMajor: 1, + ProtoMinor: 1, + Header: Header{}, + ContentLength: -1, + Host: "foo.com", + RequestURI: "/", + }, + + "foobar", + noTrailer, + noError, + }, + // CONNECT request with domain name: { "CONNECT www.google.com:443 HTTP/1.1\r\n\r\n", @@ -323,6 +354,32 @@ var reqTests = []reqTest{ noTrailer, noError, }, + + // HEAD with Content-Length 0. Make sure this is permitted, + // since I think we used to send it. + { + "HEAD / HTTP/1.1\r\nHost: issue8261.com\r\nConnection: close\r\nContent-Length: 0\r\n\r\n", + &Request{ + Method: "HEAD", + URL: &url.URL{ + Path: "/", + }, + Header: Header{ + "Connection": []string{"close"}, + "Content-Length": []string{"0"}, + }, + Host: "issue8261.com", + Proto: "HTTP/1.1", + ProtoMajor: 1, + ProtoMinor: 1, + Close: true, + RequestURI: "/", + }, + + noBody, + noTrailer, + noError, + }, } func TestReadRequest(t *testing.T) { @@ -356,3 +413,34 @@ func TestReadRequest(t *testing.T) { } } } + +// reqBytes treats req as a request (with \n delimiters) and returns it with \r\n delimiters, +// ending in \r\n\r\n +func reqBytes(req string) []byte { + return []byte(strings.Replace(strings.TrimSpace(req), "\n", "\r\n", -1) + "\r\n\r\n") +} + +var badRequestTests = []struct { + name string + req []byte +}{ + {"bad_connect_host", reqBytes("CONNECT []%20%48%54%54%50%2f%31%2e%31%0a%4d%79%48%65%61%64%65%72%3a%20%31%32%33%0a%0a HTTP/1.0")}, + {"smuggle_two_contentlen", reqBytes(`POST / HTTP/1.1 +Content-Length: 3 +Content-Length: 4 + +abc`)}, + {"smuggle_content_len_head", reqBytes(`HEAD / HTTP/1.1 +Host: foo +Content-Length: 5`)}, +} + +func TestReadRequest_Bad(t *testing.T) { + for _, tt := range badRequestTests { + got, err := ReadRequest(bufio.NewReader(bytes.NewReader(tt.req))) + if err == nil { + all, err := ioutil.ReadAll(got.Body) + t.Errorf("%s: got unexpected request = %#v\n Body = %q, %v", tt.name, got, all, err) + } + } +} diff --git a/libgo/go/net/http/request.go b/libgo/go/net/http/request.go index 487eebcb841..31fe45a4edb 100644 --- a/libgo/go/net/http/request.go +++ b/libgo/go/net/http/request.go @@ -25,9 +25,6 @@ import ( ) const ( - maxValueLength = 4096 - maxHeaderLines = 1024 - chunkSize = 4 << 10 // 4 KB chunks defaultMaxMemory = 32 << 20 // 32 MB ) @@ -172,8 +169,9 @@ type Request struct { // The HTTP client ignores Form and uses Body instead. Form url.Values - // PostForm contains the parsed form data from POST or PUT - // body parameters. + // PostForm contains the parsed form data from POST, PATCH, + // or PUT body parameters. + // // This field is only available after ParseForm is called. // The HTTP client ignores PostForm and uses Body instead. PostForm url.Values @@ -226,6 +224,13 @@ type Request struct { // otherwise it leaves the field nil. // This field is ignored by the HTTP client. TLS *tls.ConnectionState + + // Cancel is an optional channel whose closure indicates that the client + // request should be regarded as canceled. Not all implementations of + // RoundTripper may support Cancel. + // + // For server requests, this field is not applicable. + Cancel <-chan struct{} } // ProtoAtLeast reports whether the HTTP protocol used @@ -245,6 +250,7 @@ func (r *Request) Cookies() []*Cookie { return readCookies(r.Header, "") } +// ErrNoCookie is returned by Request's Cookie method when a cookie is not found. var ErrNoCookie = errors.New("http: named cookie not present") // Cookie returns the named cookie provided in the request or @@ -329,13 +335,12 @@ func valueOrDefault(value, def string) string { } // NOTE: This is not intended to reflect the actual Go version being used. -// It was changed from "Go http package" to "Go 1.1 package http" at the -// time of the Go 1.1 release because the former User-Agent had ended up -// on a blacklist for some intrusion detection systems. +// It was changed at the time of Go 1.1 release because the former User-Agent +// had ended up on a blacklist for some intrusion detection systems. // See https://codereview.appspot.com/7532043. -const defaultUserAgent = "Go 1.1 package http" +const defaultUserAgent = "Go-http-client/1.1" -// Write writes an HTTP/1.1 request -- header and body -- in wire format. +// Write writes an HTTP/1.1 request, which is the header and body, in wire format. // This method consults the following fields of the request: // Host // URL @@ -364,14 +369,23 @@ func (r *Request) WriteProxy(w io.Writer) error { // extraHeaders may be nil func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header) error { - host := req.Host + // Find the target host. Prefer the Host: header, but if that + // is not given, use the host from the request URL. + // + // Clean the host, in case it arrives with unexpected stuff in it. + host := cleanHost(req.Host) if host == "" { if req.URL == nil { return errors.New("http: Request.Write on Request with no Host or URL set") } - host = req.URL.Host + host = cleanHost(req.URL.Host) } + // According to RFC 6874, an HTTP client, proxy, or other + // intermediary must remove any IPv6 zone identifier attached + // to an outgoing URI. + host = removeZone(host) + ruri := req.URL.RequestURI() if usingProxy && req.URL.Scheme != "" && req.URL.Opaque == "" { ruri = req.URL.Scheme + "://" + host + ruri @@ -456,6 +470,39 @@ func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header) err return nil } +// cleanHost strips anything after '/' or ' '. +// Ideally we'd clean the Host header according to the spec: +// https://tools.ietf.org/html/rfc7230#section-5.4 (Host = uri-host [ ":" port ]") +// https://tools.ietf.org/html/rfc7230#section-2.7 (uri-host -> rfc3986's host) +// https://tools.ietf.org/html/rfc3986#section-3.2.2 (definition of host) +// But practically, what we are trying to avoid is the situation in +// issue 11206, where a malformed Host header used in the proxy context +// would create a bad request. So it is enough to just truncate at the +// first offending character. +func cleanHost(in string) string { + if i := strings.IndexAny(in, " /"); i != -1 { + return in[:i] + } + return in +} + +// removeZone removes IPv6 zone identifer from host. +// E.g., "[fe80::1%en0]:8080" to "[fe80::1]:8080" +func removeZone(host string) string { + if !strings.HasPrefix(host, "[") { + return host + } + i := strings.LastIndex(host, "]") + if i < 0 { + return host + } + j := strings.LastIndex(host[:i], "%") + if j < 0 { + return host + } + return host[:j] + host[i:] +} + // ParseHTTPVersion parses a HTTP version string. // "HTTP/1.0" returns (1, 0, true). func ParseHTTPVersion(vers string) (major, minor int, ok bool) { @@ -489,6 +536,13 @@ func ParseHTTPVersion(vers string) (major, minor int, ok bool) { // If the provided body is also an io.Closer, the returned // Request.Body is set to body and will be closed by the Client // methods Do, Post, and PostForm, and Transport.RoundTrip. +// +// NewRequest returns a Request suitable for use with Client.Do or +// Transport.RoundTrip. +// To create a request for use with testing a Server Handler use either +// ReadRequest or manually update the Request fields. See the Request +// type's documentation for the difference between inbound and outbound +// request fields. func NewRequest(method, urlStr string, body io.Reader) (*Request, error) { u, err := url.Parse(urlStr) if err != nil { @@ -536,10 +590,11 @@ func (r *Request) BasicAuth() (username, password string, ok bool) { // parseBasicAuth parses an HTTP Basic Authentication string. // "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==" returns ("Aladdin", "open sesame", true). func parseBasicAuth(auth string) (username, password string, ok bool) { - if !strings.HasPrefix(auth, "Basic ") { + const prefix = "Basic " + if !strings.HasPrefix(auth, prefix) { return } - c, err := base64.StdEncoding.DecodeString(strings.TrimPrefix(auth, "Basic ")) + c, err := base64.StdEncoding.DecodeString(auth[len(prefix):]) if err != nil { return } @@ -587,7 +642,7 @@ func putTextprotoReader(r *textproto.Reader) { textprotoReaderPool.Put(r) } -// ReadRequest reads and parses a request from b. +// ReadRequest reads and parses an incoming request from b. func ReadRequest(b *bufio.Reader) (req *Request, err error) { tp := newTextprotoReader(b) @@ -660,19 +715,20 @@ func ReadRequest(b *bufio.Reader) (req *Request, err error) { fixPragmaCacheControl(req.Header) + req.Close = shouldClose(req.ProtoMajor, req.ProtoMinor, req.Header, false) + err = readTransfer(req, b) if err != nil { return nil, err } - req.Close = shouldClose(req.ProtoMajor, req.ProtoMinor, req.Header, false) return req, nil } // MaxBytesReader is similar to io.LimitReader but is intended for // limiting the size of incoming request bodies. In contrast to // io.LimitReader, MaxBytesReader's result is a ReadCloser, returns a -// non-EOF error for a Read beyond the limit, and Closes the +// non-EOF error for a Read beyond the limit, and closes the // underlying reader when its Close method is called. // // MaxBytesReader prevents clients from accidentally or maliciously @@ -686,23 +742,52 @@ type maxBytesReader struct { r io.ReadCloser // underlying reader n int64 // max bytes remaining stopped bool + sawEOF bool +} + +func (l *maxBytesReader) tooLarge() (n int, err error) { + if !l.stopped { + l.stopped = true + if res, ok := l.w.(*response); ok { + res.requestTooLarge() + } + } + return 0, errors.New("http: request body too large") } func (l *maxBytesReader) Read(p []byte) (n int, err error) { - if l.n <= 0 { - if !l.stopped { - l.stopped = true - if res, ok := l.w.(*response); ok { - res.requestTooLarge() - } + toRead := l.n + if l.n == 0 { + if l.sawEOF { + return l.tooLarge() } - return 0, errors.New("http: request body too large") + // The underlying io.Reader may not return (0, io.EOF) + // at EOF if the requested size is 0, so read 1 byte + // instead. The io.Reader docs are a bit ambiguous + // about the return value of Read when 0 bytes are + // requested, and {bytes,strings}.Reader gets it wrong + // too (it returns (0, nil) even at EOF). + toRead = 1 } - if int64(len(p)) > l.n { - p = p[:l.n] + if int64(len(p)) > toRead { + p = p[:toRead] } n, err = l.r.Read(p) + if err == io.EOF { + l.sawEOF = true + } + if l.n == 0 { + // If we had zero bytes to read remaining (but hadn't seen EOF) + // and we get a byte here, that means we went over our limit. + if n > 0 { + return l.tooLarge() + } + return 0, err + } l.n -= int64(n) + if l.n < 0 { + l.n = 0 + } return } @@ -852,6 +937,7 @@ func (r *Request) ParseMultipartForm(maxMemory int64) error { // POST and PUT body parameters take precedence over URL query string values. // FormValue calls ParseMultipartForm and ParseForm if necessary and ignores // any errors returned by these functions. +// If key is not present, FormValue returns the empty string. // To access multiple values of the same key, call ParseForm and // then inspect Request.Form directly. func (r *Request) FormValue(key string) string { @@ -868,6 +954,7 @@ func (r *Request) FormValue(key string) string { // or PUT request body. URL query parameters are ignored. // PostFormValue calls ParseMultipartForm and ParseForm if necessary and ignores // any errors returned by these functions. +// If key is not present, PostFormValue returns the empty string. func (r *Request) PostFormValue(key string) string { if r.PostForm == nil { r.ParseMultipartForm(defaultMaxMemory) diff --git a/libgo/go/net/http/request_test.go b/libgo/go/net/http/request_test.go index 759ea4e8b5d..627620c0c41 100644 --- a/libgo/go/net/http/request_test.go +++ b/libgo/go/net/http/request_test.go @@ -178,6 +178,7 @@ func TestParseMultipartForm(t *testing.T) { } func TestRedirect(t *testing.T) { + defer afterTest(t) ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { switch r.URL.Path { case "/": @@ -326,13 +327,31 @@ func TestReadRequestErrors(t *testing.T) { } } +var newRequestHostTests = []struct { + in, out string +}{ + {"http://www.example.com/", "www.example.com"}, + {"http://www.example.com:8080/", "www.example.com:8080"}, + + {"http://192.168.0.1/", "192.168.0.1"}, + {"http://192.168.0.1:8080/", "192.168.0.1:8080"}, + + {"http://[fe80::1]/", "[fe80::1]"}, + {"http://[fe80::1]:8080/", "[fe80::1]:8080"}, + {"http://[fe80::1%25en0]/", "[fe80::1%en0]"}, + {"http://[fe80::1%25en0]:8080/", "[fe80::1%en0]:8080"}, +} + func TestNewRequestHost(t *testing.T) { - req, err := NewRequest("GET", "http://localhost:1234/", nil) - if err != nil { - t.Fatal(err) - } - if req.Host != "localhost:1234" { - t.Errorf("Host = %q; want localhost:1234", req.Host) + for i, tt := range newRequestHostTests { + req, err := NewRequest("GET", tt.in, nil) + if err != nil { + t.Errorf("#%v: %v", i, err) + continue + } + if req.Host != tt.out { + t.Errorf("got %q; want %q", req.Host, tt.out) + } } } @@ -402,8 +421,6 @@ type getBasicAuthTest struct { ok bool } -type parseBasicAuthTest getBasicAuthTest - type basicAuthCredentialsTest struct { username, password string } @@ -496,6 +513,82 @@ func TestRequestWriteBufferedWriter(t *testing.T) { } } +func TestRequestBadHost(t *testing.T) { + got := []string{} + req, err := NewRequest("GET", "http://foo.com with spaces/after", nil) + if err != nil { + t.Fatal(err) + } + req.Write(logWrites{t, &got}) + want := []string{ + "GET /after HTTP/1.1\r\n", + "Host: foo.com\r\n", + "User-Agent: " + DefaultUserAgent + "\r\n", + "\r\n", + } + if !reflect.DeepEqual(got, want) { + t.Errorf("Writes = %q\n Want = %q", got, want) + } +} + +func TestStarRequest(t *testing.T) { + req, err := ReadRequest(bufio.NewReader(strings.NewReader("M-SEARCH * HTTP/1.1\r\n\r\n"))) + if err != nil { + return + } + var out bytes.Buffer + if err := req.Write(&out); err != nil { + t.Fatal(err) + } + back, err := ReadRequest(bufio.NewReader(&out)) + if err != nil { + t.Fatal(err) + } + // Ignore the Headers (the User-Agent breaks the deep equal, + // but we don't care about it) + req.Header = nil + back.Header = nil + if !reflect.DeepEqual(req, back) { + t.Errorf("Original request doesn't match Request read back.") + t.Logf("Original: %#v", req) + t.Logf("Original.URL: %#v", req.URL) + t.Logf("Wrote: %s", out.Bytes()) + t.Logf("Read back (doesn't match Original): %#v", back) + } +} + +type responseWriterJustWriter struct { + io.Writer +} + +func (responseWriterJustWriter) Header() Header { panic("should not be called") } +func (responseWriterJustWriter) WriteHeader(int) { panic("should not be called") } + +// delayedEOFReader never returns (n > 0, io.EOF), instead putting +// off the io.EOF until a subsequent Read call. +type delayedEOFReader struct { + r io.Reader +} + +func (dr delayedEOFReader) Read(p []byte) (n int, err error) { + n, err = dr.r.Read(p) + if n > 0 && err == io.EOF { + err = nil + } + return +} + +func TestIssue10884_MaxBytesEOF(t *testing.T) { + dst := ioutil.Discard + _, err := io.Copy(dst, MaxBytesReader( + responseWriterJustWriter{dst}, + ioutil.NopCloser(delayedEOFReader{strings.NewReader("12345")}), + 5)) + if err != nil { + t.Fatal(err) + } +} + func testMissingFile(t *testing.T, req *Request) { f, fh, err := req.FormFile("missing") if f != nil { diff --git a/libgo/go/net/http/requestwrite_test.go b/libgo/go/net/http/requestwrite_test.go index 7a6bd587863..cfb95b0a800 100644 --- a/libgo/go/net/http/requestwrite_test.go +++ b/libgo/go/net/http/requestwrite_test.go @@ -93,13 +93,13 @@ var reqWriteTests = []reqWriteTest{ WantWrite: "GET /search HTTP/1.1\r\n" + "Host: www.google.com\r\n" + - "User-Agent: Go 1.1 package http\r\n" + + "User-Agent: Go-http-client/1.1\r\n" + "Transfer-Encoding: chunked\r\n\r\n" + chunk("abcdef") + chunk(""), WantProxy: "GET http://www.google.com/search HTTP/1.1\r\n" + "Host: www.google.com\r\n" + - "User-Agent: Go 1.1 package http\r\n" + + "User-Agent: Go-http-client/1.1\r\n" + "Transfer-Encoding: chunked\r\n\r\n" + chunk("abcdef") + chunk(""), }, @@ -123,14 +123,14 @@ var reqWriteTests = []reqWriteTest{ WantWrite: "POST /search HTTP/1.1\r\n" + "Host: www.google.com\r\n" + - "User-Agent: Go 1.1 package http\r\n" + + "User-Agent: Go-http-client/1.1\r\n" + "Connection: close\r\n" + "Transfer-Encoding: chunked\r\n\r\n" + chunk("abcdef") + chunk(""), WantProxy: "POST http://www.google.com/search HTTP/1.1\r\n" + "Host: www.google.com\r\n" + - "User-Agent: Go 1.1 package http\r\n" + + "User-Agent: Go-http-client/1.1\r\n" + "Connection: close\r\n" + "Transfer-Encoding: chunked\r\n\r\n" + chunk("abcdef") + chunk(""), @@ -156,7 +156,7 @@ var reqWriteTests = []reqWriteTest{ WantWrite: "POST /search HTTP/1.1\r\n" + "Host: www.google.com\r\n" + - "User-Agent: Go 1.1 package http\r\n" + + "User-Agent: Go-http-client/1.1\r\n" + "Connection: close\r\n" + "Content-Length: 6\r\n" + "\r\n" + @@ -164,7 +164,7 @@ var reqWriteTests = []reqWriteTest{ WantProxy: "POST http://www.google.com/search HTTP/1.1\r\n" + "Host: www.google.com\r\n" + - "User-Agent: Go 1.1 package http\r\n" + + "User-Agent: Go-http-client/1.1\r\n" + "Connection: close\r\n" + "Content-Length: 6\r\n" + "\r\n" + @@ -187,14 +187,14 @@ var reqWriteTests = []reqWriteTest{ WantWrite: "POST / HTTP/1.1\r\n" + "Host: example.com\r\n" + - "User-Agent: Go 1.1 package http\r\n" + + "User-Agent: Go-http-client/1.1\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef", WantProxy: "POST http://example.com/ HTTP/1.1\r\n" + "Host: example.com\r\n" + - "User-Agent: Go 1.1 package http\r\n" + + "User-Agent: Go-http-client/1.1\r\n" + "Content-Length: 6\r\n" + "\r\n" + "abcdef", @@ -210,7 +210,7 @@ var reqWriteTests = []reqWriteTest{ WantWrite: "GET /search HTTP/1.1\r\n" + "Host: www.google.com\r\n" + - "User-Agent: Go 1.1 package http\r\n" + + "User-Agent: Go-http-client/1.1\r\n" + "\r\n", }, @@ -232,13 +232,13 @@ var reqWriteTests = []reqWriteTest{ // Also, nginx expects it for POST and PUT. WantWrite: "POST / HTTP/1.1\r\n" + "Host: example.com\r\n" + - "User-Agent: Go 1.1 package http\r\n" + + "User-Agent: Go-http-client/1.1\r\n" + "Content-Length: 0\r\n" + "\r\n", WantProxy: "POST / HTTP/1.1\r\n" + "Host: example.com\r\n" + - "User-Agent: Go 1.1 package http\r\n" + + "User-Agent: Go-http-client/1.1\r\n" + "Content-Length: 0\r\n" + "\r\n", }, @@ -258,13 +258,13 @@ var reqWriteTests = []reqWriteTest{ WantWrite: "POST / HTTP/1.1\r\n" + "Host: example.com\r\n" + - "User-Agent: Go 1.1 package http\r\n" + + "User-Agent: Go-http-client/1.1\r\n" + "Transfer-Encoding: chunked\r\n\r\n" + chunk("x") + chunk(""), WantProxy: "POST / HTTP/1.1\r\n" + "Host: example.com\r\n" + - "User-Agent: Go 1.1 package http\r\n" + + "User-Agent: Go-http-client/1.1\r\n" + "Transfer-Encoding: chunked\r\n\r\n" + chunk("x") + chunk(""), }, @@ -365,7 +365,7 @@ var reqWriteTests = []reqWriteTest{ WantWrite: "GET /foo HTTP/1.1\r\n" + "Host: \r\n" + - "User-Agent: Go 1.1 package http\r\n" + + "User-Agent: Go-http-client/1.1\r\n" + "X-Foo: X-Bar\r\n\r\n", }, @@ -391,7 +391,7 @@ var reqWriteTests = []reqWriteTest{ WantWrite: "GET /search HTTP/1.1\r\n" + "Host: \r\n" + - "User-Agent: Go 1.1 package http\r\n\r\n", + "User-Agent: Go-http-client/1.1\r\n\r\n", }, // Opaque test #1 from golang.org/issue/4860 @@ -410,7 +410,7 @@ var reqWriteTests = []reqWriteTest{ WantWrite: "GET /%2F/%2F/ HTTP/1.1\r\n" + "Host: www.google.com\r\n" + - "User-Agent: Go 1.1 package http\r\n\r\n", + "User-Agent: Go-http-client/1.1\r\n\r\n", }, // Opaque test #2 from golang.org/issue/4860 @@ -429,7 +429,7 @@ var reqWriteTests = []reqWriteTest{ WantWrite: "GET http://y.google.com/%2F/%2F/ HTTP/1.1\r\n" + "Host: x.google.com\r\n" + - "User-Agent: Go 1.1 package http\r\n\r\n", + "User-Agent: Go-http-client/1.1\r\n\r\n", }, // Testing custom case in header keys. Issue 5022. @@ -451,10 +451,41 @@ var reqWriteTests = []reqWriteTest{ WantWrite: "GET / HTTP/1.1\r\n" + "Host: www.google.com\r\n" + - "User-Agent: Go 1.1 package http\r\n" + + "User-Agent: Go-http-client/1.1\r\n" + "ALL-CAPS: x\r\n" + "\r\n", }, + + // Request with host header field; IPv6 address with zone identifier + { + Req: Request{ + Method: "GET", + URL: &url.URL{ + Host: "[fe80::1%en0]", + }, + }, + + WantWrite: "GET / HTTP/1.1\r\n" + + "Host: [fe80::1]\r\n" + + "User-Agent: Go-http-client/1.1\r\n" + + "\r\n", + }, + + // Request with optional host header field; IPv6 address with zone identifier + { + Req: Request{ + Method: "GET", + URL: &url.URL{ + Host: "www.example.com", + }, + Host: "[fe80::1%en0]:8080", + }, + + WantWrite: "GET / HTTP/1.1\r\n" + + "Host: [fe80::1]:8080\r\n" + + "User-Agent: Go-http-client/1.1\r\n" + + "\r\n", + }, } func TestRequestWrite(t *testing.T) { @@ -538,7 +569,7 @@ func TestRequestWriteClosesBody(t *testing.T) { } expected := "POST / HTTP/1.1\r\n" + "Host: foo.com\r\n" + - "User-Agent: Go 1.1 package http\r\n" + + "User-Agent: Go-http-client/1.1\r\n" + "Transfer-Encoding: chunked\r\n\r\n" + // TODO: currently we don't buffer before chunking, so we get a // single "m" chunk before the other chunks, as this was the 1-byte diff --git a/libgo/go/net/http/response.go b/libgo/go/net/http/response.go index 5d2c39080e4..76b85385244 100644 --- a/libgo/go/net/http/response.go +++ b/libgo/go/net/http/response.go @@ -48,7 +48,10 @@ type Response struct { // The http Client and Transport guarantee that Body is always // non-nil, even on responses without a body or responses with // a zero-length body. It is the caller's responsibility to - // close Body. + // close Body. The default HTTP client's Transport does not + // attempt to reuse HTTP/1.0 or HTTP/1.1 TCP connections + // ("keep-alive") unless the Body is read to completion and is + // closed. // // The Body is automatically dechunked if the server replied // with a "chunked" Transfer-Encoding. @@ -90,6 +93,8 @@ func (r *Response) Cookies() []*Cookie { return readSetCookies(r.Header) } +// ErrNoLocation is returned by Response's Location method +// when no Location header is present. var ErrNoLocation = errors.New("http: no Location header in response") // Location returns the URL of the response's "Location" header, @@ -186,8 +191,10 @@ func (r *Response) ProtoAtLeast(major, minor int) bool { r.ProtoMajor == major && r.ProtoMinor >= minor } -// Writes the response (header, body and trailer) in wire format. This method -// consults the following fields of the response: +// Write writes r to w in the HTTP/1.n server response format, +// including the status line, headers, body, and optional trailer. +// +// This method consults the following fields of the response r: // // StatusCode // ProtoMajor @@ -199,7 +206,7 @@ func (r *Response) ProtoAtLeast(major, minor int) bool { // ContentLength // Header, values for non-canonical keys will have unpredictable behavior // -// Body is closed after it is sent. +// The Response Body is closed after it is sent. func (r *Response) Write(w io.Writer) error { // Status line text := r.Status diff --git a/libgo/go/net/http/response_test.go b/libgo/go/net/http/response_test.go index 06e940d9aba..421cf55f491 100644 --- a/libgo/go/net/http/response_test.go +++ b/libgo/go/net/http/response_test.go @@ -405,6 +405,57 @@ some body`, "foobar", }, + + // Both keep-alive and close, on the same Connection line. (Issue 8840) + { + "HTTP/1.1 200 OK\r\n" + + "Content-Length: 256\r\n" + + "Connection: keep-alive, close\r\n" + + "\r\n", + + Response{ + Status: "200 OK", + StatusCode: 200, + Proto: "HTTP/1.1", + ProtoMajor: 1, + ProtoMinor: 1, + Request: dummyReq("HEAD"), + Header: Header{ + "Content-Length": {"256"}, + }, + TransferEncoding: nil, + Close: true, + ContentLength: 256, + }, + + "", + }, + + // Both keep-alive and close, on different Connection lines. (Issue 8840) + { + "HTTP/1.1 200 OK\r\n" + + "Content-Length: 256\r\n" + + "Connection: keep-alive\r\n" + + "Connection: close\r\n" + + "\r\n", + + Response{ + Status: "200 OK", + StatusCode: 200, + Proto: "HTTP/1.1", + ProtoMajor: 1, + ProtoMinor: 1, + Request: dummyReq("HEAD"), + Header: Header{ + "Content-Length": {"256"}, + }, + TransferEncoding: nil, + Close: true, + ContentLength: 256, + }, + + "", + }, } func TestReadResponse(t *testing.T) { diff --git a/libgo/go/net/http/responsewrite_test.go b/libgo/go/net/http/responsewrite_test.go index 585b13b8504..5b8d47ab581 100644 --- a/libgo/go/net/http/responsewrite_test.go +++ b/libgo/go/net/http/responsewrite_test.go @@ -207,6 +207,21 @@ func TestResponseWrite(t *testing.T) { }, "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n", }, + + // When a response to a POST has Content-Length: -1, make sure we don't + // write the Content-Length as -1. + { + Response{ + StatusCode: StatusOK, + ProtoMajor: 1, + ProtoMinor: 1, + Request: &Request{Method: "POST"}, + Header: Header{}, + ContentLength: -1, + Body: ioutil.NopCloser(strings.NewReader("abcdef")), + }, + "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\nabcdef", + }, } for i := range respWriteTests { diff --git a/libgo/go/net/http/serve_test.go b/libgo/go/net/http/serve_test.go index 6bd168d3de3..d51417eb4a0 100644 --- a/libgo/go/net/http/serve_test.go +++ b/libgo/go/net/http/serve_test.go @@ -20,6 +20,7 @@ import ( . "net/http" "net/http/httptest" "net/http/httputil" + "net/http/internal" "net/url" "os" "os/exec" @@ -146,6 +147,7 @@ func (ht handlerTest) rawResponse(req string) string { } func TestConsumingBodyOnNextConn(t *testing.T) { + defer afterTest(t) conn := new(testConn) for i := 0; i < 2; i++ { conn.readBuf.Write([]byte( @@ -205,6 +207,7 @@ var handlers = []struct { }{ {"/", "Default"}, {"/someDir/", "someDir"}, + {"/#/", "hash"}, {"someHost.com/someDir/", "someHost.com/someDir"}, } @@ -213,12 +216,14 @@ var vtests = []struct { expected string }{ {"http://localhost/someDir/apage", "someDir"}, + {"http://localhost/%23/apage", "hash"}, {"http://localhost/otherDir/apage", "Default"}, {"http://someHost.com/someDir/apage", "someHost.com/someDir"}, {"http://otherHost.com/someDir/apage", "someDir"}, {"http://otherHost.com/aDir/apage", "Default"}, // redirections for trees {"http://localhost/someDir", "/someDir/"}, + {"http://localhost/%23", "/%23/"}, {"http://someHost.com/someDir", "/someDir/"}, } @@ -416,7 +421,7 @@ func TestServeMuxHandlerRedirects(t *testing.T) { } } -// Tests for http://code.google.com/p/go/issues/detail?id=900 +// Tests for https://golang.org/issue/900 func TestMuxRedirectLeadingSlashes(t *testing.T) { paths := []string{"//foo.txt", "///foo.txt", "/../../foo.txt"} for _, path := range paths { @@ -443,7 +448,7 @@ func TestMuxRedirectLeadingSlashes(t *testing.T) { func TestServerTimeouts(t *testing.T) { if runtime.GOOS == "plan9" { - t.Skip("skipping test; see http://golang.org/issue/7237") + t.Skip("skipping test; see https://golang.org/issue/7237") } defer afterTest(t) reqNum := 0 @@ -522,7 +527,7 @@ func TestServerTimeouts(t *testing.T) { // request) that will never happen. func TestOnlyWriteTimeout(t *testing.T) { if runtime.GOOS == "plan9" { - t.Skip("skipping test; see http://golang.org/issue/7237") + t.Skip("skipping test; see https://golang.org/issue/7237") } defer afterTest(t) var conn net.Conn @@ -877,7 +882,7 @@ func TestHeadResponses(t *testing.T) { func TestTLSHandshakeTimeout(t *testing.T) { if runtime.GOOS == "plan9" { - t.Skip("skipping test; see http://golang.org/issue/7237") + t.Skip("skipping test; see https://golang.org/issue/7237") } defer afterTest(t) ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) {})) @@ -1105,6 +1110,7 @@ func TestServerExpect(t *testing.T) { // Under a ~256KB (maxPostHandlerReadBytes) threshold, the server // should consume client request bodies that a handler didn't read. func TestServerUnreadRequestBodyLittle(t *testing.T) { + defer afterTest(t) conn := new(testConn) body := strings.Repeat("x", 100<<10) conn.readBuf.Write([]byte(fmt.Sprintf( @@ -1166,6 +1172,365 @@ func TestServerUnreadRequestBodyLarge(t *testing.T) { } } +type handlerBodyCloseTest struct { + bodySize int + bodyChunked bool + reqConnClose bool + + wantEOFSearch bool // should Handler's Body.Close do Reads, looking for EOF? + wantNextReq bool // should it find the next request on the same conn? +} + +func (t handlerBodyCloseTest) connectionHeader() string { + if t.reqConnClose { + return "Connection: close\r\n" + } + return "" +} + +var handlerBodyCloseTests = [...]handlerBodyCloseTest{ + // Small enough to slurp past to the next request + + // has Content-Length. + 0: { + bodySize: 20 << 10, + bodyChunked: false, + reqConnClose: false, + wantEOFSearch: true, + wantNextReq: true, + }, + + // Small enough to slurp past to the next request + + // is chunked. + 1: { + bodySize: 20 << 10, + bodyChunked: true, + reqConnClose: false, + wantEOFSearch: true, + wantNextReq: true, + }, + + // Small enough to slurp past to the next request + + // has Content-Length + + // declares Connection: close (so pointless to read more). + 2: { + bodySize: 20 << 10, + bodyChunked: false, + reqConnClose: true, + wantEOFSearch: false, + wantNextReq: false, + }, + + // Small enough to slurp past to the next request + + // declares Connection: close, + // but chunked, so it might have trailers. + // TODO: maybe skip this search if no trailers were declared + // in the headers. + 3: { + bodySize: 20 << 10, + bodyChunked: true, + reqConnClose: true, + wantEOFSearch: true, + wantNextReq: false, + }, + + // Big with Content-Length, so give up immediately if we know it's too big. + 4: { + bodySize: 1 << 20, + bodyChunked: false, // has a Content-Length + reqConnClose: false, + wantEOFSearch: false, + wantNextReq: false, + }, + + // Big chunked, so read a bit before giving up. + 5: { + bodySize: 1 << 20, + bodyChunked: true, + reqConnClose: false, + wantEOFSearch: true, + wantNextReq: false, + }, + + // Big with Connection: close, but chunked, so search for trailers. + // TODO: maybe skip this search if no trailers were declared + // in the headers. + 6: { + bodySize: 1 << 20, + bodyChunked: true, + reqConnClose: true, + wantEOFSearch: true, + wantNextReq: false, + }, + + // Big with Connection: close, so don't do any reads on Close. + // With Content-Length. + 7: { + bodySize: 1 << 20, + bodyChunked: false, + reqConnClose: true, + wantEOFSearch: false, + wantNextReq: false, + }, +} + +func TestHandlerBodyClose(t *testing.T) { + for i, tt := range handlerBodyCloseTests { + testHandlerBodyClose(t, i, tt) + } +} + +func testHandlerBodyClose(t *testing.T, i int, tt handlerBodyCloseTest) { + conn := new(testConn) + body := strings.Repeat("x", tt.bodySize) + if tt.bodyChunked { + conn.readBuf.WriteString("POST / HTTP/1.1\r\n" + + "Host: test\r\n" + + tt.connectionHeader() + + "Transfer-Encoding: chunked\r\n" + + "\r\n") + cw := internal.NewChunkedWriter(&conn.readBuf) + io.WriteString(cw, body) + cw.Close() + conn.readBuf.WriteString("\r\n") + } else { + conn.readBuf.Write([]byte(fmt.Sprintf( + "POST / HTTP/1.1\r\n"+ + "Host: test\r\n"+ + tt.connectionHeader()+ + "Content-Length: %d\r\n"+ + "\r\n", len(body)))) + conn.readBuf.Write([]byte(body)) + } + if !tt.reqConnClose { + conn.readBuf.WriteString("GET / HTTP/1.1\r\nHost: test\r\n\r\n") + } + conn.closec = make(chan bool, 1) + + ls := &oneConnListener{conn} + var numReqs int + var size0, size1 int + go Serve(ls, HandlerFunc(func(rw ResponseWriter, req *Request) { + numReqs++ + if numReqs == 1 { + size0 = conn.readBuf.Len() + req.Body.Close() + size1 = conn.readBuf.Len() + } + })) + <-conn.closec + if numReqs < 1 || numReqs > 2 { + t.Fatalf("%d. bug in test. unexpected number of requests = %d", i, numReqs) + } + didSearch := size0 != size1 + if didSearch != tt.wantEOFSearch { + t.Errorf("%d. did EOF search = %v; want %v (size went from %d to %d)", i, didSearch, !didSearch, size0, size1) + } + if tt.wantNextReq && numReqs != 2 { + t.Errorf("%d. numReq = %d; want 2", i, numReqs) + } +} + +// testHandlerBodyConsumer represents a function injected into a test handler to +// vary work done on a request Body. +type testHandlerBodyConsumer struct { + name string + f func(io.ReadCloser) +} + +var testHandlerBodyConsumers = []testHandlerBodyConsumer{ + {"nil", func(io.ReadCloser) {}}, + {"close", func(r io.ReadCloser) { r.Close() }}, + {"discard", func(r io.ReadCloser) { io.Copy(ioutil.Discard, r) }}, +} + +func TestRequestBodyReadErrorClosesConnection(t *testing.T) { + defer afterTest(t) + for _, handler := range testHandlerBodyConsumers { + conn := new(testConn) + conn.readBuf.WriteString("POST /public HTTP/1.1\r\n" + + "Host: test\r\n" + + "Transfer-Encoding: chunked\r\n" + + "\r\n" + + "hax\r\n" + // Invalid chunked encoding + "GET /secret HTTP/1.1\r\n" + + "Host: test\r\n" + + "\r\n") + + conn.closec = make(chan bool, 1) + ls := &oneConnListener{conn} + var numReqs int + go Serve(ls, HandlerFunc(func(_ ResponseWriter, req *Request) { + numReqs++ + if strings.Contains(req.URL.Path, "secret") { + t.Error("Request for /secret encountered, should not have happened.") + } + handler.f(req.Body) + })) + <-conn.closec + if numReqs != 1 { + t.Errorf("Handler %v: got %d reqs; want 1", handler.name, numReqs) + } + } +} + +func TestInvalidTrailerClosesConnection(t *testing.T) { + defer afterTest(t) + for _, handler := range testHandlerBodyConsumers { + conn := new(testConn) + conn.readBuf.WriteString("POST /public HTTP/1.1\r\n" + + "Host: test\r\n" + + "Trailer: hack\r\n" + + "Transfer-Encoding: chunked\r\n" + + "\r\n" + + "3\r\n" + + "hax\r\n" + + "0\r\n" + + "I'm not a valid trailer\r\n" + + "GET /secret HTTP/1.1\r\n" + + "Host: test\r\n" + + "\r\n") + + conn.closec = make(chan bool, 1) + ln := &oneConnListener{conn} + var numReqs int + go Serve(ln, HandlerFunc(func(_ ResponseWriter, req *Request) { + numReqs++ + if strings.Contains(req.URL.Path, "secret") { + t.Errorf("Handler %s, Request for /secret encountered, should not have happened.", handler.name) + } + handler.f(req.Body) + })) + <-conn.closec + if numReqs != 1 { + t.Errorf("Handler %s: got %d reqs; want 1", handler.name, numReqs) + } + } +} + +// slowTestConn is a net.Conn that provides a means to simulate parts of a +// request being received piecemeal. Deadlines can be set and enforced in both +// Read and Write. +type slowTestConn struct { + // over multiple calls to Read, time.Durations are slept, strings are read. + script []interface{} + closec chan bool + rd, wd time.Time // read, write deadline + noopConn +} + +func (c *slowTestConn) SetDeadline(t time.Time) error { + c.SetReadDeadline(t) + c.SetWriteDeadline(t) + return nil +} + +func (c *slowTestConn) SetReadDeadline(t time.Time) error { + c.rd = t + return nil +} + +func (c *slowTestConn) SetWriteDeadline(t time.Time) error { + c.wd = t + return nil +} + +func (c *slowTestConn) Read(b []byte) (n int, err error) { +restart: + if !c.rd.IsZero() && time.Now().After(c.rd) { + return 0, syscall.ETIMEDOUT + } + if len(c.script) == 0 { + return 0, io.EOF + } + + switch cue := c.script[0].(type) { + case time.Duration: + if !c.rd.IsZero() { + // If the deadline falls in the middle of our sleep window, deduct + // part of the sleep, then return a timeout. + if remaining := c.rd.Sub(time.Now()); remaining < cue { + c.script[0] = cue - remaining + time.Sleep(remaining) + return 0, syscall.ETIMEDOUT + } + } + c.script = c.script[1:] + time.Sleep(cue) + goto restart + + case string: + n = copy(b, cue) + // If cue is too big for the buffer, leave the end for the next Read. + if len(cue) > n { + c.script[0] = cue[n:] + } else { + c.script = c.script[1:] + } + + default: + panic("unknown cue in slowTestConn script") + } + + return +} + +func (c *slowTestConn) Close() error { + select { + case c.closec <- true: + default: + } + return nil +} + +func (c *slowTestConn) Write(b []byte) (int, error) { + if !c.wd.IsZero() && time.Now().After(c.wd) { + return 0, syscall.ETIMEDOUT + } + return len(b), nil +} + +func TestRequestBodyTimeoutClosesConnection(t *testing.T) { + if testing.Short() { + t.Skip("skipping in -short mode") + } + defer afterTest(t) + for _, handler := range testHandlerBodyConsumers { + conn := &slowTestConn{ + script: []interface{}{ + "POST /public HTTP/1.1\r\n" + + "Host: test\r\n" + + "Content-Length: 10000\r\n" + + "\r\n", + "foo bar baz", + 600 * time.Millisecond, // Request deadline should hit here + "GET /secret HTTP/1.1\r\n" + + "Host: test\r\n" + + "\r\n", + }, + closec: make(chan bool, 1), + } + ls := &oneConnListener{conn} + + var numReqs int + s := Server{ + Handler: HandlerFunc(func(_ ResponseWriter, req *Request) { + numReqs++ + if strings.Contains(req.URL.Path, "secret") { + t.Error("Request for /secret encountered, should not have happened.") + } + handler.f(req.Body) + }), + ReadTimeout: 400 * time.Millisecond, + } + go s.Serve(ls) + <-conn.closec + + if numReqs != 1 { + t.Errorf("Handler %v: got %d reqs; want 1", handler.name, numReqs) + } + } +} + func TestTimeoutHandler(t *testing.T) { defer afterTest(t) sendHi := make(chan bool, 1) @@ -1451,19 +1816,23 @@ func testHandlerPanic(t *testing.T, withHijack bool, panicValue interface{}) { } } -func TestNoDate(t *testing.T) { +func TestServerNoDate(t *testing.T) { testServerNoHeader(t, "Date") } +func TestServerNoContentType(t *testing.T) { testServerNoHeader(t, "Content-Type") } + +func testServerNoHeader(t *testing.T, header string) { defer afterTest(t) ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { - w.Header()["Date"] = nil + w.Header()[header] = nil + io.WriteString(w, "foo") // non-empty })) defer ts.Close() res, err := Get(ts.URL) if err != nil { t.Fatal(err) } - _, present := res.Header["Date"] - if present { - t.Fatalf("Expected no Date header; got %v", res.Header["Date"]) + res.Body.Close() + if got, ok := res.Header[header]; ok { + t.Fatalf("Expected no %s header; got %q", header, got) } } @@ -1577,7 +1946,7 @@ func TestRequestBodyLimit(t *testing.T) { // side of their TCP connection, the server doesn't send a 400 Bad Request. func TestClientWriteShutdown(t *testing.T) { if runtime.GOOS == "plan9" { - t.Skip("skipping test; see http://golang.org/issue/7237") + t.Skip("skipping test; see https://golang.org/issue/7237") } defer afterTest(t) ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {})) @@ -1632,7 +2001,7 @@ func TestServerBufferedChunking(t *testing.T) { // Tests that the server flushes its response headers out when it's // ignoring the response body and waits a bit before forcefully // closing the TCP connection, causing the client to get a RST. -// See http://golang.org/issue/3595 +// See https://golang.org/issue/3595 func TestServerGracefulClose(t *testing.T) { defer afterTest(t) ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { @@ -2124,7 +2493,7 @@ func TestDoubleHijack(t *testing.T) { <-conn.closec } -// http://code.google.com/p/go/issues/detail?id=5955 +// https://golang.org/issue/5955 // Note that this does not test the "request too large" // exit path from the http server. This is intentional; // not sending Connection: close is just a minor wire @@ -2288,17 +2657,13 @@ func TestTransportAndServerSharedBodyRace(t *testing.T) { unblockBackend := make(chan bool) backend := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) { - io.CopyN(rw, req.Body, bodySize/2) + io.CopyN(rw, req.Body, bodySize) <-unblockBackend })) defer backend.Close() backendRespc := make(chan *Response, 1) proxy := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) { - if req.RequestURI == "/foo" { - rw.Write([]byte("bar")) - return - } req2, _ := NewRequest("POST", backend.URL, req.Body) req2.ContentLength = bodySize @@ -2307,7 +2672,7 @@ func TestTransportAndServerSharedBodyRace(t *testing.T) { t.Errorf("Proxy outbound request: %v", err) return } - _, err = io.CopyN(ioutil.Discard, bresp.Body, bodySize/4) + _, err = io.CopyN(ioutil.Discard, bresp.Body, bodySize/2) if err != nil { t.Errorf("Proxy copy error: %v", err) return @@ -2321,6 +2686,7 @@ func TestTransportAndServerSharedBodyRace(t *testing.T) { })) defer proxy.Close() + defer close(unblockBackend) req, _ := NewRequest("POST", proxy.URL, io.LimitReader(neverEnding('a'), bodySize)) res, err := DefaultClient.Do(req) if err != nil { @@ -2329,8 +2695,12 @@ func TestTransportAndServerSharedBodyRace(t *testing.T) { // Cleanup, so we don't leak goroutines. res.Body.Close() - close(unblockBackend) - (<-backendRespc).Body.Close() + select { + case res := <-backendRespc: + res.Body.Close() + default: + // We failed earlier. (e.g. on DefaultClient.Do(req2)) + } } // Test that a hanging Request.Body.Read from another goroutine can't @@ -2384,19 +2754,24 @@ func TestRequestBodyCloseDoesntBlock(t *testing.T) { } } -func TestResponseWriterWriteStringAllocs(t *testing.T) { - t.Skip("allocs test unreliable with gccgo") +// test that ResponseWriter implements io.stringWriter. +func TestResponseWriterWriteString(t *testing.T) { + okc := make(chan bool, 1) ht := newHandlerTest(HandlerFunc(func(w ResponseWriter, r *Request) { - if r.URL.Path == "/s" { - io.WriteString(w, "Hello world") - } else { - w.Write([]byte("Hello world")) + type stringWriter interface { + WriteString(s string) (n int, err error) } + _, ok := w.(stringWriter) + okc <- ok })) - before := testing.AllocsPerRun(50, func() { ht.rawResponse("GET / HTTP/1.0") }) - after := testing.AllocsPerRun(50, func() { ht.rawResponse("GET /s HTTP/1.0") }) - if int(after) >= int(before) { - t.Errorf("WriteString allocs of %v >= Write allocs of %v", after, before) + ht.rawResponse("GET / HTTP/1.0") + select { + case ok := <-okc: + if !ok { + t.Error("ResponseWriter did not implement io.stringWriter") + } + default: + t.Error("handler was never called") } } @@ -2757,6 +3132,134 @@ func TestServerKeepAliveAfterWriteError(t *testing.T) { } } +// Issue 9987: shouldn't add automatic Content-Length (or +// Content-Type) if a Transfer-Encoding was set by the handler. +func TestNoContentLengthIfTransferEncoding(t *testing.T) { + defer afterTest(t) + ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { + w.Header().Set("Transfer-Encoding", "foo") + io.WriteString(w, "") + })) + defer ts.Close() + c, err := net.Dial("tcp", ts.Listener.Addr().String()) + if err != nil { + t.Fatalf("Dial: %v", err) + } + defer c.Close() + if _, err := io.WriteString(c, "GET / HTTP/1.1\r\nHost: foo\r\n\r\n"); err != nil { + t.Fatal(err) + } + bs := bufio.NewScanner(c) + var got bytes.Buffer + for bs.Scan() { + if strings.TrimSpace(bs.Text()) == "" { + break + } + got.WriteString(bs.Text()) + got.WriteByte('\n') + } + if err := bs.Err(); err != nil { + t.Fatal(err) + } + if strings.Contains(got.String(), "Content-Length") { + t.Errorf("Unexpected Content-Length in response headers: %s", got.String()) + } + if strings.Contains(got.String(), "Content-Type") { + t.Errorf("Unexpected Content-Type in response headers: %s", got.String()) + } +} + +// tolerate extra CRLF(s) before Request-Line on subsequent requests on a conn +// Issue 10876. +func TestTolerateCRLFBeforeRequestLine(t *testing.T) { + req := []byte("POST / HTTP/1.1\r\nHost: golang.org\r\nContent-Length: 3\r\n\r\nABC" + + "\r\n\r\n" + // <-- this stuff is bogus, but we'll ignore it + "GET / HTTP/1.1\r\nHost: golang.org\r\n\r\n") + var buf bytes.Buffer + conn := &rwTestConn{ + Reader: bytes.NewReader(req), + Writer: &buf, + closec: make(chan bool, 1), + } + ln := &oneConnListener{conn: conn} + numReq := 0 + go Serve(ln, HandlerFunc(func(rw ResponseWriter, r *Request) { + numReq++ + })) + <-conn.closec + if numReq != 2 { + t.Errorf("num requests = %d; want 2", numReq) + t.Logf("Res: %s", buf.Bytes()) + } +} + +func TestIssue11549_Expect100(t *testing.T) { + req := reqBytes(`PUT /readbody HTTP/1.1 +User-Agent: PycURL/7.22.0 +Host: 127.0.0.1:9000 +Accept: */* +Expect: 100-continue +Content-Length: 10 + +HelloWorldPUT /noreadbody HTTP/1.1 +User-Agent: PycURL/7.22.0 +Host: 127.0.0.1:9000 +Accept: */* +Expect: 100-continue +Content-Length: 10 + +GET /should-be-ignored HTTP/1.1 +Host: foo + +`) + var buf bytes.Buffer + conn := &rwTestConn{ + Reader: bytes.NewReader(req), + Writer: &buf, + closec: make(chan bool, 1), + } + ln := &oneConnListener{conn: conn} + numReq := 0 + go Serve(ln, HandlerFunc(func(w ResponseWriter, r *Request) { + numReq++ + if r.URL.Path == "/readbody" { + ioutil.ReadAll(r.Body) + } + io.WriteString(w, "Hello world!") + })) + <-conn.closec + if numReq != 2 { + t.Errorf("num requests = %d; want 2", numReq) + } + if !strings.Contains(buf.String(), "Connection: close\r\n") { + t.Errorf("expected 'Connection: close' in response; got: %s", buf.String()) + } +} + +// If a Handler finishes and there's an unread request body, +// verify the server try to do implicit read on it before replying. +func TestHandlerFinishSkipBigContentLengthRead(t *testing.T) { + conn := &testConn{closec: make(chan bool)} + conn.readBuf.Write([]byte(fmt.Sprintf( + "POST / HTTP/1.1\r\n" + + "Host: test\r\n" + + "Content-Length: 9999999999\r\n" + + "\r\n" + strings.Repeat("a", 1<<20)))) + + ls := &oneConnListener{conn} + var inHandlerLen int + go Serve(ls, HandlerFunc(func(rw ResponseWriter, req *Request) { + inHandlerLen = conn.readBuf.Len() + rw.WriteHeader(404) + })) + <-conn.closec + afterHandlerLen := conn.readBuf.Len() + + if afterHandlerLen != inHandlerLen { + t.Errorf("unexpected implicit read. Read buffer went from %d -> %d", inHandlerLen, afterHandlerLen) + } +} + func BenchmarkClientServer(b *testing.B) { b.ReportAllocs() b.StopTimer() @@ -2886,7 +3389,7 @@ func BenchmarkServer(b *testing.B) { defer ts.Close() b.StartTimer() - cmd := exec.Command(os.Args[0], "-test.run=XXXX", "-test.bench=BenchmarkServer") + cmd := exec.Command(os.Args[0], "-test.run=XXXX", "-test.bench=BenchmarkServer$") cmd.Env = append([]string{ fmt.Sprintf("TEST_BENCH_CLIENT_N=%d", b.N), fmt.Sprintf("TEST_BENCH_SERVER_URL=%s", ts.URL), @@ -2897,6 +3400,95 @@ func BenchmarkServer(b *testing.B) { } } +// getNoBody wraps Get but closes any Response.Body before returning the response. +func getNoBody(urlStr string) (*Response, error) { + res, err := Get(urlStr) + if err != nil { + return nil, err + } + res.Body.Close() + return res, nil +} + +// A benchmark for profiling the client without the HTTP server code. +// The server code runs in a subprocess. +func BenchmarkClient(b *testing.B) { + b.ReportAllocs() + b.StopTimer() + defer afterTest(b) + + port := os.Getenv("TEST_BENCH_SERVER_PORT") // can be set by user + if port == "" { + port = "39207" + } + var data = []byte("Hello world.\n") + if server := os.Getenv("TEST_BENCH_SERVER"); server != "" { + // Server process mode. + HandleFunc("/", func(w ResponseWriter, r *Request) { + r.ParseForm() + if r.Form.Get("stop") != "" { + os.Exit(0) + } + w.Header().Set("Content-Type", "text/html; charset=utf-8") + w.Write(data) + }) + log.Fatal(ListenAndServe("localhost:"+port, nil)) + } + + // Start server process. + cmd := exec.Command(os.Args[0], "-test.run=XXXX", "-test.bench=BenchmarkClient$") + cmd.Env = append(os.Environ(), "TEST_BENCH_SERVER=yes") + if err := cmd.Start(); err != nil { + b.Fatalf("subprocess failed to start: %v", err) + } + defer cmd.Process.Kill() + done := make(chan error) + go func() { + done <- cmd.Wait() + }() + + // Wait for the server process to respond. + url := "http://localhost:" + port + "/" + for i := 0; i < 100; i++ { + time.Sleep(50 * time.Millisecond) + if _, err := getNoBody(url); err == nil { + break + } + if i == 99 { + b.Fatalf("subprocess does not respond") + } + } + + // Do b.N requests to the server. + b.StartTimer() + for i := 0; i < b.N; i++ { + res, err := Get(url) + if err != nil { + b.Fatalf("Get: %v", err) + } + body, err := ioutil.ReadAll(res.Body) + res.Body.Close() + if err != nil { + b.Fatalf("ReadAll: %v", err) + } + if bytes.Compare(body, data) != 0 { + b.Fatalf("Got body: %q", body) + } + } + b.StopTimer() + + // Instruct server process to stop. + getNoBody(url + "?stop=yes") + select { + case err := <-done: + if err != nil { + b.Fatalf("subprocess failed: %v", err) + } + case <-time.After(5 * time.Second): + b.Fatalf("subprocess did not stop") + } +} + func BenchmarkServerFakeConnNoKeepAlive(b *testing.B) { b.ReportAllocs() req := reqBytes(`GET / HTTP/1.0 diff --git a/libgo/go/net/http/server.go b/libgo/go/net/http/server.go index 008d5aa7a74..a3e43555bb3 100644 --- a/libgo/go/net/http/server.go +++ b/libgo/go/net/http/server.go @@ -15,6 +15,7 @@ import ( "io/ioutil" "log" "net" + "net/textproto" "net/url" "os" "path" @@ -55,9 +56,12 @@ type Handler interface { // A ResponseWriter interface is used by an HTTP handler to // construct an HTTP response. type ResponseWriter interface { - // Header returns the header map that will be sent by WriteHeader. - // Changing the header after a call to WriteHeader (or Write) has - // no effect. + // Header returns the header map that will be sent by + // WriteHeader. Changing the header after a call to + // WriteHeader (or Write) has no effect unless the modified + // headers were declared as trailers by setting the + // "Trailer" header before the call to WriteHeader (see example). + // To suppress implicit response headers, set their value to nil. Header() Header // Write writes the data to the connection as part of an HTTP reply. @@ -93,8 +97,14 @@ type Hijacker interface { // Hijack lets the caller take over the connection. // After a call to Hijack(), the HTTP server library // will not do anything else with the connection. + // // It becomes the caller's responsibility to manage // and close the connection. + // + // The returned net.Conn may have read or write deadlines + // already set, depending on the configuration of the + // Server. It is the caller's responsibility to set + // or clear those deadlines as needed. Hijack() (net.Conn, *bufio.ReadWriter, error) } @@ -120,6 +130,7 @@ type conn struct { lr *io.LimitedReader // io.LimitReader(sr) buf *bufio.ReadWriter // buffered(lr,rwc), reading from bufio->limitReader->sr->rwc tlsState *tls.ConnectionState // or nil when not using TLS + lastMethod string // method of previous request, or "" mu sync.Mutex // guards the following clientGone bool // if client has disconnected mid-request @@ -188,20 +199,14 @@ func (c *conn) noteClientGone() { c.clientGone = true } -// A switchReader can have its Reader changed at runtime. -// It's not safe for concurrent Reads and switches. -type switchReader struct { - io.Reader -} - // A switchWriter can have its Writer changed at runtime. // It's not safe for concurrent Writes and switches. type switchWriter struct { io.Writer } -// A liveSwitchReader is a switchReader that's safe for concurrent -// reads and switches, if its mutex is held. +// A liveSwitchReader can have its Reader changed at runtime. It's +// safe for concurrent reads and switches, if its mutex is held. type liveSwitchReader struct { sync.Mutex r io.Reader @@ -288,10 +293,21 @@ func (cw *chunkWriter) close() { cw.writeHeader(nil) } if cw.chunking { - // zero EOF chunk, trailer key/value pairs (currently - // unsupported in Go's server), followed by a blank - // line. - cw.res.conn.buf.WriteString("0\r\n\r\n") + bw := cw.res.conn.buf // conn's bufio writer + // zero chunk to mark EOF + bw.WriteString("0\r\n") + if len(cw.res.trailers) > 0 { + trailers := make(Header) + for _, h := range cw.res.trailers { + if vv := cw.res.handlerHeader[h]; len(vv) > 0 { + trailers[h] = vv + } + } + trailers.Write(bw) // the writer handles noting errors + } + // final blank line after the trailers (whether + // present or not) + bw.WriteString("\r\n") } } @@ -332,6 +348,12 @@ type response struct { // input from it. requestBodyLimitHit bool + // trailers are the headers to be sent after the handler + // finishes writing the body. This field is initialized from + // the Trailer response header when the response header is + // written. + trailers []string + handlerDone bool // set true when the handler exits // Buffers for Date and Content-Length @@ -339,6 +361,19 @@ type response struct { clenBuf [10]byte } +// declareTrailer is called for each Trailer header when the +// response header is written. It notes that a header will need to be +// written in the trailers at the end of the response. +func (w *response) declareTrailer(k string) { + k = CanonicalHeaderKey(k) + switch k { + case "Transfer-Encoding", "Content-Length", "Trailer": + // Forbidden by RFC 2616 14.40. + return + } + w.trailers = append(w.trailers, k) +} + // requestTooLarge is called by maxBytesReader when too much input has // been read from the client. func (w *response) requestTooLarge() { @@ -438,7 +473,7 @@ func (srv *Server) newConn(rwc net.Conn) (c *conn, err error) { if debugServerConnections { c.rwc = newLoggingConn("server", c.rwc) } - c.sr = liveSwitchReader{r: c.rwc} + c.sr.r = c.rwc c.lr = io.LimitReader(&c.sr, noLimit).(*io.LimitedReader) br := newBufioReader(c.lr) bw := newBufioWriterSize(checkConnErrorWriter{c}, 4<<10) @@ -468,6 +503,8 @@ func newBufioReader(r io.Reader) *bufio.Reader { br.Reset(r) return br } + // Note: if this reader size is every changed, update + // TestHandlerBodyClose's assumptions. return bufio.NewReader(r) } @@ -517,6 +554,7 @@ type expectContinueReader struct { resp *response readCloser io.ReadCloser closed bool + sawEOF bool } func (ecr *expectContinueReader) Read(p []byte) (n int, err error) { @@ -528,7 +566,11 @@ func (ecr *expectContinueReader) Read(p []byte) (n int, err error) { ecr.resp.conn.buf.WriteString("HTTP/1.1 100 Continue\r\n\r\n") ecr.resp.conn.buf.Flush() } - return ecr.readCloser.Read(p) + n, err = ecr.readCloser.Read(p) + if err == io.EOF { + ecr.sawEOF = true + } + return } func (ecr *expectContinueReader) Close() error { @@ -582,6 +624,11 @@ func (c *conn) readRequest() (w *response, err error) { } c.lr.N = c.server.initialLimitedReaderSize() + if c.lastMethod == "POST" { + // RFC 2616 section 4.1 tolerance for old buggy clients. + peek, _ := c.buf.Reader.Peek(4) // ReadRequest will get err below + c.buf.Reader.Discard(numLeadingCRorLF(peek)) + } var req *Request if req, err = ReadRequest(c.buf.Reader); err != nil { if c.lr.N == 0 { @@ -590,9 +637,13 @@ func (c *conn) readRequest() (w *response, err error) { return nil, err } c.lr.N = noLimit + c.lastMethod = req.Method req.RemoteAddr = c.remoteAddr req.TLS = c.tlsState + if body, ok := req.Body.(*body); ok { + body.doEarlyClose = true + } w = &response{ conn: c, @@ -747,6 +798,15 @@ func (cw *chunkWriter) writeHeader(p []byte) { } var setHeader extraHeader + trailers := false + for _, v := range cw.header["Trailer"] { + trailers = true + foreachHeaderElement(v, cw.res.declareTrailer) + } + + te := header.get("Transfer-Encoding") + hasTE := te != "" + // If the handler is done but never sent a Content-Length // response header and this is our first (and last) write, set // it, even to zero. This helps HTTP/1.0 clients keep their @@ -759,7 +819,9 @@ func (cw *chunkWriter) writeHeader(p []byte) { // write non-zero bytes. If it's actually 0 bytes and the // handler never looked at the Request.Method, we just don't // send a Content-Length header. - if w.handlerDone && bodyAllowedForStatus(w.status) && header.get("Content-Length") == "" && (!isHEAD || len(p) > 0) { + // Further, we don't send an automatic Content-Length if they + // set a Transfer-Encoding, because they're generally incompatible. + if w.handlerDone && !trailers && !hasTE && bodyAllowedForStatus(w.status) && header.get("Content-Length") == "" && (!isHEAD || len(p) > 0) { w.contentLength = int64(len(p)) setHeader.contentLength = strconv.AppendInt(cw.res.clenBuf[:0], int64(len(p)), 10) } @@ -789,21 +851,78 @@ func (cw *chunkWriter) writeHeader(p []byte) { w.closeAfterReply = true } + // If the client wanted a 100-continue but we never sent it to + // them (or, more strictly: we never finished reading their + // request body), don't reuse this connection because it's now + // in an unknown state: we might be sending this response at + // the same time the client is now sending its request body + // after a timeout. (Some HTTP clients send Expect: + // 100-continue but knowing that some servers don't support + // it, the clients set a timer and send the body later anyway) + // If we haven't seen EOF, we can't skip over the unread body + // because we don't know if the next bytes on the wire will be + // the body-following-the-timer or the subsequent request. + // See Issue 11549. + if ecr, ok := w.req.Body.(*expectContinueReader); ok && !ecr.sawEOF { + w.closeAfterReply = true + } + // Per RFC 2616, we should consume the request body before // replying, if the handler hasn't already done so. But we // don't want to do an unbounded amount of reading here for // DoS reasons, so we only try up to a threshold. if w.req.ContentLength != 0 && !w.closeAfterReply { - ecr, isExpecter := w.req.Body.(*expectContinueReader) - if !isExpecter || ecr.resp.wroteContinue { - n, _ := io.CopyN(ioutil.Discard, w.req.Body, maxPostHandlerReadBytes+1) - if n >= maxPostHandlerReadBytes { - w.requestTooLarge() - delHeader("Connection") - setHeader.connection = "close" - } else { - w.req.Body.Close() + var discard, tooBig bool + + switch bdy := w.req.Body.(type) { + case *expectContinueReader: + if bdy.resp.wroteContinue { + discard = true + } + case *body: + bdy.mu.Lock() + switch { + case bdy.closed: + if !bdy.sawEOF { + // Body was closed in handler with non-EOF error. + w.closeAfterReply = true + } + case bdy.unreadDataSizeLocked() >= maxPostHandlerReadBytes: + tooBig = true + default: + discard = true } + bdy.mu.Unlock() + default: + discard = true + } + + if discard { + _, err := io.CopyN(ioutil.Discard, w.req.Body, maxPostHandlerReadBytes+1) + switch err { + case nil: + // There must be even more data left over. + tooBig = true + case ErrBodyReadAfterClose: + // Body was already consumed and closed. + case io.EOF: + // The remaining body was just consumed, close it. + err = w.req.Body.Close() + if err != nil { + w.closeAfterReply = true + } + default: + // Some other kind of error occured, like a read timeout, or + // corrupt chunked encoding. In any case, whatever remains + // on the wire must not be parsed as another HTTP request. + w.closeAfterReply = true + } + } + + if tooBig { + w.requestTooLarge() + delHeader("Connection") + setHeader.connection = "close" } } @@ -811,7 +930,7 @@ func (cw *chunkWriter) writeHeader(p []byte) { if bodyAllowedForStatus(code) { // If no content type, apply sniffing algorithm to body. _, haveType := header["Content-Type"] - if !haveType { + if !haveType && !hasTE { setHeader.contentType = DetectContentType(p) } } else { @@ -824,8 +943,6 @@ func (cw *chunkWriter) writeHeader(p []byte) { setHeader.date = appendTime(cw.res.dateBuf[:0], time.Now()) } - te := header.get("Transfer-Encoding") - hasTE := te != "" if hasCL && hasTE && te != "identity" { // TODO: return an error if WriteHeader gets a return parameter // For now just ignore the Content-Length. @@ -885,6 +1002,24 @@ func (cw *chunkWriter) writeHeader(p []byte) { w.conn.buf.Write(crlf) } +// foreachHeaderElement splits v according to the "#rule" construction +// in RFC 2616 section 2.1 and calls fn for each non-empty element. +func foreachHeaderElement(v string, fn func(string)) { + v = textproto.TrimString(v) + if v == "" { + return + } + if !strings.Contains(v, ",") { + fn(v) + return + } + for _, f := range strings.Split(v, ",") { + if f = textproto.TrimString(f); f != "" { + fn(f) + } + } +} + // statusLines is a cache of Status-Line strings, keyed by code (for // HTTP/1.1) or negative code (for HTTP/1.0). This is faster than a // map keyed by struct of two fields. This map's max size is bounded @@ -930,7 +1065,7 @@ func statusLine(req *Request, code int) string { return line } -// bodyAllowed returns true if a Write is allowed for this response type. +// bodyAllowed reports whether a Write is allowed for this response type. // It's illegal to call this before the header has been flushed. func (w *response) bodyAllowed() bool { if !w.wroteHeader { @@ -1027,17 +1162,39 @@ func (w *response) finishRequest() { if w.req.MultipartForm != nil { w.req.MultipartForm.RemoveAll() } +} + +// shouldReuseConnection reports whether the underlying TCP connection can be reused. +// It must only be called after the handler is done executing. +func (w *response) shouldReuseConnection() bool { + if w.closeAfterReply { + // The request or something set while executing the + // handler indicated we shouldn't reuse this + // connection. + return false + } if w.req.Method != "HEAD" && w.contentLength != -1 && w.bodyAllowed() && w.contentLength != w.written { // Did not write enough. Avoid getting out of sync. - w.closeAfterReply = true + return false } // There was some error writing to the underlying connection // during the request, so don't re-use this conn. if w.conn.werr != nil { - w.closeAfterReply = true + return false } + + if w.closedRequestBodyEarly() { + return false + } + + return true +} + +func (w *response) closedRequestBodyEarly() bool { + body, ok := w.req.Body.(*body) + return ok && body.didEarlyClose() } func (w *response) Flush() { @@ -1093,7 +1250,7 @@ var _ closeWriter = (*net.TCPConn)(nil) // pause for a bit, hoping the client processes it before any // subsequent RST. // -// See http://golang.org/issue/3595 +// See https://golang.org/issue/3595 func (c *conn) closeWriteAndWait() { c.finalFlush() if tcp, ok := c.rwc.(closeWriter); ok { @@ -1206,8 +1363,8 @@ func (c *conn) serve() { return } w.finishRequest() - if w.closeAfterReply { - if w.requestBodyLimitHit { + if !w.shouldReuseConnection() { + if w.requestBodyLimitHit || w.closedRequestBodyEarly() { c.closeWriteAndWait() } break @@ -1271,6 +1428,7 @@ func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) { // The error message should be plain text. func Error(w ResponseWriter, error string, code int) { w.Header().Set("Content-Type", "text/plain; charset=utf-8") + w.Header().Set("X-Content-Type-Options", "nosniff") w.WriteHeader(code) fmt.Fprintln(w, error) } @@ -1576,7 +1734,8 @@ func (mux *ServeMux) Handle(pattern string, handler Handler) { // strings.Index can't be -1. path = pattern[strings.Index(pattern, "/"):] } - mux.m[pattern[0:n-1]] = muxEntry{h: RedirectHandler(path, StatusMovedPermanently), pattern: pattern} + url := &url.URL{Path: path} + mux.m[pattern[0:n-1]] = muxEntry{h: RedirectHandler(url.String(), StatusMovedPermanently), pattern: pattern} } } @@ -1760,11 +1919,11 @@ func (s *Server) doKeepAlives() bool { // By default, keep-alives are always enabled. Only very // resource-constrained environments or servers in the process of // shutting down should disable them. -func (s *Server) SetKeepAlivesEnabled(v bool) { +func (srv *Server) SetKeepAlivesEnabled(v bool) { if v { - atomic.StoreInt32(&s.disableKeepAlives, 0) + atomic.StoreInt32(&srv.disableKeepAlives, 0) } else { - atomic.StoreInt32(&s.disableKeepAlives, 1) + atomic.StoreInt32(&srv.disableKeepAlives, 1) } } @@ -1812,7 +1971,7 @@ func ListenAndServe(addr string, handler Handler) error { // expects HTTPS connections. Additionally, files containing a certificate and // matching private key for the server must be provided. If the certificate // is signed by a certificate authority, the certFile should be the concatenation -// of the server's certificate followed by the CA's certificate. +// of the server's certificate, any intermediates, and the CA's certificate. // // A trivial example server is: // @@ -1844,10 +2003,11 @@ func ListenAndServeTLS(addr string, certFile string, keyFile string, handler Han // ListenAndServeTLS listens on the TCP network address srv.Addr and // then calls Serve to handle requests on incoming TLS connections. // -// Filenames containing a certificate and matching private key for -// the server must be provided. If the certificate is signed by a -// certificate authority, the certFile should be the concatenation -// of the server's certificate followed by the CA's certificate. +// Filenames containing a certificate and matching private key for the +// server must be provided if the Server's TLSConfig.Certificates is +// not populated. If the certificate is signed by a certificate +// authority, the certFile should be the concatenation of the server's +// certificate, any intermediates, and the CA's certificate. // // If srv.Addr is blank, ":https" is used. func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error { @@ -1855,19 +2015,18 @@ func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error { if addr == "" { addr = ":https" } - config := &tls.Config{} - if srv.TLSConfig != nil { - *config = *srv.TLSConfig - } + config := cloneTLSConfig(srv.TLSConfig) if config.NextProtos == nil { config.NextProtos = []string{"http/1.1"} } - var err error - config.Certificates = make([]tls.Certificate, 1) - config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile) - if err != nil { - return err + if len(config.Certificates) == 0 || certFile != "" || keyFile != "" { + var err error + config.Certificates = make([]tls.Certificate, 1) + config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile) + if err != nil { + return err + } } ln, err := net.Listen("tcp", addr) @@ -2094,3 +2253,15 @@ func (w checkConnErrorWriter) Write(p []byte) (n int, err error) { } return } + +func numLeadingCRorLF(v []byte) (n int) { + for _, b := range v { + if b == '\r' || b == '\n' { + n++ + continue + } + break + } + return + +} diff --git a/libgo/go/net/http/sniff.go b/libgo/go/net/http/sniff.go index 68f519b0542..3be8c865d3b 100644 --- a/libgo/go/net/http/sniff.go +++ b/libgo/go/net/http/sniff.go @@ -38,7 +38,11 @@ func DetectContentType(data []byte) string { } func isWS(b byte) bool { - return bytes.IndexByte([]byte("\t\n\x0C\r "), b) != -1 + switch b { + case '\t', '\n', '\x0c', '\r', ' ': + return true + } + return false } type sniffSig interface { @@ -161,6 +165,8 @@ func (h htmlSig) match(data []byte, firstNonWS int) string { return "text/html; charset=utf-8" } +var mp4ftype = []byte("ftyp") + type mp4Sig int func (mp4Sig) match(data []byte, firstNonWS int) string { @@ -172,7 +178,7 @@ func (mp4Sig) match(data []byte, firstNonWS int) string { if boxSize%4 != 0 || len(data) < boxSize { return "" } - if !bytes.Equal(data[4:8], []byte("ftyp")) { + if !bytes.Equal(data[4:8], mp4ftype) { return "" } for st := 8; st < boxSize; st += 4 { diff --git a/libgo/go/net/http/transfer.go b/libgo/go/net/http/transfer.go index 520500330bc..a8736b28e16 100644 --- a/libgo/go/net/http/transfer.go +++ b/libgo/go/net/http/transfer.go @@ -27,7 +27,7 @@ type errorReader struct { err error } -func (r *errorReader) Read(p []byte) (n int, err error) { +func (r errorReader) Read(p []byte) (n int, err error) { return 0, r.err } @@ -43,6 +43,7 @@ type transferWriter struct { Close bool TransferEncoding []string Trailer Header + IsResponse bool } func newTransferWriter(r interface{}) (t *transferWriter, err error) { @@ -70,7 +71,7 @@ func newTransferWriter(r interface{}) (t *transferWriter, err error) { n, rerr := io.ReadFull(t.Body, buf[:]) if rerr != nil && rerr != io.EOF { t.ContentLength = -1 - t.Body = &errorReader{rerr} + t.Body = errorReader{rerr} } else if n == 1 { // Oh, guess there is data in this Body Reader after all. // The ContentLength field just wasn't set. @@ -89,6 +90,7 @@ func newTransferWriter(r interface{}) (t *transferWriter, err error) { } } case *Response: + t.IsResponse = true if rr.Request != nil { t.Method = rr.Request.Method } @@ -138,11 +140,17 @@ func (t *transferWriter) shouldSendContentLength() bool { if t.ContentLength > 0 { return true } + if t.ContentLength < 0 { + return false + } // Many servers expect a Content-Length for these methods if t.Method == "POST" || t.Method == "PUT" { return true } if t.ContentLength == 0 && isIdentity(t.TransferEncoding) { + if t.Method == "GET" || t.Method == "HEAD" { + return false + } return true } @@ -203,6 +211,9 @@ func (t *transferWriter) WriteBody(w io.Writer) error { // Write body if t.Body != nil { if chunked(t.TransferEncoding) { + if bw, ok := w.(*bufio.Writer); ok && !t.IsResponse { + w = &internal.FlushAfterChunkWriter{bw} + } cw := internal.NewChunkedWriter(w) _, err = io.Copy(cw, t.Body) if err == nil { @@ -232,7 +243,6 @@ func (t *transferWriter) WriteBody(w io.Writer) error { t.ContentLength, ncopy) } - // TODO(petar): Place trailer writer code here. if chunked(t.TransferEncoding) { // Write Trailer header if t.Trailer != nil { @@ -310,11 +320,13 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err error) { } case *Request: t.Header = rr.Header + t.RequestMethod = rr.Method t.ProtoMajor = rr.ProtoMajor t.ProtoMinor = rr.ProtoMinor // Transfer semantics for Requests are exactly like those for // Responses with status code 200, responding to a GET method t.StatusCode = 200 + t.Close = rr.Close default: panic("unexpected type") } @@ -325,7 +337,7 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err error) { } // Transfer encoding, content length - t.TransferEncoding, err = fixTransferEncoding(t.RequestMethod, t.Header) + t.TransferEncoding, err = fixTransferEncoding(isResponse, t.RequestMethod, t.Header) if err != nil { return err } @@ -413,12 +425,11 @@ func chunked(te []string) bool { return len(te) > 0 && te[0] == "chunked" } func isIdentity(te []string) bool { return len(te) == 1 && te[0] == "identity" } // Sanitize transfer encoding -func fixTransferEncoding(requestMethod string, header Header) ([]string, error) { +func fixTransferEncoding(isResponse bool, requestMethod string, header Header) ([]string, error) { raw, present := header["Transfer-Encoding"] if !present { return nil, nil } - delete(header, "Transfer-Encoding") encodings := strings.Split(raw[0], ",") @@ -443,9 +454,22 @@ func fixTransferEncoding(requestMethod string, header Header) ([]string, error) return nil, &badStringError{"too many transfer encodings", strings.Join(te, ",")} } if len(te) > 0 { - // Chunked encoding trumps Content-Length. See RFC 2616 - // Section 4.4. Currently len(te) > 0 implies chunked - // encoding. + // RFC 7230 3.3.2 says "A sender MUST NOT send a + // Content-Length header field in any message that + // contains a Transfer-Encoding header field." + // + // but also: + // "If a message is received with both a + // Transfer-Encoding and a Content-Length header + // field, the Transfer-Encoding overrides the + // Content-Length. Such a message might indicate an + // attempt to perform request smuggling (Section 9.5) + // or response splitting (Section 9.4) and ought to be + // handled as an error. A sender MUST remove the + // received Content-Length field prior to forwarding + // such a message downstream." + // + // Reportedly, these appear in the wild. delete(header, "Content-Length") return te, nil } @@ -457,9 +481,17 @@ func fixTransferEncoding(requestMethod string, header Header) ([]string, error) // function is not a method, because ultimately it should be shared by // ReadResponse and ReadRequest. func fixLength(isResponse bool, status int, requestMethod string, header Header, te []string) (int64, error) { - + contentLens := header["Content-Length"] + isRequest := !isResponse // Logic based on response type or status if noBodyExpected(requestMethod) { + // For HTTP requests, as part of hardening against request + // smuggling (RFC 7230), don't allow a Content-Length header for + // methods which don't permit bodies. As an exception, allow + // exactly one Content-Length header if its value is "0". + if isRequest && len(contentLens) > 0 && !(len(contentLens) == 1 && contentLens[0] == "0") { + return 0, fmt.Errorf("http: method cannot contain a Content-Length; got %q", contentLens) + } return 0, nil } if status/100 == 1 { @@ -470,13 +502,21 @@ func fixLength(isResponse bool, status int, requestMethod string, header Header, return 0, nil } + if len(contentLens) > 1 { + // harden against HTTP request smuggling. See RFC 7230. + return 0, errors.New("http: message cannot contain multiple Content-Length headers") + } + // Logic based on Transfer-Encoding if chunked(te) { return -1, nil } // Logic based on Content-Length - cl := strings.TrimSpace(header.get("Content-Length")) + var cl string + if len(contentLens) == 1 { + cl = strings.TrimSpace(contentLens[0]) + } if cl != "" { n, err := parseContentLength(cl) if err != nil { @@ -487,11 +527,14 @@ func fixLength(isResponse bool, status int, requestMethod string, header Header, header.Del("Content-Length") } - if !isResponse && requestMethod == "GET" { - // RFC 2616 doesn't explicitly permit nor forbid an + if !isResponse { + // RFC 2616 neither explicitly permits nor forbids an // entity-body on a GET request so we permit one if // declared, but we default to 0 here (not -1 below) // if there's no mention of a body. + // Likewise, all other request methods are assumed to have + // no body if neither Transfer-Encoding chunked nor a + // Content-Length are set. return 0, nil } @@ -506,14 +549,13 @@ func shouldClose(major, minor int, header Header, removeCloseHeader bool) bool { if major < 1 { return true } else if major == 1 && minor == 0 { - if !strings.Contains(strings.ToLower(header.get("Connection")), "keep-alive") { + vv := header["Connection"] + if headerValuesContainsToken(vv, "close") || !headerValuesContainsToken(vv, "keep-alive") { return true } return false } else { - // TODO: Should split on commas, toss surrounding white space, - // and check each field. - if strings.ToLower(header.get("Connection")) == "close" { + if headerValuesContainsToken(header["Connection"], "close") { if removeCloseHeader { header.Del("Connection") } @@ -555,13 +597,16 @@ func fixTrailer(header Header, te []string) (Header, error) { // Close ensures that the body has been fully read // and then reads the trailer if necessary. type body struct { - src io.Reader - hdr interface{} // non-nil (Response or Request) value means read trailer - r *bufio.Reader // underlying wire-format reader for the trailer - closing bool // is the connection to be closed after reading body? - - mu sync.Mutex // guards closed, and calls to Read and Close - closed bool + src io.Reader + hdr interface{} // non-nil (Response or Request) value means read trailer + r *bufio.Reader // underlying wire-format reader for the trailer + closing bool // is the connection to be closed after reading body? + doEarlyClose bool // whether Close should stop early + + mu sync.Mutex // guards closed, and calls to Read and Close + sawEOF bool + closed bool + earlyClose bool // Close called and we didn't read to the end of src } // ErrBodyReadAfterClose is returned when reading a Request or Response @@ -581,13 +626,23 @@ func (b *body) Read(p []byte) (n int, err error) { // Must hold b.mu. func (b *body) readLocked(p []byte) (n int, err error) { + if b.sawEOF { + return 0, io.EOF + } n, err = b.src.Read(p) if err == io.EOF { + b.sawEOF = true // Chunked case. Read the trailer. if b.hdr != nil { if e := b.readTrailer(); e != nil { err = e + // Something went wrong in the trailer, we must not allow any + // further reads of any kind to succeed from body, nor any + // subsequent requests on the server connection. See + // golang.org/issue/12027 + b.sawEOF = false + b.closed = true } b.hdr = nil } else { @@ -607,6 +662,7 @@ func (b *body) readLocked(p []byte) (n int, err error) { if err == nil && n > 0 { if lr, ok := b.src.(*io.LimitedReader); ok && lr.N == 0 { err = io.EOF + b.sawEOF = true } } @@ -639,8 +695,7 @@ func (b *body) readTrailer() error { // The common case, since nobody uses trailers. buf, err := b.r.Peek(2) if bytes.Equal(buf, singleCRLF) { - b.r.ReadByte() - b.r.ReadByte() + b.r.Discard(2) return nil } if len(buf) < 2 { @@ -688,6 +743,16 @@ func mergeSetHeader(dst *Header, src Header) { } } +// unreadDataSizeLocked returns the number of bytes of unread input. +// It returns -1 if unknown. +// b.mu must be held. +func (b *body) unreadDataSizeLocked() int64 { + if lr, ok := b.src.(*io.LimitedReader); ok { + return lr.N + } + return -1 +} + func (b *body) Close() error { b.mu.Lock() defer b.mu.Unlock() @@ -696,9 +761,30 @@ func (b *body) Close() error { } var err error switch { + case b.sawEOF: + // Already saw EOF, so no need going to look for it. case b.hdr == nil && b.closing: // no trailer and closing the connection next. // no point in reading to EOF. + case b.doEarlyClose: + // Read up to maxPostHandlerReadBytes bytes of the body, looking for + // for EOF (and trailers), so we can re-use this connection. + if lr, ok := b.src.(*io.LimitedReader); ok && lr.N > maxPostHandlerReadBytes { + // There was a declared Content-Length, and we have more bytes remaining + // than our maxPostHandlerReadBytes tolerance. So, give up. + b.earlyClose = true + } else { + var n int64 + // Consume the body, or, which will also lead to us reading + // the trailer headers after the body, if present. + n, err = io.CopyN(ioutil.Discard, bodyLocked{b}, maxPostHandlerReadBytes) + if err == io.EOF { + err = nil + } + if n == maxPostHandlerReadBytes { + b.earlyClose = true + } + } default: // Fully consume the body, which will also lead to us reading // the trailer headers after the body, if present. @@ -708,6 +794,12 @@ func (b *body) Close() error { return err } +func (b *body) didEarlyClose() bool { + b.mu.Lock() + defer b.mu.Unlock() + return b.earlyClose +} + // bodyLocked is a io.Reader reading from a *body when its mutex is // already held. type bodyLocked struct { diff --git a/libgo/go/net/http/transport.go b/libgo/go/net/http/transport.go index 782f7cd395b..70d18646059 100644 --- a/libgo/go/net/http/transport.go +++ b/libgo/go/net/http/transport.go @@ -274,11 +274,12 @@ func (t *Transport) CloseIdleConnections() { } } -// CancelRequest cancels an in-flight request by closing its -// connection. +// CancelRequest cancels an in-flight request by closing its connection. +// CancelRequest should only be called after RoundTrip has returned. func (t *Transport) CancelRequest(req *Request) { t.reqMu.Lock() cancel := t.reqCanceler[req] + delete(t.reqCanceler, req) t.reqMu.Unlock() if cancel != nil { cancel() @@ -474,6 +475,25 @@ func (t *Transport) setReqCanceler(r *Request, fn func()) { } } +// replaceReqCanceler replaces an existing cancel function. If there is no cancel function +// for the request, we don't set the function and return false. +// Since CancelRequest will clear the canceler, we can use the return value to detect if +// the request was canceled since the last setReqCancel call. +func (t *Transport) replaceReqCanceler(r *Request, fn func()) bool { + t.reqMu.Lock() + defer t.reqMu.Unlock() + _, ok := t.reqCanceler[r] + if !ok { + return false + } + if fn != nil { + t.reqCanceler[r] = fn + } else { + delete(t.reqCanceler, r) + } + return true +} + func (t *Transport) dial(network, addr string) (c net.Conn, err error) { if t.Dial != nil { return t.Dial(network, addr) @@ -490,6 +510,10 @@ var prePendingDial, postPendingDial func() // is ready to write requests to. func (t *Transport) getConn(req *Request, cm connectMethod) (*persistConn, error) { if pc := t.getIdleConn(cm); pc != nil { + // set request canceler to some non-nil function so we + // can detect whether it was cleared between now and when + // we enter roundTrip + t.setReqCanceler(req, func() {}) return pc, nil } @@ -499,6 +523,11 @@ func (t *Transport) getConn(req *Request, cm connectMethod) (*persistConn, error } dialc := make(chan dialRes) + // Copy these hooks so we don't race on the postPendingDial in + // the goroutine we launch. Issue 11136. + prePendingDial := prePendingDial + postPendingDial := postPendingDial + handlePendingDial := func() { if prePendingDial != nil { prePendingDial() @@ -534,6 +563,9 @@ func (t *Transport) getConn(req *Request, cm connectMethod) (*persistConn, error // when it finishes: handlePendingDial() return pc, nil + case <-req.Cancel: + handlePendingDial() + return nil, errors.New("net/http: request canceled while waiting for connection") case <-cancelc: handlePendingDial() return nil, errors.New("net/http: request canceled while waiting for connection") @@ -613,16 +645,9 @@ func (t *Transport) dialConn(cm connectMethod) (*persistConn, error) { if cm.targetScheme == "https" && !tlsDial { // Initiate TLS and check remote host name against certificate. - cfg := t.TLSClientConfig - if cfg == nil || cfg.ServerName == "" { - host := cm.tlsHost() - if cfg == nil { - cfg = &tls.Config{ServerName: host} - } else { - clone := *cfg // shallow clone - clone.ServerName = host - cfg = &clone - } + cfg := cloneTLSClientConfig(t.TLSClientConfig) + if cfg.ServerName == "" { + cfg.ServerName = cm.tlsHost() } plainConn := pconn.conn tlsConn := tls.Client(plainConn, cfg) @@ -662,7 +687,7 @@ func (t *Transport) dialConn(cm connectMethod) (*persistConn, error) { return pconn, nil } -// useProxy returns true if requests to addr should use a proxy, +// useProxy reports whether requests to addr should use a proxy, // according to the NO_PROXY or no_proxy environment variable. // addr is always a canonicalAddr with a host and port. func useProxy(addr string) bool { @@ -805,6 +830,7 @@ type persistConn struct { numExpectedResponses int closed bool // whether conn has been closed broken bool // an error has happened on this connection; marked broken so it's not reused. + canceled bool // whether this conn was broken due a CancelRequest // mutateHeaderFunc is an optional func to modify extra // headers on each outbound request before it's written. (the // original Request given to RoundTrip is not modified) @@ -819,25 +845,33 @@ func (pc *persistConn) isBroken() bool { return b } -func (pc *persistConn) cancelRequest() { - pc.conn.Close() +// isCanceled reports whether this connection was closed due to CancelRequest. +func (pc *persistConn) isCanceled() bool { + pc.lk.Lock() + defer pc.lk.Unlock() + return pc.canceled } -var remoteSideClosedFunc func(error) bool // or nil to use default - -func remoteSideClosed(err error) bool { - if err == io.EOF { - return true - } - if remoteSideClosedFunc != nil { - return remoteSideClosedFunc(err) - } - return false +func (pc *persistConn) cancelRequest() { + pc.lk.Lock() + defer pc.lk.Unlock() + pc.canceled = true + pc.closeLocked() } func (pc *persistConn) readLoop() { - alive := true + // eofc is used to block http.Handler goroutines reading from Response.Body + // at EOF until this goroutines has (potentially) added the connection + // back to the idle pool. + eofc := make(chan struct{}) + defer close(eofc) // unblock reader on errors + + // Read this once, before loop starts. (to avoid races in tests) + testHookMu.Lock() + testHookReadLoopBeforeNextRead := testHookReadLoopBeforeNextRead + testHookMu.Unlock() + alive := true for alive { pb, err := pc.br.Peek(1) @@ -895,49 +929,79 @@ func (pc *persistConn) readLoop() { alive = false } - var waitForBodyRead chan bool + var waitForBodyRead chan bool // channel is nil when there's no body if hasBody { waitForBodyRead = make(chan bool, 2) resp.Body.(*bodyEOFSignal).earlyCloseFn = func() error { - // Sending false here sets alive to - // false and closes the connection - // below. waitForBodyRead <- false return nil } - resp.Body.(*bodyEOFSignal).fn = func(err error) { - waitForBodyRead <- alive && - err == nil && - !pc.sawEOF && - pc.wroteRequest() && - pc.t.putIdleConn(pc) + resp.Body.(*bodyEOFSignal).fn = func(err error) error { + isEOF := err == io.EOF + waitForBodyRead <- isEOF + if isEOF { + <-eofc // see comment at top + } else if err != nil && pc.isCanceled() { + return errRequestCanceled + } + return err } + } else { + // Before send on rc.ch, as client might re-use the + // same *Request pointer, and we don't want to set this + // on t from this persistConn while the Transport + // potentially spins up a different persistConn for the + // caller's subsequent request. + pc.t.setReqCanceler(rc.req, nil) } - if alive && !hasBody { - alive = !pc.sawEOF && - pc.wroteRequest() && - pc.t.putIdleConn(pc) - } + pc.lk.Lock() + pc.numExpectedResponses-- + pc.lk.Unlock() + // The connection might be going away when we put the + // idleConn below. When that happens, we close the response channel to signal + // to roundTrip that the connection is gone. roundTrip waits for + // both closing and a response in a select, so it might choose + // the close channel, rather than the response. + // We send the response first so that roundTrip can check + // if there is a pending one with a non-blocking select + // on the response channel before erroring out. rc.ch <- responseAndError{resp, err} - // Wait for the just-returned response body to be fully consumed - // before we race and peek on the underlying bufio reader. - if waitForBodyRead != nil { + if hasBody { + // To avoid a race, wait for the just-returned + // response body to be fully consumed before peek on + // the underlying bufio reader. select { - case alive = <-waitForBodyRead: + case <-rc.req.Cancel: + alive = false + pc.t.CancelRequest(rc.req) + case bodyEOF := <-waitForBodyRead: + pc.t.setReqCanceler(rc.req, nil) // before pc might return to idle pool + alive = alive && + bodyEOF && + !pc.sawEOF && + pc.wroteRequest() && + pc.t.putIdleConn(pc) + if bodyEOF { + eofc <- struct{}{} + } case <-pc.closech: alive = false } + } else { + alive = alive && + !pc.sawEOF && + pc.wroteRequest() && + pc.t.putIdleConn(pc) } - pc.t.setReqCanceler(rc.req, nil) - - if !alive { - pc.close() + if hook := testHookReadLoopBeforeNextRead; hook != nil { + hook() } } + pc.close() } func (pc *persistConn) writeLoop() { @@ -1027,9 +1091,24 @@ func (e *httpError) Temporary() bool { return true } var errTimeout error = &httpError{err: "net/http: timeout awaiting response headers", timeout: true} var errClosed error = &httpError{err: "net/http: transport closed before response was received"} +var errRequestCanceled = errors.New("net/http: request canceled") + +// nil except for tests +var ( + testHookPersistConnClosedGotRes func() + testHookEnterRoundTrip func() + testHookMu sync.Locker = fakeLocker{} // guards following + testHookReadLoopBeforeNextRead func() +) func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err error) { - pc.t.setReqCanceler(req.Request, pc.cancelRequest) + if hook := testHookEnterRoundTrip; hook != nil { + hook() + } + if !pc.t.replaceReqCanceler(req.Request, pc.cancelRequest) { + pc.t.putIdleConn(pc) + return nil, errRequestCanceled + } pc.lk.Lock() pc.numExpectedResponses++ headerFn := pc.mutateHeaderFunc @@ -1055,15 +1134,19 @@ func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err err // Note that we don't request this for HEAD requests, // due to a bug in nginx: // http://trac.nginx.org/nginx/ticket/358 - // http://golang.org/issue/5522 + // https://golang.org/issue/5522 // // We don't request gzip if the request is for a range, since // auto-decoding a portion of a gzipped document will just fail - // anyway. See http://golang.org/issue/8923 + // anyway. See https://golang.org/issue/8923 requestedGzip = true req.extraHeaders().Set("Accept-Encoding", "gzip") } + if pc.t.DisableKeepAlives { + req.extraHeaders().Set("Connection", "close") + } + // Write the request concurrently with waiting for a response, // in case the server decides to reply before reading our full // request body. @@ -1074,38 +1157,57 @@ func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err err pc.reqch <- requestAndChan{req.Request, resc, requestedGzip} var re responseAndError - var pconnDeadCh = pc.closech - var failTicker <-chan time.Time var respHeaderTimer <-chan time.Time + cancelChan := req.Request.Cancel WaitResponse: for { select { case err := <-writeErrCh: + if isNetWriteError(err) { + // Issue 11745. If we failed to write the request + // body, it's possible the server just heard enough + // and already wrote to us. Prioritize the server's + // response over returning a body write error. + select { + case re = <-resc: + pc.close() + break WaitResponse + case <-time.After(50 * time.Millisecond): + // Fall through. + } + } if err != nil { re = responseAndError{nil, err} pc.close() break WaitResponse } if d := pc.t.ResponseHeaderTimeout; d > 0 { - respHeaderTimer = time.After(d) + timer := time.NewTimer(d) + defer timer.Stop() // prevent leaks + respHeaderTimer = timer.C } - case <-pconnDeadCh: + case <-pc.closech: // The persist connection is dead. This shouldn't // usually happen (only with Connection: close responses // with no response bodies), but if it does happen it // means either a) the remote server hung up on us // prematurely, or b) the readLoop sent us a response & // closed its closech at roughly the same time, and we - // selected this case first, in which case a response - // might still be coming soon. - // - // We can't avoid the select race in b) by using a unbuffered - // resc channel instead, because then goroutines can - // leak if we exit due to other errors. - pconnDeadCh = nil // avoid spinning - failTicker = time.After(100 * time.Millisecond) // arbitrary time to wait for resc - case <-failTicker: - re = responseAndError{err: errClosed} + // selected this case first. If we got a response, readLoop makes sure + // to send it before it puts the conn and closes the channel. + // That way, we can fetch the response, if there is one, + // with a non-blocking receive. + select { + case re = <-resc: + if fn := testHookPersistConnClosedGotRes; fn != nil { + fn() + } + default: + re = responseAndError{err: errClosed} + if pc.isCanceled() { + re = responseAndError{err: errRequestCanceled} + } + } break WaitResponse case <-respHeaderTimer: pc.close() @@ -1113,13 +1215,12 @@ WaitResponse: break WaitResponse case re = <-resc: break WaitResponse + case <-cancelChan: + pc.t.CancelRequest(req.Request) + cancelChan = nil } } - pc.lk.Lock() - pc.numExpectedResponses-- - pc.lk.Unlock() - if re.err != nil { pc.t.setReqCanceler(req.Request, nil) } @@ -1167,16 +1268,18 @@ func canonicalAddr(url *url.URL) string { // bodyEOFSignal wraps a ReadCloser but runs fn (if non-nil) at most // once, right before its final (error-producing) Read or Close call -// returns. If earlyCloseFn is non-nil and Close is called before -// io.EOF is seen, earlyCloseFn is called instead of fn, and its -// return value is the return value from Close. +// returns. fn should return the new error to return from Read or Close. +// +// If earlyCloseFn is non-nil and Close is called before io.EOF is +// seen, earlyCloseFn is called instead of fn, and its return value is +// the return value from Close. type bodyEOFSignal struct { body io.ReadCloser - mu sync.Mutex // guards following 4 fields - closed bool // whether Close has been called - rerr error // sticky Read error - fn func(error) // error will be nil on Read io.EOF - earlyCloseFn func() error // optional alt Close func used if io.EOF not seen + mu sync.Mutex // guards following 4 fields + closed bool // whether Close has been called + rerr error // sticky Read error + fn func(error) error // err will be nil on Read io.EOF + earlyCloseFn func() error // optional alt Close func used if io.EOF not seen } func (es *bodyEOFSignal) Read(p []byte) (n int, err error) { @@ -1197,7 +1300,7 @@ func (es *bodyEOFSignal) Read(p []byte) (n int, err error) { if es.rerr == nil { es.rerr = err } - es.condfn(err) + err = es.condfn(err) } return } @@ -1213,20 +1316,17 @@ func (es *bodyEOFSignal) Close() error { return es.earlyCloseFn() } err := es.body.Close() - es.condfn(err) - return err + return es.condfn(err) } // caller must hold es.mu. -func (es *bodyEOFSignal) condfn(err error) { +func (es *bodyEOFSignal) condfn(err error) error { if es.fn == nil { - return - } - if err == io.EOF { - err = nil + return err } - es.fn(err) + err = es.fn(err) es.fn = nil + return err } // gzipReader wraps a response body so it can lazily @@ -1273,3 +1373,89 @@ func (nr noteEOFReader) Read(p []byte) (n int, err error) { } return } + +// fakeLocker is a sync.Locker which does nothing. It's used to guard +// test-only fields when not under test, to avoid runtime atomic +// overhead. +type fakeLocker struct{} + +func (fakeLocker) Lock() {} +func (fakeLocker) Unlock() {} + +func isNetWriteError(err error) bool { + switch e := err.(type) { + case *url.Error: + return isNetWriteError(e.Err) + case *net.OpError: + return e.Op == "write" + default: + return false + } +} + +// cloneTLSConfig returns a shallow clone of the exported +// fields of cfg, ignoring the unexported sync.Once, which +// contains a mutex and must not be copied. +// +// The cfg must not be in active use by tls.Server, or else +// there can still be a race with tls.Server updating SessionTicketKey +// and our copying it, and also a race with the server setting +// SessionTicketsDisabled=false on failure to set the random +// ticket key. +// +// If cfg is nil, a new zero tls.Config is returned. +func cloneTLSConfig(cfg *tls.Config) *tls.Config { + if cfg == nil { + return &tls.Config{} + } + return &tls.Config{ + Rand: cfg.Rand, + Time: cfg.Time, + Certificates: cfg.Certificates, + NameToCertificate: cfg.NameToCertificate, + GetCertificate: cfg.GetCertificate, + RootCAs: cfg.RootCAs, + NextProtos: cfg.NextProtos, + ServerName: cfg.ServerName, + ClientAuth: cfg.ClientAuth, + ClientCAs: cfg.ClientCAs, + InsecureSkipVerify: cfg.InsecureSkipVerify, + CipherSuites: cfg.CipherSuites, + PreferServerCipherSuites: cfg.PreferServerCipherSuites, + SessionTicketsDisabled: cfg.SessionTicketsDisabled, + SessionTicketKey: cfg.SessionTicketKey, + ClientSessionCache: cfg.ClientSessionCache, + MinVersion: cfg.MinVersion, + MaxVersion: cfg.MaxVersion, + CurvePreferences: cfg.CurvePreferences, + } +} + +// cloneTLSClientConfig is like cloneTLSConfig but omits +// the fields SessionTicketsDisabled and SessionTicketKey. +// This makes it safe to call cloneTLSClientConfig on a config +// in active use by a server. +func cloneTLSClientConfig(cfg *tls.Config) *tls.Config { + if cfg == nil { + return &tls.Config{} + } + return &tls.Config{ + Rand: cfg.Rand, + Time: cfg.Time, + Certificates: cfg.Certificates, + NameToCertificate: cfg.NameToCertificate, + GetCertificate: cfg.GetCertificate, + RootCAs: cfg.RootCAs, + NextProtos: cfg.NextProtos, + ServerName: cfg.ServerName, + ClientAuth: cfg.ClientAuth, + ClientCAs: cfg.ClientCAs, + InsecureSkipVerify: cfg.InsecureSkipVerify, + CipherSuites: cfg.CipherSuites, + PreferServerCipherSuites: cfg.PreferServerCipherSuites, + ClientSessionCache: cfg.ClientSessionCache, + MinVersion: cfg.MinVersion, + MaxVersion: cfg.MaxVersion, + CurvePreferences: cfg.CurvePreferences, + } +} diff --git a/libgo/go/net/http/transport_test.go b/libgo/go/net/http/transport_test.go index defa6337082..c21d4afa87f 100644 --- a/libgo/go/net/http/transport_test.go +++ b/libgo/go/net/http/transport_test.go @@ -18,11 +18,11 @@ import ( "io/ioutil" "log" "net" - "net/http" . "net/http" "net/http/httptest" "net/url" "os" + "reflect" "runtime" "strconv" "strings" @@ -39,6 +39,7 @@ var hostPortHandler = HandlerFunc(func(w ResponseWriter, r *Request) { if r.FormValue("close") == "true" { w.Header().Set("Connection", "close") } + w.Header().Set("X-Saw-Close", fmt.Sprint(r.Close)) w.Write([]byte(r.RemoteAddr)) }) @@ -228,6 +229,10 @@ func TestTransportConnectionCloseOnRequest(t *testing.T) { if err != nil { t.Fatalf("error in connectionClose=%v, req #%d, Do: %v", connectionClose, n, err) } + if got, want := res.Header.Get("X-Saw-Close"), fmt.Sprint(connectionClose); got != want { + t.Errorf("For connectionClose = %v; handler's X-Saw-Close was %v; want %v", + connectionClose, got, !connectionClose) + } body, err := ioutil.ReadAll(res.Body) if err != nil { t.Fatalf("error in connectionClose=%v, req #%d, ReadAll: %v", connectionClose, n, err) @@ -249,6 +254,27 @@ func TestTransportConnectionCloseOnRequest(t *testing.T) { connSet.check(t) } +// if the Transport's DisableKeepAlives is set, all requests should +// send Connection: close. +func TestTransportConnectionCloseOnRequestDisableKeepAlive(t *testing.T) { + defer afterTest(t) + ts := httptest.NewServer(hostPortHandler) + defer ts.Close() + + tr := &Transport{ + DisableKeepAlives: true, + } + c := &Client{Transport: tr} + res, err := c.Get(ts.URL) + if err != nil { + t.Fatal(err) + } + res.Body.Close() + if res.Header.Get("X-Saw-Close") != "true" { + t.Errorf("handler didn't see Connection: close ") + } +} + func TestTransportIdleCacheKeys(t *testing.T) { defer afterTest(t) ts := httptest.NewServer(hostPortHandler) @@ -293,7 +319,7 @@ func TestTransportReadToEndReusesConn(t *testing.T) { addrSeen[r.RemoteAddr]++ if r.URL.Path == "/chunked/" { w.WriteHeader(200) - w.(http.Flusher).Flush() + w.(Flusher).Flush() } else { w.Header().Set("Content-Type", strconv.Itoa(len(msg))) w.WriteHeader(200) @@ -308,7 +334,7 @@ func TestTransportReadToEndReusesConn(t *testing.T) { wantLen := []int{len(msg), -1}[pi] addrSeen = make(map[string]int) for i := 0; i < 3; i++ { - res, err := http.Get(ts.URL + path) + res, err := Get(ts.URL + path) if err != nil { t.Errorf("Get %s: %v", path, err) continue @@ -459,7 +485,7 @@ func TestTransportServerClosingUnexpectedly(t *testing.T) { } } -// Test for http://golang.org/issue/2616 (appropriate issue number) +// Test for https://golang.org/issue/2616 (appropriate issue number) // This fails pretty reliably with GOMAXPROCS=100 or something high. func TestStressSurpriseServerCloses(t *testing.T) { defer afterTest(t) @@ -479,12 +505,17 @@ func TestStressSurpriseServerCloses(t *testing.T) { tr := &Transport{DisableKeepAlives: false} c := &Client{Transport: tr} + defer tr.CloseIdleConnections() // Do a bunch of traffic from different goroutines. Send to activityc // after each request completes, regardless of whether it failed. + // If these are too high, OS X exhausts its ephemeral ports + // and hangs waiting for them to transition TCP states. That's + // not what we want to test. TODO(bradfitz): use an io.Pipe + // dialer for this test instead? const ( - numClients = 50 - reqsPerClient = 250 + numClients = 20 + reqsPerClient = 25 ) activityc := make(chan bool) for i := 0; i < numClients; i++ { @@ -567,11 +598,22 @@ func TestTransportHeadChunkedResponse(t *testing.T) { tr := &Transport{DisableKeepAlives: false} c := &Client{Transport: tr} + // Ensure that we wait for the readLoop to complete before + // calling Head again + didRead := make(chan bool) + SetReadLoopBeforeNextReadHook(func() { didRead <- true }) + defer SetReadLoopBeforeNextReadHook(nil) + res1, err := c.Head(ts.URL) + <-didRead + if err != nil { t.Fatalf("request 1 error: %v", err) } + res2, err := c.Head(ts.URL) + <-didRead + if err != nil { t.Fatalf("request 2 error: %v", err) } @@ -833,7 +875,7 @@ func TestTransportGzipShort(t *testing.T) { // tests that persistent goroutine connections shut down when no longer desired. func TestTransportPersistConnLeak(t *testing.T) { if runtime.GOOS == "plan9" { - t.Skip("skipping test; see http://golang.org/issue/7237") + t.Skip("skipping test; see https://golang.org/issue/7237") } defer afterTest(t) gotReqCh := make(chan bool) @@ -902,7 +944,7 @@ func TestTransportPersistConnLeak(t *testing.T) { // request.ContentLength is explicitly short func TestTransportPersistConnLeakShortBody(t *testing.T) { if runtime.GOOS == "plan9" { - t.Skip("skipping test; see http://golang.org/issue/7237") + t.Skip("skipping test; see https://golang.org/issue/7237") } defer afterTest(t) ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { @@ -941,7 +983,7 @@ func TestTransportPersistConnLeakShortBody(t *testing.T) { } } -// This used to crash; http://golang.org/issue/3266 +// This used to crash; https://golang.org/issue/3266 func TestTransportIdleConnCrash(t *testing.T) { defer afterTest(t) tr := &Transport{} @@ -1023,7 +1065,7 @@ func TestIssue3595(t *testing.T) { } } -// From http://golang.org/issue/4454 , +// From https://golang.org/issue/4454 , // "client fails to handle requests with no body and chunked encoding" func TestChunkedNoContent(t *testing.T) { defer afterTest(t) @@ -1110,7 +1152,7 @@ func TestTransportConcurrency(t *testing.T) { func TestIssue4191_InfiniteGetTimeout(t *testing.T) { if runtime.GOOS == "plan9" { - t.Skip("skipping test; see http://golang.org/issue/7237") + t.Skip("skipping test; see https://golang.org/issue/7237") } defer afterTest(t) const debug = false @@ -1174,7 +1216,7 @@ func TestIssue4191_InfiniteGetTimeout(t *testing.T) { func TestIssue4191_InfiniteGetToPutTimeout(t *testing.T) { if runtime.GOOS == "plan9" { - t.Skip("skipping test; see http://golang.org/issue/7237") + t.Skip("skipping test; see https://golang.org/issue/7237") } defer afterTest(t) const debug = false @@ -1345,8 +1387,8 @@ func TestTransportCancelRequest(t *testing.T) { body, err := ioutil.ReadAll(res.Body) d := time.Since(t0) - if err == nil { - t.Error("expected an error reading the body") + if err != ExportErrRequestCanceled { + t.Errorf("Body.Read error = %v; want errRequestCanceled", err) } if string(body) != "Hello" { t.Errorf("Body = %q; want Hello", body) @@ -1356,7 +1398,7 @@ func TestTransportCancelRequest(t *testing.T) { } // Verify no outstanding requests after readLoop/writeLoop // goroutines shut down. - for tries := 3; tries > 0; tries-- { + for tries := 5; tries > 0; tries-- { n := tr.NumPendingRequestsForTesting() if n == 0 { break @@ -1405,6 +1447,7 @@ func TestTransportCancelRequestInDial(t *testing.T) { eventLog.Printf("canceling") tr.CancelRequest(req) + tr.CancelRequest(req) // used to panic on second call select { case <-gotres: @@ -1422,6 +1465,135 @@ Get = Get http://something.no-network.tld/: net/http: request canceled while wai } } +func TestCancelRequestWithChannel(t *testing.T) { + defer afterTest(t) + if testing.Short() { + t.Skip("skipping test in -short mode") + } + unblockc := make(chan bool) + ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { + fmt.Fprintf(w, "Hello") + w.(Flusher).Flush() // send headers and some body + <-unblockc + })) + defer ts.Close() + defer close(unblockc) + + tr := &Transport{} + defer tr.CloseIdleConnections() + c := &Client{Transport: tr} + + req, _ := NewRequest("GET", ts.URL, nil) + ch := make(chan struct{}) + req.Cancel = ch + + res, err := c.Do(req) + if err != nil { + t.Fatal(err) + } + go func() { + time.Sleep(1 * time.Second) + close(ch) + }() + t0 := time.Now() + body, err := ioutil.ReadAll(res.Body) + d := time.Since(t0) + + if err != ExportErrRequestCanceled { + t.Errorf("Body.Read error = %v; want errRequestCanceled", err) + } + if string(body) != "Hello" { + t.Errorf("Body = %q; want Hello", body) + } + if d < 500*time.Millisecond { + t.Errorf("expected ~1 second delay; got %v", d) + } + // Verify no outstanding requests after readLoop/writeLoop + // goroutines shut down. + for tries := 5; tries > 0; tries-- { + n := tr.NumPendingRequestsForTesting() + if n == 0 { + break + } + time.Sleep(100 * time.Millisecond) + if tries == 1 { + t.Errorf("pending requests = %d; want 0", n) + } + } +} + +func TestCancelRequestWithChannelBeforeDo(t *testing.T) { + defer afterTest(t) + unblockc := make(chan bool) + ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { + <-unblockc + })) + defer ts.Close() + defer close(unblockc) + + // Don't interfere with the next test on plan9. + // Cf. https://golang.org/issues/11476 + if runtime.GOOS == "plan9" { + defer time.Sleep(500 * time.Millisecond) + } + + tr := &Transport{} + defer tr.CloseIdleConnections() + c := &Client{Transport: tr} + + req, _ := NewRequest("GET", ts.URL, nil) + ch := make(chan struct{}) + req.Cancel = ch + close(ch) + + _, err := c.Do(req) + if err == nil || !strings.Contains(err.Error(), "canceled") { + t.Errorf("Do error = %v; want cancelation", err) + } +} + +// Issue 11020. The returned error message should be errRequestCanceled +func TestTransportCancelBeforeResponseHeaders(t *testing.T) { + t.Skip("Skipping flaky test; see Issue 11894") + defer afterTest(t) + + serverConnCh := make(chan net.Conn, 1) + tr := &Transport{ + Dial: func(network, addr string) (net.Conn, error) { + cc, sc := net.Pipe() + serverConnCh <- sc + return cc, nil + }, + } + defer tr.CloseIdleConnections() + errc := make(chan error, 1) + req, _ := NewRequest("GET", "http://example.com/", nil) + go func() { + _, err := tr.RoundTrip(req) + errc <- err + }() + + sc := <-serverConnCh + verb := make([]byte, 3) + if _, err := io.ReadFull(sc, verb); err != nil { + t.Errorf("Error reading HTTP verb from server: %v", err) + } + if string(verb) != "GET" { + t.Errorf("server received %q; want GET", verb) + } + defer sc.Close() + + tr.CancelRequest(req) + + err := <-errc + if err == nil { + t.Fatalf("unexpected success from RoundTrip") + } + if err != ExportErrRequestCanceled { + t.Errorf("RoundTrip error = %v; want ExportErrRequestCanceled", err) + } +} + // golang.org/issue/3672 -- Client can't close HTTP stream // Calling Close on a Response.Body used to just read until EOF. // Now it actually closes the TCP connection. @@ -1795,6 +1967,11 @@ func TestIdleConnChannelLeak(t *testing.T) { })) defer ts.Close() + const nReqs = 5 + didRead := make(chan bool, nReqs) + SetReadLoopBeforeNextReadHook(func() { didRead <- true }) + defer SetReadLoopBeforeNextReadHook(nil) + tr := &Transport{ Dial: func(netw, addr string) (net.Conn, error) { return net.Dial(netw, ts.Listener.Addr().String()) @@ -1807,12 +1984,28 @@ func TestIdleConnChannelLeak(t *testing.T) { // First, without keep-alives. for _, disableKeep := range []bool{true, false} { tr.DisableKeepAlives = disableKeep - for i := 0; i < 5; i++ { + for i := 0; i < nReqs; i++ { _, err := c.Get(fmt.Sprintf("http://foo-host-%d.tld/", i)) if err != nil { t.Fatal(err) } + // Note: no res.Body.Close is needed here, since the + // response Content-Length is zero. Perhaps the test + // should be more explicit and use a HEAD, but tests + // elsewhere guarantee that zero byte responses generate + // a "Content-Length: 0" instead of chunking. + } + + // At this point, each of the 5 Transport.readLoop goroutines + // are scheduling noting that there are no response bodies (see + // earlier comment), and are then calling putIdleConn, which + // decrements this count. Usually that happens quickly, which is + // why this test has seemed to work for ages. But it's still + // racey: we have wait for them to finish first. See Issue 10427 + for i := 0; i < nReqs; i++ { + <-didRead } + if got := tr.IdleConnChMapSizeForTesting(); got != 0 { t.Fatalf("ForDisableKeepAlives = %v, map size = %d; want 0", disableKeep, got) } @@ -1824,7 +2017,7 @@ func TestIdleConnChannelLeak(t *testing.T) { // then closes it. func TestTransportClosesRequestBody(t *testing.T) { defer afterTest(t) - ts := httptest.NewServer(http.HandlerFunc(func(w ResponseWriter, r *Request) { + ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { io.Copy(ioutil.Discard, r.Body) })) defer ts.Close() @@ -2060,6 +2253,38 @@ func TestTransportNoReuseAfterEarlyResponse(t *testing.T) { } } +// Tests that we don't leak Transport persistConn.readLoop goroutines +// when a server hangs up immediately after saying it would keep-alive. +func TestTransportIssue10457(t *testing.T) { + defer afterTest(t) // used to fail in goroutine leak check + ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { + // Send a response with no body, keep-alive + // (implicit), and then lie and immediately close the + // connection. This forces the Transport's readLoop to + // immediately Peek an io.EOF and get to the point + // that used to hang. + conn, _, _ := w.(Hijacker).Hijack() + conn.Write([]byte("HTTP/1.1 200 OK\r\nFoo: Bar\r\nContent-Length: 0\r\n\r\n")) // keep-alive + conn.Close() + })) + defer ts.Close() + tr := &Transport{} + defer tr.CloseIdleConnections() + cl := &Client{Transport: tr} + res, err := cl.Get(ts.URL) + if err != nil { + t.Fatalf("Get: %v", err) + } + defer res.Body.Close() + + // Just a sanity check that we at least get the response. The real + // test here is that the "defer afterTest" above doesn't find any + // leaked goroutines. + if got, want := res.Header.Get("Foo"), "Bar"; got != want { + t.Errorf("Foo header = %q; want %q", got, want) + } +} + type errorReader struct { err error } @@ -2073,7 +2298,7 @@ func (f closerFunc) Close() error { return f() } // Issue 6981 func TestTransportClosesBodyOnError(t *testing.T) { if runtime.GOOS == "plan9" { - t.Skip("skipping test; see http://golang.org/issue/7782") + t.Skip("skipping test; see https://golang.org/issue/7782") } defer afterTest(t) readBody := make(chan error, 1) @@ -2162,13 +2387,13 @@ func TestTransportDialTLS(t *testing.T) { // Test for issue 8755 // Ensure that if a proxy returns an error, it is exposed by RoundTrip func TestRoundTripReturnsProxyError(t *testing.T) { - badProxy := func(*http.Request) (*url.URL, error) { + badProxy := func(*Request) (*url.URL, error) { return nil, errors.New("errorMessage") } tr := &Transport{Proxy: badProxy} - req, _ := http.NewRequest("GET", "http://example.com", nil) + req, _ := NewRequest("GET", "http://example.com", nil) _, err := tr.RoundTrip(req) @@ -2249,7 +2474,268 @@ func TestTransportRangeAndGzip(t *testing.T) { res.Body.Close() } -func wantBody(res *http.Response, err error, want string) error { +// Previously, we used to handle a logical race within RoundTrip by waiting for 100ms +// in the case of an error. Changing the order of the channel operations got rid of this +// race. +// +// In order to test that the channel op reordering works, we install a hook into the +// roundTrip function which gets called if we saw the connection go away and +// we subsequently received a response. +func TestTransportResponseCloseRace(t *testing.T) { + if testing.Short() { + t.Skip("skipping in short mode") + } + defer afterTest(t) + + ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { + })) + defer ts.Close() + sawRace := false + SetInstallConnClosedHook(func() { + sawRace = true + }) + defer SetInstallConnClosedHook(nil) + tr := &Transport{ + DisableKeepAlives: true, + } + req, err := NewRequest("GET", ts.URL, nil) + if err != nil { + t.Fatal(err) + } + // selects are not deterministic, so do this a bunch + // and see if we handle the logical race at least once. + for i := 0; i < 10000; i++ { + resp, err := tr.RoundTrip(req) + if err != nil { + t.Fatalf("unexpected error: %s", err) + continue + } + resp.Body.Close() + if sawRace { + break + } + } + if !sawRace { + t.Errorf("didn't see response/connection going away race") + } +} + +// Test for issue 10474 +func TestTransportResponseCancelRace(t *testing.T) { + defer afterTest(t) + + ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { + // important that this response has a body. + var b [1024]byte + w.Write(b[:]) + })) + defer ts.Close() + + tr := &Transport{} + defer tr.CloseIdleConnections() + + req, err := NewRequest("GET", ts.URL, nil) + if err != nil { + t.Fatal(err) + } + res, err := tr.RoundTrip(req) + if err != nil { + t.Fatal(err) + } + // If we do an early close, Transport just throws the connection away and + // doesn't reuse it. In order to trigger the bug, it has to reuse the connection + // so read the body + if _, err := io.Copy(ioutil.Discard, res.Body); err != nil { + t.Fatal(err) + } + + req2, err := NewRequest("GET", ts.URL, nil) + if err != nil { + t.Fatal(err) + } + tr.CancelRequest(req) + res, err = tr.RoundTrip(req2) + if err != nil { + t.Fatal(err) + } + res.Body.Close() +} + +func TestTransportDialCancelRace(t *testing.T) { + defer afterTest(t) + + ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {})) + defer ts.Close() + + tr := &Transport{} + defer tr.CloseIdleConnections() + + req, err := NewRequest("GET", ts.URL, nil) + if err != nil { + t.Fatal(err) + } + SetEnterRoundTripHook(func() { + tr.CancelRequest(req) + }) + defer SetEnterRoundTripHook(nil) + res, err := tr.RoundTrip(req) + if err != ExportErrRequestCanceled { + t.Errorf("expected canceled request error; got %v", err) + if err == nil { + res.Body.Close() + } + } +} + +// logWritesConn is a net.Conn that logs each Write call to writes +// and then proxies to w. +// It proxies Read calls to a reader it receives from rch. +type logWritesConn struct { + net.Conn // nil. crash on use. + + w io.Writer + + rch <-chan io.Reader + r io.Reader // nil until received by rch + + mu sync.Mutex + writes []string +} + +func (c *logWritesConn) Write(p []byte) (n int, err error) { + c.mu.Lock() + defer c.mu.Unlock() + c.writes = append(c.writes, string(p)) + return c.w.Write(p) +} + +func (c *logWritesConn) Read(p []byte) (n int, err error) { + if c.r == nil { + c.r = <-c.rch + } + return c.r.Read(p) +} + +func (c *logWritesConn) Close() error { return nil } + +// Issue 6574 +func TestTransportFlushesBodyChunks(t *testing.T) { + defer afterTest(t) + resBody := make(chan io.Reader, 1) + connr, connw := io.Pipe() // connection pipe pair + lw := &logWritesConn{ + rch: resBody, + w: connw, + } + tr := &Transport{ + Dial: func(network, addr string) (net.Conn, error) { + return lw, nil + }, + } + bodyr, bodyw := io.Pipe() // body pipe pair + go func() { + defer bodyw.Close() + for i := 0; i < 3; i++ { + fmt.Fprintf(bodyw, "num%d\n", i) + } + }() + resc := make(chan *Response) + go func() { + req, _ := NewRequest("POST", "http://localhost:8080", bodyr) + req.Header.Set("User-Agent", "x") // known value for test + res, err := tr.RoundTrip(req) + if err != nil { + t.Error("RoundTrip: %v", err) + close(resc) + return + } + resc <- res + + }() + // Fully consume the request before checking the Write log vs. want. + req, err := ReadRequest(bufio.NewReader(connr)) + if err != nil { + t.Fatal(err) + } + io.Copy(ioutil.Discard, req.Body) + + // Unblock the transport's roundTrip goroutine. + resBody <- strings.NewReader("HTTP/1.1 204 No Content\r\nConnection: close\r\n\r\n") + res, ok := <-resc + if !ok { + return + } + defer res.Body.Close() + + want := []string{ + // Because Request.ContentLength = 0, the body is sniffed for 1 byte to determine whether there's content. + // That explains the initial "num0" being split into "n" and "um0". + // The first byte is included with the request headers Write. Perhaps in the future + // we will want to flush the headers out early if the first byte of the request body is + // taking a long time to arrive. But not yet. + "POST / HTTP/1.1\r\nHost: localhost:8080\r\nUser-Agent: x\r\nTransfer-Encoding: chunked\r\nAccept-Encoding: gzip\r\n\r\n" + + "1\r\nn\r\n", + "4\r\num0\n\r\n", + "5\r\nnum1\n\r\n", + "5\r\nnum2\n\r\n", + "0\r\n\r\n", + } + if !reflect.DeepEqual(lw.writes, want) { + t.Errorf("Writes differed.\n Got: %q\nWant: %q\n", lw.writes, want) + } +} + +// Issue 11745. +func TestTransportPrefersResponseOverWriteError(t *testing.T) { + if testing.Short() { + t.Skip("skipping in short mode") + } + defer afterTest(t) + const contentLengthLimit = 1024 * 1024 // 1MB + ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { + if r.ContentLength >= contentLengthLimit { + w.WriteHeader(StatusBadRequest) + r.Body.Close() + return + } + w.WriteHeader(StatusOK) + })) + defer ts.Close() + + fail := 0 + count := 100 + bigBody := strings.Repeat("a", contentLengthLimit*2) + for i := 0; i < count; i++ { + req, err := NewRequest("PUT", ts.URL, strings.NewReader(bigBody)) + if err != nil { + t.Fatal(err) + } + tr := new(Transport) + defer tr.CloseIdleConnections() + client := &Client{Transport: tr} + resp, err := client.Do(req) + if err != nil { + fail++ + t.Logf("%d = %#v", i, err) + if ue, ok := err.(*url.Error); ok { + t.Logf("urlErr = %#v", ue.Err) + if ne, ok := ue.Err.(*net.OpError); ok { + t.Logf("netOpError = %#v", ne.Err) + } + } + } else { + resp.Body.Close() + if resp.StatusCode != 400 { + t.Errorf("Expected status code 400, got %v", resp.Status) + } + } + } + if fail > 0 { + t.Errorf("Failed %v out of %v\n", fail, count) + } +} + +func wantBody(res *Response, err error, want string) error { if err != nil { return err } diff --git a/libgo/go/net/interface.go b/libgo/go/net/interface.go index 2e9f1ebc679..9c7b5da8fe9 100644 --- a/libgo/go/net/interface.go +++ b/libgo/go/net/interface.go @@ -62,41 +62,61 @@ func (f Flags) String() string { // Addrs returns interface addresses for a specific interface. func (ifi *Interface) Addrs() ([]Addr, error) { if ifi == nil { - return nil, errInvalidInterface + return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterface} } - return interfaceAddrTable(ifi) + ifat, err := interfaceAddrTable(ifi) + if err != nil { + err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err} + } + return ifat, err } // MulticastAddrs returns multicast, joined group addresses for // a specific interface. func (ifi *Interface) MulticastAddrs() ([]Addr, error) { if ifi == nil { - return nil, errInvalidInterface + return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterface} + } + ifat, err := interfaceMulticastAddrTable(ifi) + if err != nil { + err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err} } - return interfaceMulticastAddrTable(ifi) + return ifat, err } // Interfaces returns a list of the system's network interfaces. func Interfaces() ([]Interface, error) { - return interfaceTable(0) + ift, err := interfaceTable(0) + if err != nil { + err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err} + } + return ift, err } // InterfaceAddrs returns a list of the system's network interface // addresses. func InterfaceAddrs() ([]Addr, error) { - return interfaceAddrTable(nil) + ifat, err := interfaceAddrTable(nil) + if err != nil { + err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err} + } + return ifat, err } // InterfaceByIndex returns the interface specified by index. func InterfaceByIndex(index int) (*Interface, error) { if index <= 0 { - return nil, errInvalidInterfaceIndex + return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterfaceIndex} } ift, err := interfaceTable(index) if err != nil { - return nil, err + return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err} } - return interfaceByIndex(ift, index) + ifi, err := interfaceByIndex(ift, index) + if err != nil { + err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err} + } + return ifi, err } func interfaceByIndex(ift []Interface, index int) (*Interface, error) { @@ -111,16 +131,16 @@ func interfaceByIndex(ift []Interface, index int) (*Interface, error) { // InterfaceByName returns the interface specified by name. func InterfaceByName(name string) (*Interface, error) { if name == "" { - return nil, errInvalidInterfaceName + return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterfaceName} } ift, err := interfaceTable(0) if err != nil { - return nil, err + return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err} } for _, ifi := range ift { if name == ifi.Name { return &ifi, nil } } - return nil, errNoSuchInterface + return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errNoSuchInterface} } diff --git a/libgo/go/net/interface_bsd.go b/libgo/go/net/interface_bsd.go index 16775579d05..208f37f9fd3 100644 --- a/libgo/go/net/interface_bsd.go +++ b/libgo/go/net/interface_bsd.go @@ -18,11 +18,11 @@ import ( func interfaceTable(ifindex int) ([]Interface, error) { tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST, ifindex) if err != nil { - return nil, os.NewSyscallError("route rib", err) + return nil, os.NewSyscallError("routerib", err) } msgs, err := syscall.ParseRoutingMessage(tab) if err != nil { - return nil, os.NewSyscallError("route message", err) + return nil, os.NewSyscallError("parseroutingmessage", err) } return parseInterfaceTable(ifindex, msgs) } @@ -51,27 +51,25 @@ loop: func newLink(m *syscall.InterfaceMessage) (*Interface, error) { sas, err := syscall.ParseRoutingSockaddr(m) if err != nil { - return nil, os.NewSyscallError("route sockaddr", err) + return nil, os.NewSyscallError("parseroutingsockaddr", err) } ifi := &Interface{Index: int(m.Header.Index), Flags: linkFlags(m.Header.Flags)} - for _, sa := range sas { - switch sa := sa.(type) { - case *syscall.SockaddrDatalink: - // NOTE: SockaddrDatalink.Data is minimum work area, - // can be larger. - m.Data = m.Data[unsafe.Offsetof(sa.Data):] - var name [syscall.IFNAMSIZ]byte - for i := 0; i < int(sa.Nlen); i++ { - name[i] = byte(m.Data[i]) - } - ifi.Name = string(name[:sa.Nlen]) - ifi.MTU = int(m.Header.Data.Mtu) - addr := make([]byte, sa.Alen) - for i := 0; i < int(sa.Alen); i++ { - addr[i] = byte(m.Data[int(sa.Nlen)+i]) - } - ifi.HardwareAddr = addr[:sa.Alen] + sa, _ := sas[syscall.RTAX_IFP].(*syscall.SockaddrDatalink) + if sa != nil { + // NOTE: SockaddrDatalink.Data is minimum work area, + // can be larger. + m.Data = m.Data[unsafe.Offsetof(sa.Data):] + var name [syscall.IFNAMSIZ]byte + for i := 0; i < int(sa.Nlen); i++ { + name[i] = byte(m.Data[i]) } + ifi.Name = string(name[:sa.Nlen]) + ifi.MTU = int(m.Header.Data.Mtu) + addr := make([]byte, sa.Alen) + for i := 0; i < int(sa.Alen); i++ { + addr[i] = byte(m.Data[int(sa.Nlen)+i]) + } + ifi.HardwareAddr = addr[:sa.Alen] } return ifi, nil } @@ -106,11 +104,11 @@ func interfaceAddrTable(ifi *Interface) ([]Addr, error) { } tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST, index) if err != nil { - return nil, os.NewSyscallError("route rib", err) + return nil, os.NewSyscallError("routerib", err) } msgs, err := syscall.ParseRoutingMessage(tab) if err != nil { - return nil, os.NewSyscallError("route message", err) + return nil, os.NewSyscallError("parseroutingmessage", err) } var ift []Interface if index == 0 { @@ -144,39 +142,34 @@ func interfaceAddrTable(ifi *Interface) ([]Addr, error) { return ifat, nil } -func newAddr(ifi *Interface, m *syscall.InterfaceAddrMessage) (Addr, error) { +func newAddr(ifi *Interface, m *syscall.InterfaceAddrMessage) (*IPNet, error) { sas, err := syscall.ParseRoutingSockaddr(m) if err != nil { - return nil, os.NewSyscallError("route sockaddr", err) + return nil, os.NewSyscallError("parseroutingsockaddr", err) } ifa := &IPNet{} - for i, sa := range sas { - switch sa := sa.(type) { - case *syscall.SockaddrInet4: - switch i { - case 0: - ifa.Mask = IPv4Mask(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3]) - case 1: - ifa.IP = IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3]) - } - case *syscall.SockaddrInet6: - switch i { - case 0: - ifa.Mask = make(IPMask, IPv6len) - copy(ifa.Mask, sa.Addr[:]) - case 1: - ifa.IP = make(IP, IPv6len) - copy(ifa.IP, sa.Addr[:]) - // NOTE: KAME based IPv6 protcol stack usually embeds - // the interface index in the interface-local or link- - // local address as the kernel-internal form. - if ifa.IP.IsLinkLocalUnicast() { - ifa.IP[2], ifa.IP[3] = 0, 0 - } - } - default: // Sockaddrs contain syscall.SockaddrDatalink on NetBSD - return nil, nil + switch sa := sas[syscall.RTAX_NETMASK].(type) { + case *syscall.SockaddrInet4: + ifa.Mask = IPv4Mask(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3]) + case *syscall.SockaddrInet6: + ifa.Mask = make(IPMask, IPv6len) + copy(ifa.Mask, sa.Addr[:]) + } + switch sa := sas[syscall.RTAX_IFA].(type) { + case *syscall.SockaddrInet4: + ifa.IP = IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3]) + case *syscall.SockaddrInet6: + ifa.IP = make(IP, IPv6len) + copy(ifa.IP, sa.Addr[:]) + // NOTE: KAME based IPv6 protcol stack usually embeds + // the interface index in the interface-local or + // link-local address as the kernel-internal form. + if ifa.IP.IsLinkLocalUnicast() { + ifa.IP[2], ifa.IP[3] = 0, 0 } } + if ifa.IP == nil || ifa.Mask == nil { + return nil, nil // Sockaddrs contain syscall.SockaddrDatalink on NetBSD + } return ifa, nil } diff --git a/libgo/go/net/interface_darwin.go b/libgo/go/net/interface_darwin.go index ad0937db047..b7a333849d1 100644 --- a/libgo/go/net/interface_darwin.go +++ b/libgo/go/net/interface_darwin.go @@ -14,11 +14,11 @@ import ( func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) { tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST2, ifi.Index) if err != nil { - return nil, os.NewSyscallError("route rib", err) + return nil, os.NewSyscallError("routerib", err) } msgs, err := syscall.ParseRoutingMessage(tab) if err != nil { - return nil, os.NewSyscallError("route message", err) + return nil, os.NewSyscallError("parseroutingmessage", err) } var ifmat []Addr for _, m := range msgs { @@ -29,35 +29,34 @@ func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) { if err != nil { return nil, err } - ifmat = append(ifmat, ifma...) + if ifma != nil { + ifmat = append(ifmat, ifma) + } } } } return ifmat, nil } -func newMulticastAddr(ifi *Interface, m *syscall.InterfaceMulticastAddrMessage) ([]Addr, error) { +func newMulticastAddr(ifi *Interface, m *syscall.InterfaceMulticastAddrMessage) (*IPAddr, error) { sas, err := syscall.ParseRoutingSockaddr(m) if err != nil { - return nil, os.NewSyscallError("route sockaddr", err) + return nil, os.NewSyscallError("parseroutingsockaddr", err) } - var ifmat []Addr - for _, sa := range sas { - switch sa := sa.(type) { - case *syscall.SockaddrInet4: - ifma := &IPAddr{IP: IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])} - ifmat = append(ifmat, ifma.toAddr()) - case *syscall.SockaddrInet6: - ifma := &IPAddr{IP: make(IP, IPv6len)} - copy(ifma.IP, sa.Addr[:]) - // NOTE: KAME based IPv6 protocol stack usually embeds - // the interface index in the interface-local or link- - // local address as the kernel-internal form. - if ifma.IP.IsInterfaceLocalMulticast() || ifma.IP.IsLinkLocalMulticast() { - ifma.IP[2], ifma.IP[3] = 0, 0 - } - ifmat = append(ifmat, ifma.toAddr()) + switch sa := sas[syscall.RTAX_IFA].(type) { + case *syscall.SockaddrInet4: + return &IPAddr{IP: IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])}, nil + case *syscall.SockaddrInet6: + ifma := IPAddr{IP: make(IP, IPv6len)} + copy(ifma.IP, sa.Addr[:]) + // NOTE: KAME based IPv6 protcol stack usually embeds + // the interface index in the interface-local or + // link-local address as the kernel-internal form. + if ifma.IP.IsInterfaceLocalMulticast() || ifma.IP.IsLinkLocalMulticast() { + ifma.IP[2], ifma.IP[3] = 0, 0 } + return &ifma, nil + default: + return nil, nil } - return ifmat, nil } diff --git a/libgo/go/net/interface_freebsd.go b/libgo/go/net/interface_freebsd.go index 5df767910e4..c42d90b7403 100644 --- a/libgo/go/net/interface_freebsd.go +++ b/libgo/go/net/interface_freebsd.go @@ -14,11 +14,11 @@ import ( func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) { tab, err := syscall.RouteRIB(syscall.NET_RT_IFMALIST, ifi.Index) if err != nil { - return nil, os.NewSyscallError("route rib", err) + return nil, os.NewSyscallError("routerib", err) } msgs, err := syscall.ParseRoutingMessage(tab) if err != nil { - return nil, os.NewSyscallError("route message", err) + return nil, os.NewSyscallError("parseroutingmessage", err) } var ifmat []Addr for _, m := range msgs { @@ -29,35 +29,34 @@ func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) { if err != nil { return nil, err } - ifmat = append(ifmat, ifma...) + if ifma != nil { + ifmat = append(ifmat, ifma) + } } } } return ifmat, nil } -func newMulticastAddr(ifi *Interface, m *syscall.InterfaceMulticastAddrMessage) ([]Addr, error) { +func newMulticastAddr(ifi *Interface, m *syscall.InterfaceMulticastAddrMessage) (*IPAddr, error) { sas, err := syscall.ParseRoutingSockaddr(m) if err != nil { - return nil, os.NewSyscallError("route sockaddr", err) + return nil, os.NewSyscallError("parseroutingsockaddr", err) } - var ifmat []Addr - for _, sa := range sas { - switch sa := sa.(type) { - case *syscall.SockaddrInet4: - ifma := &IPAddr{IP: IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])} - ifmat = append(ifmat, ifma.toAddr()) - case *syscall.SockaddrInet6: - ifma := &IPAddr{IP: make(IP, IPv6len)} - copy(ifma.IP, sa.Addr[:]) - // NOTE: KAME based IPv6 protocol stack usually embeds - // the interface index in the interface-local or link- - // local address as the kernel-internal form. - if ifma.IP.IsInterfaceLocalMulticast() || ifma.IP.IsLinkLocalMulticast() { - ifma.IP[2], ifma.IP[3] = 0, 0 - } - ifmat = append(ifmat, ifma.toAddr()) + switch sa := sas[syscall.RTAX_IFA].(type) { + case *syscall.SockaddrInet4: + return &IPAddr{IP: IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])}, nil + case *syscall.SockaddrInet6: + ifma := IPAddr{IP: make(IP, IPv6len)} + copy(ifma.IP, sa.Addr[:]) + // NOTE: KAME based IPv6 protcol stack usually embeds + // the interface index in the interface-local or + // link-local address as the kernel-internal form. + if ifma.IP.IsInterfaceLocalMulticast() || ifma.IP.IsLinkLocalMulticast() { + ifma.IP[2], ifma.IP[3] = 0, 0 } + return &ifma, nil + default: + return nil, nil } - return ifmat, nil } diff --git a/libgo/go/net/interface_linux.go b/libgo/go/net/interface_linux.go index 1115d0fc40b..ef2042920ed 100644 --- a/libgo/go/net/interface_linux.go +++ b/libgo/go/net/interface_linux.go @@ -16,11 +16,11 @@ import ( func interfaceTable(ifindex int) ([]Interface, error) { tab, err := syscall.NetlinkRIB(syscall.RTM_GETLINK, syscall.AF_UNSPEC) if err != nil { - return nil, os.NewSyscallError("netlink rib", err) + return nil, os.NewSyscallError("netlinkrib", err) } msgs, err := syscall.ParseNetlinkMessage(tab) if err != nil { - return nil, os.NewSyscallError("netlink message", err) + return nil, os.NewSyscallError("parsenetlinkmessage", err) } var ift []Interface loop: @@ -33,7 +33,7 @@ loop: if ifindex == 0 || ifindex == int(ifim.Index) { attrs, err := syscall.ParseNetlinkRouteAttr(&m) if err != nil { - return nil, os.NewSyscallError("netlink routeattr", err) + return nil, os.NewSyscallError("parsenetlinkrouteattr", err) } ift = append(ift, *newLink(ifim, attrs)) if ifindex == int(ifim.Index) { @@ -120,11 +120,11 @@ func linkFlags(rawFlags uint32) Flags { func interfaceAddrTable(ifi *Interface) ([]Addr, error) { tab, err := syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_UNSPEC) if err != nil { - return nil, os.NewSyscallError("netlink rib", err) + return nil, os.NewSyscallError("netlinkrib", err) } msgs, err := syscall.ParseNetlinkMessage(tab) if err != nil { - return nil, os.NewSyscallError("netlink message", err) + return nil, os.NewSyscallError("parsenetlinkmessage", err) } var ift []Interface if ifi == nil { @@ -160,7 +160,7 @@ loop: } attrs, err := syscall.ParseNetlinkRouteAttr(&m) if err != nil { - return nil, os.NewSyscallError("netlink routeattr", err) + return nil, os.NewSyscallError("parsenetlinkrouteattr", err) } ifa := newAddr(ifi, ifam, attrs) if ifa != nil { @@ -176,17 +176,15 @@ func newAddr(ifi *Interface, ifam *syscall.IfAddrmsg, attrs []syscall.NetlinkRou var ipPointToPoint bool // Seems like we need to make sure whether the IP interface // stack consists of IP point-to-point numbered or unnumbered - // addressing over point-to-point link encapsulation. - if ifi.Flags&FlagPointToPoint != 0 { - for _, a := range attrs { - if a.Attr.Type == syscall.IFA_LOCAL { - ipPointToPoint = true - break - } + // addressing. + for _, a := range attrs { + if a.Attr.Type == syscall.IFA_LOCAL { + ipPointToPoint = true + break } } for _, a := range attrs { - if ipPointToPoint && a.Attr.Type == syscall.IFA_ADDRESS || !ipPointToPoint && a.Attr.Type == syscall.IFA_LOCAL { + if ipPointToPoint && a.Attr.Type == syscall.IFA_ADDRESS { continue } switch ifam.Family { @@ -238,8 +236,8 @@ func parseProcNetIGMP(path string, ifi *Interface) []Addr { b[i/2], _ = xtoi2(f[0][i:i+2], 0) } i := *(*uint32)(unsafe.Pointer(&b[:4][0])) - ifma := IPAddr{IP: IPv4(byte(i>>24), byte(i>>16), byte(i>>8), byte(i))} - ifmat = append(ifmat, ifma.toAddr()) + ifma := &IPAddr{IP: IPv4(byte(i>>24), byte(i>>16), byte(i>>8), byte(i))} + ifmat = append(ifmat, ifma) } } } @@ -263,8 +261,8 @@ func parseProcNetIGMP6(path string, ifi *Interface) []Addr { 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()) + 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) } } return ifmat diff --git a/libgo/go/net/interface_test.go b/libgo/go/net/interface_test.go index efabb5f3c25..567d18de448 100644 --- a/libgo/go/net/interface_test.go +++ b/libgo/go/net/interface_test.go @@ -6,6 +6,7 @@ package net import ( "reflect" + "runtime" "testing" ) @@ -37,12 +38,7 @@ func ipv6LinkLocalUnicastAddr(ifi *Interface) string { return "" } for _, ifa := range ifat { - switch ifa := ifa.(type) { - case *IPAddr: - if ifa.IP.To4() == nil && ifa.IP.IsLinkLocalUnicast() { - return ifa.IP.String() - } - case *IPNet: + if ifa, ok := ifa.(*IPNet); ok { if ifa.IP.To4() == nil && ifa.IP.IsLinkLocalUnicast() { return ifa.IP.String() } @@ -51,161 +47,259 @@ func ipv6LinkLocalUnicastAddr(ifi *Interface) string { return "" } +type routeStats struct { + loop int // # of active loopback interfaces + other int // # of active other interfaces + + uni4, uni6 int // # of active connected unicast, anycast routes + multi4, multi6 int // # of active connected multicast route clones +} + func TestInterfaces(t *testing.T) { ift, err := Interfaces() if err != nil { - t.Fatalf("Interfaces failed: %v", err) + t.Fatal(err) } - t.Logf("table: len/cap = %v/%v", len(ift), cap(ift)) - + var stats routeStats for _, ifi := range ift { ifxi, err := InterfaceByIndex(ifi.Index) if err != nil { - t.Fatalf("InterfaceByIndex(%v) failed: %v", ifi.Index, err) + t.Fatal(err) } if !reflect.DeepEqual(ifxi, &ifi) { - t.Fatalf("InterfaceByIndex(%v) = %v, want %v", ifi.Index, ifxi, ifi) + t.Errorf("got %v; want %v", ifxi, ifi) } ifxn, err := InterfaceByName(ifi.Name) if err != nil { - t.Fatalf("InterfaceByName(%q) failed: %v", ifi.Name, err) + t.Fatal(err) } if !reflect.DeepEqual(ifxn, &ifi) { - t.Fatalf("InterfaceByName(%q) = %v, want %v", ifi.Name, ifxn, ifi) + t.Errorf("got %v; want %v", ifxn, ifi) } t.Logf("%q: flags %q, ifindex %v, mtu %v", ifi.Name, ifi.Flags.String(), ifi.Index, ifi.MTU) - t.Logf("\thardware address %q", ifi.HardwareAddr.String()) - testInterfaceAddrs(t, &ifi) - testInterfaceMulticastAddrs(t, &ifi) + t.Logf("hardware address %q", ifi.HardwareAddr.String()) + if ifi.Flags&FlagUp != 0 { + if ifi.Flags&FlagLoopback != 0 { + stats.loop++ + } else { + stats.other++ + } + } + n4, n6 := testInterfaceAddrs(t, &ifi) + stats.uni4 += n4 + stats.uni6 += n6 + n4, n6 = testInterfaceMulticastAddrs(t, &ifi) + stats.multi4 += n4 + stats.multi6 += n6 + } + switch runtime.GOOS { + case "nacl", "plan9", "solaris": + default: + // Test the existence of connected unicast routes for + // IPv4. + if supportsIPv4 && stats.loop+stats.other > 0 && stats.uni4 == 0 { + t.Errorf("num IPv4 unicast routes = 0; want >0; summary: %+v", stats) + } + // Test the existence of connected unicast routes for + // IPv6. We can assume the existence of ::1/128 when + // at least one looopback interface is installed. + if supportsIPv6 && stats.loop > 0 && stats.uni6 == 0 { + t.Errorf("num IPv6 unicast routes = 0; want >0; summary: %+v", stats) + } + } + switch runtime.GOOS { + case "dragonfly", "nacl", "netbsd", "openbsd", "plan9", "solaris": + default: + // Test the existence of connected multicast route + // clones for IPv4. Unlike IPv6, IPv4 multicast + // capability is not a mandatory feature, and so this + // test is disabled. + //if supportsIPv4 && stats.loop > 0 && stats.uni4 > 1 && stats.multi4 == 0 { + // t.Errorf("num IPv4 multicast route clones = 0; want >0; summary: %+v", stats) + //} + // Test the existence of connected multicast route + // clones for IPv6. Some platform never uses loopback + // interface as the nexthop for multicast routing. + // We can assume the existence of connected multicast + // route clones when at least two connected unicast + // routes, ::1/128 and other, are installed. + if supportsIPv6 && stats.loop > 0 && stats.uni6 > 1 && stats.multi6 == 0 { + t.Errorf("num IPv6 multicast route clones = 0; want >0; summary: %+v", stats) + } } } func TestInterfaceAddrs(t *testing.T) { + ift, err := Interfaces() + if err != nil { + t.Fatal(err) + } + var stats routeStats + for _, ifi := range ift { + if ifi.Flags&FlagUp != 0 { + if ifi.Flags&FlagLoopback != 0 { + stats.loop++ + } else { + stats.other++ + } + } + } ifat, err := InterfaceAddrs() if err != nil { - t.Fatalf("InterfaceAddrs failed: %v", err) + t.Fatal(err) + } + stats.uni4, stats.uni6 = testAddrs(t, ifat) + // Test the existence of connected unicast routes for IPv4. + if supportsIPv4 && stats.loop+stats.other > 0 && stats.uni4 == 0 { + t.Errorf("num IPv4 unicast routes = 0; want >0; summary: %+v", stats) + } + // Test the existence of connected unicast routes for IPv6. + // We can assume the existence of ::1/128 when at least one + // looopback interface is installed. + if supportsIPv6 && stats.loop > 0 && stats.uni6 == 0 { + t.Errorf("num IPv6 unicast routes = 0; want >0; summary: %+v", stats) } - t.Logf("table: len/cap = %v/%v", len(ifat), cap(ifat)) - testAddrs(t, ifat) } -func testInterfaceAddrs(t *testing.T, ifi *Interface) { +func testInterfaceAddrs(t *testing.T, ifi *Interface) (naf4, naf6 int) { ifat, err := ifi.Addrs() if err != nil { - t.Fatalf("Interface.Addrs failed: %v", err) + t.Fatal(err) } - testAddrs(t, ifat) + return testAddrs(t, ifat) } -func testInterfaceMulticastAddrs(t *testing.T, ifi *Interface) { +func testInterfaceMulticastAddrs(t *testing.T, ifi *Interface) (nmaf4, nmaf6 int) { ifmat, err := ifi.MulticastAddrs() if err != nil { - t.Fatalf("Interface.MulticastAddrs failed: %v", err) + t.Fatal(err) } - testMulticastAddrs(t, ifmat) + return testMulticastAddrs(t, ifmat) } -func testAddrs(t *testing.T, ifat []Addr) { +func testAddrs(t *testing.T, ifat []Addr) (naf4, naf6 int) { for _, ifa := range ifat { switch ifa := ifa.(type) { - case *IPAddr: - if ifa == nil || ifa.IP == nil { - t.Errorf("\tunexpected value: %v, %v", ifa, ifa.IP) - } else { - t.Logf("\tinterface address %q", ifa.String()) - } case *IPNet: - if ifa == nil || ifa.IP == nil || ifa.Mask == nil { - t.Errorf("\tunexpected value: %v, %v, %v", ifa, ifa.IP, ifa.Mask) - } else { - _, prefixLen := ifa.Mask.Size() - if ifa.IP.To4() != nil && prefixLen != 8*IPv4len || ifa.IP.To16() != nil && ifa.IP.To4() == nil && prefixLen != 8*IPv6len { - t.Errorf("\tunexpected value: %v, %v, %v, %v", ifa, ifa.IP, ifa.Mask, prefixLen) - } else { - t.Logf("\tinterface address %q", ifa.String()) + if ifa == nil || ifa.IP == nil || ifa.IP.IsUnspecified() || ifa.IP.IsMulticast() || ifa.Mask == nil { + t.Errorf("unexpected value: %#v", ifa) + continue + } + prefixLen, maxPrefixLen := ifa.Mask.Size() + if ifa.IP.To4() != nil { + if 0 >= prefixLen || prefixLen > 8*IPv4len || maxPrefixLen != 8*IPv4len { + t.Errorf("unexpected prefix length: %v/%v", prefixLen, maxPrefixLen) + continue + } + naf4++ + } else if ifa.IP.To16() != nil { + if 0 >= prefixLen || prefixLen > 8*IPv6len || maxPrefixLen != 8*IPv6len { + t.Errorf("unexpected prefix length: %v/%v", prefixLen, maxPrefixLen) + continue } + naf6++ } + t.Logf("interface address %q", ifa.String()) default: - t.Errorf("\tunexpected type: %T", ifa) + t.Errorf("unexpected type: %T", ifa) } } + return } -func testMulticastAddrs(t *testing.T, ifmat []Addr) { +func testMulticastAddrs(t *testing.T, ifmat []Addr) (nmaf4, nmaf6 int) { for _, ifma := range ifmat { switch ifma := ifma.(type) { case *IPAddr: - if ifma == nil { - t.Errorf("\tunexpected value: %v", ifma) - } else { - t.Logf("\tjoined group address %q", ifma.String()) + if ifma == nil || ifma.IP == nil || ifma.IP.IsUnspecified() || !ifma.IP.IsMulticast() { + t.Errorf("unexpected value: %#v", ifma) + continue } + if ifma.IP.To4() != nil { + nmaf4++ + } else if ifma.IP.To16() != nil { + nmaf6++ + } + t.Logf("joined group address %q", ifma.String()) default: - t.Errorf("\tunexpected type: %T", ifma) + t.Errorf("unexpected type: %T", ifma) } } + return } func BenchmarkInterfaces(b *testing.B) { + testHookUninstaller.Do(uninstallTestHooks) + for i := 0; i < b.N; i++ { if _, err := Interfaces(); err != nil { - b.Fatalf("Interfaces failed: %v", err) + b.Fatal(err) } } } func BenchmarkInterfaceByIndex(b *testing.B) { + testHookUninstaller.Do(uninstallTestHooks) + ifi := loopbackInterface() if ifi == nil { b.Skip("loopback interface not found") } for i := 0; i < b.N; i++ { if _, err := InterfaceByIndex(ifi.Index); err != nil { - b.Fatalf("InterfaceByIndex failed: %v", err) + b.Fatal(err) } } } func BenchmarkInterfaceByName(b *testing.B) { + testHookUninstaller.Do(uninstallTestHooks) + ifi := loopbackInterface() if ifi == nil { b.Skip("loopback interface not found") } for i := 0; i < b.N; i++ { if _, err := InterfaceByName(ifi.Name); err != nil { - b.Fatalf("InterfaceByName failed: %v", err) + b.Fatal(err) } } } func BenchmarkInterfaceAddrs(b *testing.B) { + testHookUninstaller.Do(uninstallTestHooks) + for i := 0; i < b.N; i++ { if _, err := InterfaceAddrs(); err != nil { - b.Fatalf("InterfaceAddrs failed: %v", err) + b.Fatal(err) } } } func BenchmarkInterfacesAndAddrs(b *testing.B) { + testHookUninstaller.Do(uninstallTestHooks) + ifi := loopbackInterface() if ifi == nil { b.Skip("loopback interface not found") } for i := 0; i < b.N; i++ { if _, err := ifi.Addrs(); err != nil { - b.Fatalf("Interface.Addrs failed: %v", err) + b.Fatal(err) } } } func BenchmarkInterfacesAndMulticastAddrs(b *testing.B) { + testHookUninstaller.Do(uninstallTestHooks) + ifi := loopbackInterface() if ifi == nil { b.Skip("loopback interface not found") } for i := 0; i < b.N; i++ { if _, err := ifi.MulticastAddrs(); err != nil { - b.Fatalf("Interface.MulticastAddrs failed: %v", err) + b.Fatal(err) } } } diff --git a/libgo/go/net/interface_windows.go b/libgo/go/net/interface_windows.go index 0759dc255d4..e25c1ed560b 100644 --- a/libgo/go/net/interface_windows.go +++ b/libgo/go/net/interface_windows.go @@ -5,123 +5,139 @@ package net import ( + "internal/syscall/windows" "os" "syscall" "unsafe" ) -func bytePtrToString(p *uint8) string { - a := (*[10000]uint8)(unsafe.Pointer(p)) - i := 0 - for a[i] != 0 { - i++ - } - return string(a[:i]) -} +func getAdapters() (*windows.IpAdapterAddresses, error) { + block := uint32(unsafe.Sizeof(windows.IpAdapterAddresses{})) -func getAdapterList() (*syscall.IpAdapterInfo, error) { - b := make([]byte, 1000) - l := uint32(len(b)) - a := (*syscall.IpAdapterInfo)(unsafe.Pointer(&b[0])) - // TODO(mikio): GetAdaptersInfo returns IP_ADAPTER_INFO that - // contains IPv4 address list only. We should use another API - // for fetching IPv6 stuff from the kernel. - err := syscall.GetAdaptersInfo(a, &l) - if err == syscall.ERROR_BUFFER_OVERFLOW { - b = make([]byte, l) - a = (*syscall.IpAdapterInfo)(unsafe.Pointer(&b[0])) - err = syscall.GetAdaptersInfo(a, &l) - } - if err != nil { - return nil, os.NewSyscallError("GetAdaptersInfo", err) + // pre-allocate a 15KB working buffer pointed to by the AdapterAddresses + // parameter. + // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365915(v=vs.85).aspx + size := uint32(15000) + + var addrs []windows.IpAdapterAddresses + for { + addrs = make([]windows.IpAdapterAddresses, size/block+1) + err := windows.GetAdaptersAddresses(syscall.AF_UNSPEC, windows.GAA_FLAG_INCLUDE_PREFIX, 0, &addrs[0], &size) + if err == nil { + break + } + if err.(syscall.Errno) != syscall.ERROR_BUFFER_OVERFLOW { + return nil, os.NewSyscallError("getadaptersaddresses", err) + } } - return a, nil + return &addrs[0], nil } -func getInterfaceList() ([]syscall.InterfaceInfo, error) { +func getInterfaceInfos() ([]syscall.InterfaceInfo, error) { s, err := sysSocket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP) if err != nil { - return nil, os.NewSyscallError("Socket", err) + return nil, err } - defer syscall.Closesocket(s) + defer closeFunc(s) - ii := [20]syscall.InterfaceInfo{} + iia := [20]syscall.InterfaceInfo{} ret := uint32(0) - size := uint32(unsafe.Sizeof(ii)) - err = syscall.WSAIoctl(s, syscall.SIO_GET_INTERFACE_LIST, nil, 0, (*byte)(unsafe.Pointer(&ii[0])), size, &ret, nil, 0) + size := uint32(unsafe.Sizeof(iia)) + err = syscall.WSAIoctl(s, syscall.SIO_GET_INTERFACE_LIST, nil, 0, (*byte)(unsafe.Pointer(&iia[0])), size, &ret, nil, 0) if err != nil { - return nil, os.NewSyscallError("WSAIoctl", err) + return nil, os.NewSyscallError("wsaioctl", err) } - c := ret / uint32(unsafe.Sizeof(ii[0])) - return ii[:c-1], nil + iilen := ret / uint32(unsafe.Sizeof(iia[0])) + return iia[:iilen-1], nil +} + +func bytesEqualIP(a []byte, b []int8) bool { + for i := 0; i < len(a); i++ { + if a[i] != byte(b[i]) { + return false + } + } + return true +} + +func findInterfaceInfo(iis []syscall.InterfaceInfo, paddr *windows.IpAdapterAddresses) *syscall.InterfaceInfo { + for _, ii := range iis { + iaddr := (*syscall.RawSockaddr)(unsafe.Pointer(&ii.Address)) + puni := paddr.FirstUnicastAddress + for ; puni != nil; puni = puni.Next { + if iaddr.Family == puni.Address.Sockaddr.Addr.Family { + switch iaddr.Family { + case syscall.AF_INET: + a := (*syscall.RawSockaddrInet4)(unsafe.Pointer(&ii.Address)).Addr + if bytesEqualIP(a[:], puni.Address.Sockaddr.Addr.Data[2:]) { + return &ii + } + case syscall.AF_INET6: + a := (*syscall.RawSockaddrInet6)(unsafe.Pointer(&ii.Address)).Addr + if bytesEqualIP(a[:], puni.Address.Sockaddr.Addr.Data[2:]) { + return &ii + } + default: + continue + } + } + } + } + return nil } // If the ifindex is zero, interfaceTable returns mappings of all // network interfaces. Otherwise it returns a mapping of a specific // interface. func interfaceTable(ifindex int) ([]Interface, error) { - ai, err := getAdapterList() + paddr, err := getAdapters() if err != nil { return nil, err } - ii, err := getInterfaceList() + iis, err := getInterfaceInfos() if err != nil { return nil, err } var ift []Interface - for ; ai != nil; ai = ai.Next { - index := ai.Index + for ; paddr != nil; paddr = paddr.Next { + index := paddr.IfIndex + if paddr.Ipv6IfIndex != 0 { + index = paddr.Ipv6IfIndex + } if ifindex == 0 || ifindex == int(index) { + ii := findInterfaceInfo(iis, paddr) + if ii == nil { + continue + } var flags Flags - - row := syscall.MibIfRow{Index: index} - e := syscall.GetIfEntry(&row) - if e != nil { - return nil, os.NewSyscallError("GetIfEntry", e) + if paddr.Flags&windows.IfOperStatusUp != 0 { + flags |= FlagUp } - - for _, ii := range ii { - ip := (*syscall.RawSockaddrInet4)(unsafe.Pointer(&ii.Address)).Addr - ipv4 := IPv4(ip[0], ip[1], ip[2], ip[3]) - ipl := &ai.IpAddressList - for ipl != nil { - ips := bytePtrToString(&ipl.IpAddress.String[0]) - if ipv4.Equal(parseIPv4(ips)) { - break - } - ipl = ipl.Next - } - if ipl == nil { - continue - } - if ii.Flags&syscall.IFF_UP != 0 { - flags |= FlagUp - } - if ii.Flags&syscall.IFF_LOOPBACK != 0 { - flags |= FlagLoopback - } - if ii.Flags&syscall.IFF_BROADCAST != 0 { - flags |= FlagBroadcast - } - if ii.Flags&syscall.IFF_POINTTOPOINT != 0 { - flags |= FlagPointToPoint - } - if ii.Flags&syscall.IFF_MULTICAST != 0 { - flags |= FlagMulticast - } + if paddr.IfType&windows.IF_TYPE_SOFTWARE_LOOPBACK != 0 { + flags |= FlagLoopback + } + if ii.Flags&syscall.IFF_BROADCAST != 0 { + flags |= FlagBroadcast + } + if ii.Flags&syscall.IFF_POINTTOPOINT != 0 { + flags |= FlagPointToPoint + } + if ii.Flags&syscall.IFF_MULTICAST != 0 { + flags |= FlagMulticast } - - name := bytePtrToString(&ai.AdapterName[0]) - ifi := Interface{ Index: int(index), - MTU: int(row.Mtu), - Name: name, - HardwareAddr: HardwareAddr(row.PhysAddr[:row.PhysAddrLen]), - Flags: flags} + MTU: int(paddr.Mtu), + Name: syscall.UTF16ToString((*(*[10000]uint16)(unsafe.Pointer(paddr.FriendlyName)))[:]), + HardwareAddr: HardwareAddr(paddr.PhysicalAddress[:]), + Flags: flags, + } ift = append(ift, ifi) + if ifindex == int(ifi.Index) { + break + } } } return ift, nil @@ -131,28 +147,86 @@ func interfaceTable(ifindex int) ([]Interface, error) { // network interfaces. Otherwise it returns addresses for a specific // interface. func interfaceAddrTable(ifi *Interface) ([]Addr, error) { - ai, err := getAdapterList() + paddr, err := getAdapters() if err != nil { return nil, err } var ifat []Addr - for ; ai != nil; ai = ai.Next { - index := ai.Index + for ; paddr != nil; paddr = paddr.Next { + index := paddr.IfIndex + if paddr.Ipv6IfIndex != 0 { + index = paddr.Ipv6IfIndex + } if ifi == nil || ifi.Index == int(index) { - ipl := &ai.IpAddressList - for ; ipl != nil; ipl = ipl.Next { - ifa := IPAddr{IP: parseIPv4(bytePtrToString(&ipl.IpAddress.String[0]))} - ifat = append(ifat, ifa.toAddr()) + puni := paddr.FirstUnicastAddress + for ; puni != nil; puni = puni.Next { + if sa, err := puni.Address.Sockaddr.Sockaddr(); err == nil { + switch sav := sa.(type) { + case *syscall.SockaddrInet4: + ifa := &IPNet{IP: make(IP, IPv4len), Mask: CIDRMask(int(puni.Address.SockaddrLength), 8*IPv4len)} + copy(ifa.IP, sav.Addr[:]) + ifat = append(ifat, ifa) + case *syscall.SockaddrInet6: + ifa := &IPNet{IP: make(IP, IPv6len), Mask: CIDRMask(int(puni.Address.SockaddrLength), 8*IPv6len)} + copy(ifa.IP, sav.Addr[:]) + ifat = append(ifat, ifa) + } + } + } + pany := paddr.FirstAnycastAddress + for ; pany != nil; pany = pany.Next { + if sa, err := pany.Address.Sockaddr.Sockaddr(); err == nil { + switch sav := sa.(type) { + case *syscall.SockaddrInet4: + ifa := &IPNet{IP: make(IP, IPv4len), Mask: CIDRMask(int(pany.Address.SockaddrLength), 8*IPv4len)} + copy(ifa.IP, sav.Addr[:]) + ifat = append(ifat, ifa) + case *syscall.SockaddrInet6: + ifa := &IPNet{IP: make(IP, IPv6len), Mask: CIDRMask(int(pany.Address.SockaddrLength), 8*IPv6len)} + copy(ifa.IP, sav.Addr[:]) + ifat = append(ifat, ifa) + } + } } } } + return ifat, nil } // interfaceMulticastAddrTable returns addresses for a specific // interface. func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) { - // TODO(mikio): Implement this like other platforms. - return nil, nil + paddr, err := getAdapters() + if err != nil { + return nil, err + } + + var ifat []Addr + for ; paddr != nil; paddr = paddr.Next { + index := paddr.IfIndex + if paddr.Ipv6IfIndex != 0 { + index = paddr.Ipv6IfIndex + } + if ifi == nil || ifi.Index == int(index) { + pmul := paddr.FirstMulticastAddress + for ; pmul != nil; pmul = pmul.Next { + if sa, err := pmul.Address.Sockaddr.Sockaddr(); err == nil { + switch sav := sa.(type) { + case *syscall.SockaddrInet4: + ifa := &IPAddr{IP: make(IP, IPv4len)} + copy(ifa.IP, sav.Addr[:]) + ifat = append(ifat, ifa) + case *syscall.SockaddrInet6: + ifa := &IPAddr{IP: make(IP, IPv6len)} + copy(ifa.IP, sav.Addr[:]) + ifat = append(ifat, ifa) + } + } + } + } + } + + return ifat, nil } diff --git a/libgo/go/net/internal/socktest/main_test.go b/libgo/go/net/internal/socktest/main_test.go new file mode 100644 index 00000000000..60e581f463c --- /dev/null +++ b/libgo/go/net/internal/socktest/main_test.go @@ -0,0 +1,56 @@ +// Copyright 2015 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 !plan9 + +package socktest_test + +import ( + "net/internal/socktest" + "os" + "sync" + "syscall" + "testing" +) + +var sw socktest.Switch + +func TestMain(m *testing.M) { + installTestHooks() + + st := m.Run() + + for s := range sw.Sockets() { + closeFunc(s) + } + uninstallTestHooks() + os.Exit(st) +} + +func TestSwitch(t *testing.T) { + const N = 10 + var wg sync.WaitGroup + wg.Add(N) + for i := 0; i < N; i++ { + go func() { + defer wg.Done() + for _, family := range []int{syscall.AF_INET, syscall.AF_INET6} { + socketFunc(family, syscall.SOCK_STREAM, syscall.IPPROTO_TCP) + } + }() + } + wg.Wait() +} + +func TestSocket(t *testing.T) { + for _, f := range []socktest.Filter{ + func(st *socktest.Status) (socktest.AfterFilter, error) { return nil, nil }, + nil, + } { + sw.Set(socktest.FilterSocket, f) + for _, family := range []int{syscall.AF_INET, syscall.AF_INET6} { + socketFunc(family, syscall.SOCK_STREAM, syscall.IPPROTO_TCP) + } + } +} diff --git a/libgo/go/net/internal/socktest/main_unix_test.go b/libgo/go/net/internal/socktest/main_unix_test.go new file mode 100644 index 00000000000..b8eebc2aa42 --- /dev/null +++ b/libgo/go/net/internal/socktest/main_unix_test.go @@ -0,0 +1,24 @@ +// Copyright 2015 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 !plan9,!windows + +package socktest_test + +import "syscall" + +var ( + socketFunc func(int, int, int) (int, error) + closeFunc func(int) error +) + +func installTestHooks() { + socketFunc = sw.Socket + closeFunc = sw.Close +} + +func uninstallTestHooks() { + socketFunc = syscall.Socket + closeFunc = syscall.Close +} diff --git a/libgo/go/net/internal/socktest/main_windows_test.go b/libgo/go/net/internal/socktest/main_windows_test.go new file mode 100644 index 00000000000..df1cb97784b --- /dev/null +++ b/libgo/go/net/internal/socktest/main_windows_test.go @@ -0,0 +1,22 @@ +// Copyright 2015 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 socktest_test + +import "syscall" + +var ( + socketFunc func(int, int, int) (syscall.Handle, error) + closeFunc func(syscall.Handle) error +) + +func installTestHooks() { + socketFunc = sw.Socket + closeFunc = sw.Closesocket +} + +func uninstallTestHooks() { + socketFunc = syscall.Socket + closeFunc = syscall.Closesocket +} diff --git a/libgo/go/net/internal/socktest/switch.go b/libgo/go/net/internal/socktest/switch.go new file mode 100644 index 00000000000..4e38c7a85f3 --- /dev/null +++ b/libgo/go/net/internal/socktest/switch.go @@ -0,0 +1,169 @@ +// Copyright 2015 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 socktest provides utilities for socket testing. +package socktest + +import ( + "fmt" + "sync" +) + +// A Switch represents a callpath point switch for socket system +// calls. +type Switch struct { + once sync.Once + + fmu sync.RWMutex + fltab map[FilterType]Filter + + smu sync.RWMutex + sotab Sockets + stats stats +} + +func (sw *Switch) init() { + sw.fltab = make(map[FilterType]Filter) + sw.sotab = make(Sockets) + sw.stats = make(stats) +} + +// Stats returns a list of per-cookie socket statistics. +func (sw *Switch) Stats() []Stat { + var st []Stat + sw.smu.RLock() + for _, s := range sw.stats { + ns := *s + st = append(st, ns) + } + sw.smu.RUnlock() + return st +} + +// Sockets returns mappings of socket descriptor to socket status. +func (sw *Switch) Sockets() Sockets { + sw.smu.RLock() + tab := make(Sockets, len(sw.sotab)) + for i, s := range sw.sotab { + tab[i] = s + } + sw.smu.RUnlock() + return tab +} + +// A Cookie represents a 3-tuple of a socket; address family, socket +// type and protocol number. +type Cookie uint64 + +// Family returns an address family. +func (c Cookie) Family() int { return int(c >> 48) } + +// Type returns a socket type. +func (c Cookie) Type() int { return int(c << 16 >> 32) } + +// Protocol returns a protocol number. +func (c Cookie) Protocol() int { return int(c & 0xff) } + +func cookie(family, sotype, proto int) Cookie { + return Cookie(family)<<48 | Cookie(sotype)&0xffffffff<<16 | Cookie(proto)&0xff +} + +// A Status represents the status of a socket. +type Status struct { + Cookie Cookie + Err error // error status of socket system call + SocketErr error // error status of socket by SO_ERROR +} + +func (so Status) String() string { + return fmt.Sprintf("(%s, %s, %s): syscallerr=%v, socketerr=%v", familyString(so.Cookie.Family()), typeString(so.Cookie.Type()), protocolString(so.Cookie.Protocol()), so.Err, so.SocketErr) +} + +// A Stat represents a per-cookie socket statistics. +type Stat struct { + Family int // address family + Type int // socket type + Protocol int // protocol number + + Opened uint64 // number of sockets opened + Connected uint64 // number of sockets connected + Listened uint64 // number of sockets listened + Accepted uint64 // number of sockets accepted + Closed uint64 // number of sockets closed + + OpenFailed uint64 // number of sockets open failed + ConnectFailed uint64 // number of sockets connect failed + ListenFailed uint64 // number of sockets listen failed + AcceptFailed uint64 // number of sockets accept failed + CloseFailed uint64 // number of sockets close failed +} + +func (st Stat) String() string { + return fmt.Sprintf("(%s, %s, %s): opened=%d, connected=%d, listened=%d, accepted=%d, closed=%d, openfailed=%d, connectfailed=%d, listenfailed=%d, acceptfailed=%d, closefailed=%d", familyString(st.Family), typeString(st.Type), protocolString(st.Protocol), st.Opened, st.Connected, st.Listened, st.Accepted, st.Closed, st.OpenFailed, st.ConnectFailed, st.ListenFailed, st.AcceptFailed, st.CloseFailed) +} + +type stats map[Cookie]*Stat + +func (st stats) getLocked(c Cookie) *Stat { + s, ok := st[c] + if !ok { + s = &Stat{Family: c.Family(), Type: c.Type(), Protocol: c.Protocol()} + st[c] = s + } + return s +} + +// A FilterType represents a filter type. +type FilterType int + +const ( + FilterSocket FilterType = iota // for Socket + FilterConnect // for Connect or ConnectEx + FilterListen // for Listen + FilterAccept // for Accept or Accept4 + FilterGetsockoptInt // for GetsockoptInt + FilterClose // for Close or Closesocket +) + +// A Filter represents a socket system call filter. +// +// It will only be executed before a system call for a socket that has +// an entry in internal table. +// If the filter returns a non-nil error, the execution of system call +// will be canceled and the system call function returns the non-nil +// error. +// It can return a non-nil AfterFilter for filtering after the +// execution of the system call. +type Filter func(*Status) (AfterFilter, error) + +func (f Filter) apply(st *Status) (AfterFilter, error) { + if f == nil { + return nil, nil + } + return f(st) +} + +// An AfterFilter represents a socket system call filter after an +// execution of a system call. +// +// It will only be executed after a system call for a socket that has +// an entry in internal table. +// If the filter returns a non-nil error, the system call function +// returns the non-nil error. +type AfterFilter func(*Status) error + +func (f AfterFilter) apply(st *Status) error { + if f == nil { + return nil + } + return f(st) +} + +// Set deploys the socket system call filter f for the filter type t. +func (sw *Switch) Set(t FilterType, f Filter) { + sw.once.Do(sw.init) + sw.fmu.Lock() + sw.fltab[t] = f + sw.fmu.Unlock() +} diff --git a/libgo/go/net/internal/socktest/switch_posix.go b/libgo/go/net/internal/socktest/switch_posix.go new file mode 100644 index 00000000000..863edef0d35 --- /dev/null +++ b/libgo/go/net/internal/socktest/switch_posix.go @@ -0,0 +1,58 @@ +// Copyright 2015 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 !plan9 + +package socktest + +import ( + "fmt" + "syscall" +) + +func familyString(family int) string { + switch family { + case syscall.AF_INET: + return "inet4" + case syscall.AF_INET6: + return "inet6" + case syscall.AF_UNIX: + return "local" + default: + return fmt.Sprintf("%d", family) + } +} + +func typeString(sotype int) string { + var s string + switch sotype & 0xff { + case syscall.SOCK_STREAM: + s = "stream" + case syscall.SOCK_DGRAM: + s = "datagram" + case syscall.SOCK_RAW: + s = "raw" + case syscall.SOCK_SEQPACKET: + s = "seqpacket" + default: + s = fmt.Sprintf("%d", sotype&0xff) + } + if flags := uint(sotype) & ^uint(0xff); flags != 0 { + s += fmt.Sprintf("|%#x", flags) + } + return s +} + +func protocolString(proto int) string { + switch proto { + case 0: + return "default" + case syscall.IPPROTO_TCP: + return "tcp" + case syscall.IPPROTO_UDP: + return "udp" + default: + return fmt.Sprintf("%d", proto) + } +} diff --git a/libgo/go/net/internal/socktest/switch_stub.go b/libgo/go/net/internal/socktest/switch_stub.go new file mode 100644 index 00000000000..28ce72cb855 --- /dev/null +++ b/libgo/go/net/internal/socktest/switch_stub.go @@ -0,0 +1,16 @@ +// Copyright 2015 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 plan9 + +package socktest + +// Sockets maps a socket descriptor to the status of socket. +type Sockets map[int]Status + +func familyString(family int) string { return "" } + +func typeString(sotype int) string { return "" } + +func protocolString(proto int) string { return "" } diff --git a/libgo/go/net/internal/socktest/switch_unix.go b/libgo/go/net/internal/socktest/switch_unix.go new file mode 100644 index 00000000000..14c0c228a2f --- /dev/null +++ b/libgo/go/net/internal/socktest/switch_unix.go @@ -0,0 +1,29 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris + +package socktest + +// Sockets maps a socket descriptor to the status of socket. +type Sockets map[int]Status + +func (sw *Switch) sockso(s int) *Status { + sw.smu.RLock() + defer sw.smu.RUnlock() + so, ok := sw.sotab[s] + if !ok { + return nil + } + return &so +} + +// addLocked returns a new Status without locking. +// sw.smu must be held before call. +func (sw *Switch) addLocked(s, family, sotype, proto int) *Status { + sw.once.Do(sw.init) + so := Status{Cookie: cookie(family, sotype, proto)} + sw.sotab[s] = so + return &so +} diff --git a/libgo/go/net/internal/socktest/switch_windows.go b/libgo/go/net/internal/socktest/switch_windows.go new file mode 100644 index 00000000000..4f1d597a27a --- /dev/null +++ b/libgo/go/net/internal/socktest/switch_windows.go @@ -0,0 +1,29 @@ +// Copyright 2015 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 socktest + +import "syscall" + +// Sockets maps a socket descriptor to the status of socket. +type Sockets map[syscall.Handle]Status + +func (sw *Switch) sockso(s syscall.Handle) *Status { + sw.smu.RLock() + defer sw.smu.RUnlock() + so, ok := sw.sotab[s] + if !ok { + return nil + } + return &so +} + +// addLocked returns a new Status without locking. +// sw.smu must be held before call. +func (sw *Switch) addLocked(s syscall.Handle, family, sotype, proto int) *Status { + sw.once.Do(sw.init) + so := Status{Cookie: cookie(family, sotype, proto)} + sw.sotab[s] = so + return &so +} diff --git a/libgo/go/net/internal/socktest/sys_cloexec.go b/libgo/go/net/internal/socktest/sys_cloexec.go new file mode 100644 index 00000000000..340ff071e7e --- /dev/null +++ b/libgo/go/net/internal/socktest/sys_cloexec.go @@ -0,0 +1,42 @@ +// Copyright 2015 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 freebsd linux + +package socktest + +import "syscall" + +// Accept4 wraps syscall.Accept4. +func (sw *Switch) Accept4(s, flags int) (ns int, sa syscall.Sockaddr, err error) { + so := sw.sockso(s) + if so == nil { + return syscall.Accept4(s, flags) + } + sw.fmu.RLock() + f, _ := sw.fltab[FilterAccept] + sw.fmu.RUnlock() + + af, err := f.apply(so) + if err != nil { + return -1, nil, err + } + ns, sa, so.Err = syscall.Accept4(s, flags) + if err = af.apply(so); err != nil { + if so.Err == nil { + syscall.Close(ns) + } + return -1, nil, err + } + + sw.smu.Lock() + defer sw.smu.Unlock() + if so.Err != nil { + sw.stats.getLocked(so.Cookie).AcceptFailed++ + return -1, nil, so.Err + } + nso := sw.addLocked(ns, so.Cookie.Family(), so.Cookie.Type(), so.Cookie.Protocol()) + sw.stats.getLocked(nso.Cookie).Accepted++ + return ns, sa, nil +} diff --git a/libgo/go/net/internal/socktest/sys_unix.go b/libgo/go/net/internal/socktest/sys_unix.go new file mode 100644 index 00000000000..f983e266f16 --- /dev/null +++ b/libgo/go/net/internal/socktest/sys_unix.go @@ -0,0 +1,193 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris + +package socktest + +import "syscall" + +// Socket wraps syscall.Socket. +func (sw *Switch) Socket(family, sotype, proto int) (s int, err error) { + sw.once.Do(sw.init) + + so := &Status{Cookie: cookie(family, sotype, proto)} + sw.fmu.RLock() + f, _ := sw.fltab[FilterSocket] + sw.fmu.RUnlock() + + af, err := f.apply(so) + if err != nil { + return -1, err + } + s, so.Err = syscall.Socket(family, sotype, proto) + if err = af.apply(so); err != nil { + if so.Err == nil { + syscall.Close(s) + } + return -1, err + } + + sw.smu.Lock() + defer sw.smu.Unlock() + if so.Err != nil { + sw.stats.getLocked(so.Cookie).OpenFailed++ + return -1, so.Err + } + nso := sw.addLocked(s, family, sotype, proto) + sw.stats.getLocked(nso.Cookie).Opened++ + return s, nil +} + +// Close wraps syscall.Close. +func (sw *Switch) Close(s int) (err error) { + so := sw.sockso(s) + if so == nil { + return syscall.Close(s) + } + sw.fmu.RLock() + f, _ := sw.fltab[FilterClose] + sw.fmu.RUnlock() + + af, err := f.apply(so) + if err != nil { + return err + } + so.Err = syscall.Close(s) + if err = af.apply(so); err != nil { + return err + } + + sw.smu.Lock() + defer sw.smu.Unlock() + if so.Err != nil { + sw.stats.getLocked(so.Cookie).CloseFailed++ + return so.Err + } + delete(sw.sotab, s) + sw.stats.getLocked(so.Cookie).Closed++ + return nil +} + +// Connect wraps syscall.Connect. +func (sw *Switch) Connect(s int, sa syscall.Sockaddr) (err error) { + so := sw.sockso(s) + if so == nil { + return syscall.Connect(s, sa) + } + sw.fmu.RLock() + f, _ := sw.fltab[FilterConnect] + sw.fmu.RUnlock() + + af, err := f.apply(so) + if err != nil { + return err + } + so.Err = syscall.Connect(s, sa) + if err = af.apply(so); err != nil { + return err + } + + sw.smu.Lock() + defer sw.smu.Unlock() + if so.Err != nil { + sw.stats.getLocked(so.Cookie).ConnectFailed++ + return so.Err + } + sw.stats.getLocked(so.Cookie).Connected++ + return nil +} + +// Listen wraps syscall.Listen. +func (sw *Switch) Listen(s, backlog int) (err error) { + so := sw.sockso(s) + if so == nil { + return syscall.Listen(s, backlog) + } + sw.fmu.RLock() + f, _ := sw.fltab[FilterListen] + sw.fmu.RUnlock() + + af, err := f.apply(so) + if err != nil { + return err + } + so.Err = syscall.Listen(s, backlog) + if err = af.apply(so); err != nil { + return err + } + + sw.smu.Lock() + defer sw.smu.Unlock() + if so.Err != nil { + sw.stats.getLocked(so.Cookie).ListenFailed++ + return so.Err + } + sw.stats.getLocked(so.Cookie).Listened++ + return nil +} + +// Accept wraps syscall.Accept. +func (sw *Switch) Accept(s int) (ns int, sa syscall.Sockaddr, err error) { + so := sw.sockso(s) + if so == nil { + return syscall.Accept(s) + } + sw.fmu.RLock() + f, _ := sw.fltab[FilterAccept] + sw.fmu.RUnlock() + + af, err := f.apply(so) + if err != nil { + return -1, nil, err + } + ns, sa, so.Err = syscall.Accept(s) + if err = af.apply(so); err != nil { + if so.Err == nil { + syscall.Close(ns) + } + return -1, nil, err + } + + sw.smu.Lock() + defer sw.smu.Unlock() + if so.Err != nil { + sw.stats.getLocked(so.Cookie).AcceptFailed++ + return -1, nil, so.Err + } + nso := sw.addLocked(ns, so.Cookie.Family(), so.Cookie.Type(), so.Cookie.Protocol()) + sw.stats.getLocked(nso.Cookie).Accepted++ + return ns, sa, nil +} + +// GetsockoptInt wraps syscall.GetsockoptInt. +func (sw *Switch) GetsockoptInt(s, level, opt int) (soerr int, err error) { + so := sw.sockso(s) + if so == nil { + return syscall.GetsockoptInt(s, level, opt) + } + sw.fmu.RLock() + f, _ := sw.fltab[FilterGetsockoptInt] + sw.fmu.RUnlock() + + af, err := f.apply(so) + if err != nil { + return -1, err + } + soerr, so.Err = syscall.GetsockoptInt(s, level, opt) + so.SocketErr = syscall.Errno(soerr) + if err = af.apply(so); err != nil { + return -1, err + } + + if so.Err != nil { + return -1, so.Err + } + if opt == syscall.SO_ERROR && (so.SocketErr == syscall.Errno(0) || so.SocketErr == syscall.EISCONN) { + sw.smu.Lock() + sw.stats.getLocked(so.Cookie).Connected++ + sw.smu.Unlock() + } + return soerr, nil +} diff --git a/libgo/go/net/internal/socktest/sys_windows.go b/libgo/go/net/internal/socktest/sys_windows.go new file mode 100644 index 00000000000..e61bf2be605 --- /dev/null +++ b/libgo/go/net/internal/socktest/sys_windows.go @@ -0,0 +1,156 @@ +// Copyright 2015 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 socktest + +import "syscall" + +// Socket wraps syscall.Socket. +func (sw *Switch) Socket(family, sotype, proto int) (s syscall.Handle, err error) { + sw.once.Do(sw.init) + + so := &Status{Cookie: cookie(family, sotype, proto)} + sw.fmu.RLock() + f, _ := sw.fltab[FilterSocket] + sw.fmu.RUnlock() + + af, err := f.apply(so) + if err != nil { + return syscall.InvalidHandle, err + } + s, so.Err = syscall.Socket(family, sotype, proto) + if err = af.apply(so); err != nil { + if so.Err == nil { + syscall.Closesocket(s) + } + return syscall.InvalidHandle, err + } + + sw.smu.Lock() + defer sw.smu.Unlock() + if so.Err != nil { + sw.stats.getLocked(so.Cookie).OpenFailed++ + return syscall.InvalidHandle, so.Err + } + nso := sw.addLocked(s, family, sotype, proto) + sw.stats.getLocked(nso.Cookie).Opened++ + return s, nil +} + +// Closesocket wraps syscall.Closesocket. +func (sw *Switch) Closesocket(s syscall.Handle) (err error) { + so := sw.sockso(s) + if so == nil { + return syscall.Closesocket(s) + } + sw.fmu.RLock() + f, _ := sw.fltab[FilterClose] + sw.fmu.RUnlock() + + af, err := f.apply(so) + if err != nil { + return err + } + so.Err = syscall.Closesocket(s) + if err = af.apply(so); err != nil { + return err + } + + sw.smu.Lock() + defer sw.smu.Unlock() + if so.Err != nil { + sw.stats.getLocked(so.Cookie).CloseFailed++ + return so.Err + } + delete(sw.sotab, s) + sw.stats.getLocked(so.Cookie).Closed++ + return nil +} + +// Connect wraps syscall.Connect. +func (sw *Switch) Connect(s syscall.Handle, sa syscall.Sockaddr) (err error) { + so := sw.sockso(s) + if so == nil { + return syscall.Connect(s, sa) + } + sw.fmu.RLock() + f, _ := sw.fltab[FilterConnect] + sw.fmu.RUnlock() + + af, err := f.apply(so) + if err != nil { + return err + } + so.Err = syscall.Connect(s, sa) + if err = af.apply(so); err != nil { + return err + } + + sw.smu.Lock() + defer sw.smu.Unlock() + if so.Err != nil { + sw.stats.getLocked(so.Cookie).ConnectFailed++ + return so.Err + } + sw.stats.getLocked(so.Cookie).Connected++ + return nil +} + +// ConnectEx wraps syscall.ConnectEx. +func (sw *Switch) ConnectEx(s syscall.Handle, sa syscall.Sockaddr, b *byte, n uint32, nwr *uint32, o *syscall.Overlapped) (err error) { + so := sw.sockso(s) + if so == nil { + return syscall.ConnectEx(s, sa, b, n, nwr, o) + } + sw.fmu.RLock() + f, _ := sw.fltab[FilterConnect] + sw.fmu.RUnlock() + + af, err := f.apply(so) + if err != nil { + return err + } + so.Err = syscall.ConnectEx(s, sa, b, n, nwr, o) + if err = af.apply(so); err != nil { + return err + } + + sw.smu.Lock() + defer sw.smu.Unlock() + if so.Err != nil { + sw.stats.getLocked(so.Cookie).ConnectFailed++ + return so.Err + } + sw.stats.getLocked(so.Cookie).Connected++ + return nil +} + +// Listen wraps syscall.Listen. +func (sw *Switch) Listen(s syscall.Handle, backlog int) (err error) { + so := sw.sockso(s) + if so == nil { + return syscall.Listen(s, backlog) + } + sw.fmu.RLock() + f, _ := sw.fltab[FilterListen] + sw.fmu.RUnlock() + + af, err := f.apply(so) + if err != nil { + return err + } + so.Err = syscall.Listen(s, backlog) + if err = af.apply(so); err != nil { + return err + } + + sw.smu.Lock() + defer sw.smu.Unlock() + if so.Err != nil { + sw.stats.getLocked(so.Cookie).ListenFailed++ + return so.Err + } + sw.stats.getLocked(so.Cookie).Listened++ + return nil +} diff --git a/libgo/go/net/ip.go b/libgo/go/net/ip.go index 4a93e97b39d..cc004d60729 100644 --- a/libgo/go/net/ip.go +++ b/libgo/go/net/ip.go @@ -12,8 +12,6 @@ package net -import "errors" - // IP address lengths (bytes). const ( IPv4len = 4 @@ -108,58 +106,57 @@ var ( IPv6linklocalallrouters = IP{0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x02} ) -// IsUnspecified returns true if ip is an unspecified address. +// IsUnspecified reports whether ip is an unspecified address. func (ip IP) IsUnspecified() bool { - if ip.Equal(IPv4zero) || ip.Equal(IPv6unspecified) { - return true - } - return false + return ip.Equal(IPv4zero) || ip.Equal(IPv6unspecified) } -// IsLoopback returns true if ip is a loopback address. +// IsLoopback reports whether ip is a loopback address. func (ip IP) IsLoopback() bool { - if ip4 := ip.To4(); ip4 != nil && ip4[0] == 127 { - return true + if ip4 := ip.To4(); ip4 != nil { + return ip4[0] == 127 } return ip.Equal(IPv6loopback) } -// IsMulticast returns true if ip is a multicast address. +// IsMulticast reports whether ip is a multicast address. func (ip IP) IsMulticast() bool { - if ip4 := ip.To4(); ip4 != nil && ip4[0]&0xf0 == 0xe0 { - return true + if ip4 := ip.To4(); ip4 != nil { + return ip4[0]&0xf0 == 0xe0 } - return ip[0] == 0xff + return len(ip) == IPv6len && ip[0] == 0xff } -// IsInterfaceLinkLocalMulticast returns true if ip is +// IsInterfaceLocalMulticast reports whether ip is // an interface-local multicast address. func (ip IP) IsInterfaceLocalMulticast() bool { return len(ip) == IPv6len && ip[0] == 0xff && ip[1]&0x0f == 0x01 } -// IsLinkLocalMulticast returns true if ip is a link-local +// IsLinkLocalMulticast reports whether ip is a link-local // multicast address. func (ip IP) IsLinkLocalMulticast() bool { - if ip4 := ip.To4(); ip4 != nil && ip4[0] == 224 && ip4[1] == 0 && ip4[2] == 0 { - return true + if ip4 := ip.To4(); ip4 != nil { + return ip4[0] == 224 && ip4[1] == 0 && ip4[2] == 0 } - return ip[0] == 0xff && ip[1]&0x0f == 0x02 + return len(ip) == IPv6len && ip[0] == 0xff && ip[1]&0x0f == 0x02 } -// IsLinkLocalUnicast returns true if ip is a link-local +// IsLinkLocalUnicast reports whether ip is a link-local // unicast address. func (ip IP) IsLinkLocalUnicast() bool { - if ip4 := ip.To4(); ip4 != nil && ip4[0] == 169 && ip4[1] == 254 { - return true + if ip4 := ip.To4(); ip4 != nil { + return ip4[0] == 169 && ip4[1] == 254 } - return ip[0] == 0xfe && ip[1]&0xc0 == 0x80 + return len(ip) == IPv6len && ip[0] == 0xfe && ip[1]&0xc0 == 0x80 } -// IsGlobalUnicast returns true if ip is a global unicast +// IsGlobalUnicast reports whether ip is a global unicast // address. func (ip IP) IsGlobalUnicast() bool { - return !ip.IsUnspecified() && + return (len(ip) == IPv4len || len(ip) == IPv6len) && + !ip.Equal(IPv4bcast) && + !ip.IsUnspecified() && !ip.IsLoopback() && !ip.IsMulticast() && !ip.IsLinkLocalUnicast() @@ -267,10 +264,10 @@ func (ip IP) String() string { // If IPv4, use dotted notation. if p4 := p.To4(); len(p4) == IPv4len { - return itod(uint(p4[0])) + "." + - itod(uint(p4[1])) + "." + - itod(uint(p4[2])) + "." + - itod(uint(p4[3])) + return uitoa(uint(p4[0])) + "." + + uitoa(uint(p4[1])) + "." + + uitoa(uint(p4[2])) + "." + + uitoa(uint(p4[3])) } if len(p) != IPv6len { return "?" @@ -331,7 +328,7 @@ func (ip IP) MarshalText() ([]byte, error) { return []byte(""), nil } if len(ip) != IPv4len && len(ip) != IPv6len { - return nil, errors.New("invalid IP address") + return nil, &AddrError{Err: "invalid IP address", Addr: ip.String()} } return []byte(ip.String()), nil } @@ -346,13 +343,13 @@ func (ip *IP) UnmarshalText(text []byte) error { s := string(text) x := ParseIP(s) if x == nil { - return &ParseError{"IP address", s} + return &ParseError{Type: "IP address", Text: s} } *ip = x return nil } -// Equal returns true if ip and x are the same IP address. +// Equal reports whether ip and x are the same IP address. // An IPv4 address and that same address in IPv6 form are // considered to be equal. func (ip IP) Equal(x IP) bool { @@ -491,7 +488,7 @@ func (n *IPNet) String() string { if l == -1 { return nn.String() + "/" + m.String() } - return nn.String() + "/" + itod(uint(l)) + return nn.String() + "/" + uitoa(uint(l)) } // Parse IPv4 address (d.d.d.d). @@ -633,16 +630,6 @@ func parseIPv6(s string, zoneAllowed bool) (ip IP, zone string) { return ip, zone } -// A ParseError represents a malformed text string and the type of string that was expected. -type ParseError struct { - Type string - Text string -} - -func (e *ParseError) Error() string { - return "invalid " + e.Type + ": " + e.Text -} - // ParseIP parses s as an IP address, returning the result. // The string s can be in dotted decimal ("74.125.19.99") // or IPv6 ("2001:4860:0:2001::68") form. @@ -671,7 +658,7 @@ func ParseIP(s string) IP { func ParseCIDR(s string) (IP, *IPNet, error) { i := byteIndex(s, '/') if i < 0 { - return nil, nil, &ParseError{"CIDR address", s} + return nil, nil, &ParseError{Type: "CIDR address", Text: s} } addr, mask := s[:i], s[i+1:] iplen := IPv4len @@ -682,7 +669,7 @@ func ParseCIDR(s string) (IP, *IPNet, error) { } n, i, ok := dtoi(mask, 0) if ip == nil || !ok || i != len(mask) || n < 0 || n > 8*iplen { - return nil, nil, &ParseError{"CIDR address", s} + return nil, nil, &ParseError{Type: "CIDR address", Text: s} } m := CIDRMask(n, 8*iplen) return ip, &IPNet{IP: ip.Mask(m), Mask: m}, nil diff --git a/libgo/go/net/ip_test.go b/libgo/go/net/ip_test.go index 485ff51153b..3d95a73c097 100644 --- a/libgo/go/net/ip_test.go +++ b/libgo/go/net/ip_test.go @@ -16,12 +16,20 @@ var parseIPTests = []struct { }{ {"127.0.1.2", IPv4(127, 0, 1, 2)}, {"127.0.0.1", IPv4(127, 0, 0, 1)}, + {"127.001.002.003", IPv4(127, 1, 2, 3)}, + {"::ffff:127.1.2.3", IPv4(127, 1, 2, 3)}, + {"::ffff:127.001.002.003", IPv4(127, 1, 2, 3)}, + {"::ffff:7f01:0203", IPv4(127, 1, 2, 3)}, + {"0:0:0:0:0000:ffff:127.1.2.3", IPv4(127, 1, 2, 3)}, + {"0:0:0:0:000000:ffff:127.1.2.3", IPv4(127, 1, 2, 3)}, + {"0:0:0:0::ffff:127.1.2.3", IPv4(127, 1, 2, 3)}, + + {"2001:4860:0:2001::68", IP{0x20, 0x01, 0x48, 0x60, 0, 0, 0x20, 0x01, 0, 0, 0, 0, 0, 0, 0x00, 0x68}}, + {"2001:4860:0000:2001:0000:0000:0000:0068", IP{0x20, 0x01, 0x48, 0x60, 0, 0, 0x20, 0x01, 0, 0, 0, 0, 0, 0, 0x00, 0x68}}, + {"127.0.0.256", nil}, {"abc", nil}, {"123:", nil}, - {"::ffff:127.0.0.1", IPv4(127, 0, 0, 1)}, - {"2001:4860:0:2001::68", IP{0x20, 0x01, 0x48, 0x60, 0, 0, 0x20, 0x01, 0, 0, 0, 0, 0, 0, 0x00, 0x68}}, - {"::ffff:4a7d:1363", IPv4(74, 125, 19, 99)}, {"fe80::1%lo0", nil}, {"fe80::1%911", nil}, {"", nil}, @@ -44,7 +52,52 @@ func TestParseIP(t *testing.T) { } } +func TestLookupWithIP(t *testing.T) { + _, err := LookupIP("") + if err == nil { + t.Errorf(`LookupIP("") succeeded, should fail`) + } + _, err = LookupHost("") + if err == nil { + t.Errorf(`LookupIP("") succeeded, should fail`) + } + + // Test that LookupHost and LookupIP, which normally + // expect host names, work with IP addresses. + for _, tt := range parseIPTests { + if tt.out != nil { + addrs, err := LookupHost(tt.in) + if len(addrs) != 1 || addrs[0] != tt.in || err != nil { + t.Errorf("LookupHost(%q) = %v, %v, want %v, nil", tt.in, addrs, err, []string{tt.in}) + } + } else if !testing.Short() { + // We can't control what the host resolver does; if it can resolve, say, + // 127.0.0.256 or fe80::1%911 or a host named 'abc', who are we to judge? + // Warn about these discrepancies but don't fail the test. + addrs, err := LookupHost(tt.in) + if err == nil { + t.Logf("warning: LookupHost(%q) = %v, want error", tt.in, addrs) + } + } + + if tt.out != nil { + ips, err := LookupIP(tt.in) + if len(ips) != 1 || !reflect.DeepEqual(ips[0], tt.out) || err != nil { + t.Errorf("LookupIP(%q) = %v, %v, want %v, nil", tt.in, ips, err, []IP{tt.out}) + } + } else if !testing.Short() { + ips, err := LookupIP(tt.in) + // We can't control what the host resolver does. See above. + if err == nil { + t.Logf("warning: LookupIP(%q) = %v, want error", tt.in, ips) + } + } + } +} + func BenchmarkParseIP(b *testing.B) { + testHookUninstaller.Do(uninstallTestHooks) + for i := 0; i < b.N; i++ { for _, tt := range parseIPTests { ParseIP(tt.in) @@ -100,6 +153,8 @@ func TestIPString(t *testing.T) { } func BenchmarkIPString(b *testing.B) { + testHookUninstaller.Do(uninstallTestHooks) + for i := 0; i < b.N; i++ { for _, tt := range ipStringTests { if tt.in != nil { @@ -150,6 +205,8 @@ func TestIPMaskString(t *testing.T) { } func BenchmarkIPMaskString(b *testing.B) { + testHookUninstaller.Do(uninstallTestHooks) + for i := 0; i < b.N; i++ { for _, tt := range ipMaskStringTests { tt.in.String() @@ -180,10 +237,10 @@ var parseCIDRTests = []struct { {"abcd:2345::/24", ParseIP("abcd:2345::"), &IPNet{IP: ParseIP("abcd:2300::"), Mask: IPMask(ParseIP("ffff:ff00::"))}, nil}, {"2001:DB8::/48", ParseIP("2001:DB8::"), &IPNet{IP: ParseIP("2001:DB8::"), Mask: IPMask(ParseIP("ffff:ffff:ffff::"))}, nil}, {"2001:DB8::1/48", ParseIP("2001:DB8::1"), &IPNet{IP: ParseIP("2001:DB8::"), Mask: IPMask(ParseIP("ffff:ffff:ffff::"))}, nil}, - {"192.168.1.1/255.255.255.0", nil, nil, &ParseError{"CIDR address", "192.168.1.1/255.255.255.0"}}, - {"192.168.1.1/35", nil, nil, &ParseError{"CIDR address", "192.168.1.1/35"}}, - {"2001:db8::1/-1", nil, nil, &ParseError{"CIDR address", "2001:db8::1/-1"}}, - {"", nil, nil, &ParseError{"CIDR address", ""}}, + {"192.168.1.1/255.255.255.0", nil, nil, &ParseError{Type: "CIDR address", Text: "192.168.1.1/255.255.255.0"}}, + {"192.168.1.1/35", nil, nil, &ParseError{Type: "CIDR address", Text: "192.168.1.1/35"}}, + {"2001:db8::1/-1", nil, nil, &ParseError{Type: "CIDR address", Text: "2001:db8::1/-1"}}, + {"", nil, nil, &ParseError{Type: "CIDR address", Text: ""}}, } func TestParseCIDR(t *testing.T) { @@ -425,31 +482,44 @@ var ipAddrScopeTests = []struct { {IP.IsUnspecified, IPv4(127, 0, 0, 1), false}, {IP.IsUnspecified, IPv6unspecified, true}, {IP.IsUnspecified, IPv6interfacelocalallnodes, false}, + {IP.IsUnspecified, nil, false}, {IP.IsLoopback, IPv4(127, 0, 0, 1), true}, {IP.IsLoopback, IPv4(127, 255, 255, 254), true}, {IP.IsLoopback, IPv4(128, 1, 2, 3), false}, {IP.IsLoopback, IPv6loopback, true}, {IP.IsLoopback, IPv6linklocalallrouters, false}, + {IP.IsLoopback, nil, false}, {IP.IsMulticast, IPv4(224, 0, 0, 0), true}, {IP.IsMulticast, IPv4(239, 0, 0, 0), true}, {IP.IsMulticast, IPv4(240, 0, 0, 0), false}, {IP.IsMulticast, IPv6linklocalallnodes, true}, {IP.IsMulticast, IP{0xff, 0x05, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, true}, {IP.IsMulticast, IP{0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, false}, + {IP.IsMulticast, nil, false}, + {IP.IsInterfaceLocalMulticast, IPv4(224, 0, 0, 0), false}, + {IP.IsInterfaceLocalMulticast, IPv4(0xff, 0x01, 0, 0), false}, + {IP.IsInterfaceLocalMulticast, IPv6interfacelocalallnodes, true}, + {IP.IsInterfaceLocalMulticast, nil, false}, {IP.IsLinkLocalMulticast, IPv4(224, 0, 0, 0), true}, {IP.IsLinkLocalMulticast, IPv4(239, 0, 0, 0), false}, + {IP.IsLinkLocalMulticast, IPv4(0xff, 0x02, 0, 0), false}, {IP.IsLinkLocalMulticast, IPv6linklocalallrouters, true}, {IP.IsLinkLocalMulticast, IP{0xff, 0x05, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, false}, + {IP.IsLinkLocalMulticast, nil, false}, {IP.IsLinkLocalUnicast, IPv4(169, 254, 0, 0), true}, {IP.IsLinkLocalUnicast, IPv4(169, 255, 0, 0), false}, + {IP.IsLinkLocalUnicast, IPv4(0xfe, 0x80, 0, 0), false}, {IP.IsLinkLocalUnicast, IP{0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, true}, {IP.IsLinkLocalUnicast, IP{0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, false}, + {IP.IsLinkLocalUnicast, nil, false}, {IP.IsGlobalUnicast, IPv4(240, 0, 0, 0), true}, {IP.IsGlobalUnicast, IPv4(232, 0, 0, 0), false}, {IP.IsGlobalUnicast, IPv4(169, 254, 0, 0), false}, + {IP.IsGlobalUnicast, IPv4bcast, false}, {IP.IsGlobalUnicast, IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0x1, 0x23, 0, 0x12, 0, 0x1}, true}, {IP.IsGlobalUnicast, IP{0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, false}, {IP.IsGlobalUnicast, IP{0xff, 0x05, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, false}, + {IP.IsGlobalUnicast, nil, false}, } func name(f interface{}) string { @@ -461,5 +531,12 @@ func TestIPAddrScope(t *testing.T) { if ok := tt.scope(tt.in); ok != tt.ok { t.Errorf("%s(%q) = %v, want %v", name(tt.scope), tt.in, ok, tt.ok) } + ip := tt.in.To4() + if ip == nil { + continue + } + if ok := tt.scope(ip); ok != tt.ok { + t.Errorf("%s(%q) = %v, want %v", name(tt.scope), ip, ok, tt.ok) + } } } diff --git a/libgo/go/net/ipraw_test.go b/libgo/go/net/ipraw_test.go index 92dc8dc5694..5d86a9d0316 100644 --- a/libgo/go/net/ipraw_test.go +++ b/libgo/go/net/ipraw_test.go @@ -5,17 +5,18 @@ package net import ( - "bytes" - "fmt" - "os" "reflect" - "runtime" "testing" - "time" ) +// The full stack test cases for IPConn have been moved to the +// following: +// golang.org/x/net/ipv4 +// golang.org/x/net/ipv6 +// golang.org/x/net/icmp + type resolveIPAddrTest struct { - net string + network string litAddrOrName string addr *IPAddr err error @@ -37,210 +38,41 @@ var resolveIPAddrTests = []resolveIPAddrTest{ {"", "127.0.0.1", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil}, // Go 1.0 behavior {"", "::1", &IPAddr{IP: ParseIP("::1")}, nil}, // Go 1.0 behavior + {"ip4:icmp", "", &IPAddr{}, nil}, + {"l2tp", "127.0.0.1", nil, UnknownNetworkError("l2tp")}, {"l2tp:gre", "127.0.0.1", nil, UnknownNetworkError("l2tp:gre")}, {"tcp", "1.2.3.4:123", nil, UnknownNetworkError("tcp")}, } -func init() { - if ifi := loopbackInterface(); ifi != nil { - index := fmt.Sprintf("%v", ifi.Index) - resolveIPAddrTests = append(resolveIPAddrTests, []resolveIPAddrTest{ - {"ip6", "fe80::1%" + ifi.Name, &IPAddr{IP: ParseIP("fe80::1"), Zone: zoneToString(ifi.Index)}, nil}, - {"ip6", "fe80::1%" + index, &IPAddr{IP: ParseIP("fe80::1"), Zone: index}, nil}, - }...) - } - if ips, err := LookupIP("localhost"); err == nil && len(ips) > 1 && supportsIPv4 && supportsIPv6 { - resolveIPAddrTests = append(resolveIPAddrTests, []resolveIPAddrTest{ - {"ip", "localhost", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil}, - {"ip4", "localhost", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil}, - {"ip6", "localhost", &IPAddr{IP: IPv6loopback}, nil}, - }...) - } -} - -func skipRawSocketTest(t *testing.T) (skip bool, skipmsg string) { - skip, skipmsg, err := skipRawSocketTests() - if err != nil { - t.Fatal(err) - } - return skip, skipmsg -} - func TestResolveIPAddr(t *testing.T) { - switch runtime.GOOS { - case "nacl": - t.Skipf("skipping test on %q", runtime.GOOS) + if !testableNetwork("ip+nopriv") { + t.Skip("ip+nopriv test") } - for _, tt := range resolveIPAddrTests { - addr, err := ResolveIPAddr(tt.net, tt.litAddrOrName) + origTestHookLookupIP := testHookLookupIP + defer func() { testHookLookupIP = origTestHookLookupIP }() + testHookLookupIP = lookupLocalhost + + for i, tt := range resolveIPAddrTests { + addr, err := ResolveIPAddr(tt.network, tt.litAddrOrName) if err != tt.err { - t.Fatalf("ResolveIPAddr(%v, %v) failed: %v", tt.net, tt.litAddrOrName, err) + t.Errorf("#%d: %v", i, err) } else if !reflect.DeepEqual(addr, tt.addr) { - t.Fatalf("got %#v; expected %#v", addr, tt.addr) + t.Errorf("#%d: got %#v; want %#v", i, addr, tt.addr) } - } -} - -var icmpEchoTests = []struct { - net string - laddr string - raddr string -}{ - {"ip4:icmp", "0.0.0.0", "127.0.0.1"}, - {"ip6:ipv6-icmp", "::", "::1"}, -} - -func TestConnICMPEcho(t *testing.T) { - if skip, skipmsg := skipRawSocketTest(t); skip { - t.Skip(skipmsg) - } - - for i, tt := range icmpEchoTests { - net, _, err := parseNetwork(tt.net) if err != nil { - t.Fatalf("parseNetwork failed: %v", err) - } - if net == "ip6" && !supportsIPv6 { continue } - - c, err := Dial(tt.net, tt.raddr) - if err != nil { - t.Fatalf("Dial failed: %v", err) - } - c.SetDeadline(time.Now().Add(100 * time.Millisecond)) - defer c.Close() - - typ := icmpv4EchoRequest - if net == "ip6" { - typ = icmpv6EchoRequest - } - xid, xseq := os.Getpid()&0xffff, i+1 - wb, err := (&icmpMessage{ - Type: typ, Code: 0, - Body: &icmpEcho{ - ID: xid, Seq: xseq, - Data: bytes.Repeat([]byte("Go Go Gadget Ping!!!"), 3), - }, - }).Marshal() + rtaddr, err := ResolveIPAddr(addr.Network(), addr.String()) if err != nil { - t.Fatalf("icmpMessage.Marshal failed: %v", err) - } - if _, err := c.Write(wb); err != nil { - t.Fatalf("Conn.Write failed: %v", err) - } - var m *icmpMessage - rb := make([]byte, 20+len(wb)) - for { - if _, err := c.Read(rb); err != nil { - t.Fatalf("Conn.Read failed: %v", err) - } - if net == "ip4" { - rb = ipv4Payload(rb) - } - if m, err = parseICMPMessage(rb); err != nil { - t.Fatalf("parseICMPMessage failed: %v", err) - } - switch m.Type { - case icmpv4EchoRequest, icmpv6EchoRequest: - continue - } - break - } - switch p := m.Body.(type) { - case *icmpEcho: - if p.ID != xid || p.Seq != xseq { - t.Fatalf("got id=%v, seqnum=%v; expected id=%v, seqnum=%v", p.ID, p.Seq, xid, xseq) - } - default: - t.Fatalf("got type=%v, code=%v; expected type=%v, code=%v", m.Type, m.Code, typ, 0) + t.Errorf("#%d: %v", i, err) + } else if !reflect.DeepEqual(rtaddr, addr) { + t.Errorf("#%d: got %#v; want %#v", i, rtaddr, addr) } } } -func TestPacketConnICMPEcho(t *testing.T) { - if skip, skipmsg := skipRawSocketTest(t); skip { - t.Skip(skipmsg) - } - - for i, tt := range icmpEchoTests { - net, _, err := parseNetwork(tt.net) - if err != nil { - t.Fatalf("parseNetwork failed: %v", err) - } - if net == "ip6" && !supportsIPv6 { - continue - } - - c, err := ListenPacket(tt.net, tt.laddr) - if err != nil { - t.Fatalf("ListenPacket failed: %v", err) - } - c.SetDeadline(time.Now().Add(100 * time.Millisecond)) - defer c.Close() - - ra, err := ResolveIPAddr(tt.net, tt.raddr) - if err != nil { - t.Fatalf("ResolveIPAddr failed: %v", err) - } - typ := icmpv4EchoRequest - if net == "ip6" { - typ = icmpv6EchoRequest - } - xid, xseq := os.Getpid()&0xffff, i+1 - wb, err := (&icmpMessage{ - Type: typ, Code: 0, - Body: &icmpEcho{ - ID: xid, Seq: xseq, - Data: bytes.Repeat([]byte("Go Go Gadget Ping!!!"), 3), - }, - }).Marshal() - if err != nil { - t.Fatalf("icmpMessage.Marshal failed: %v", err) - } - if _, err := c.WriteTo(wb, ra); err != nil { - t.Fatalf("PacketConn.WriteTo failed: %v", err) - } - var m *icmpMessage - rb := make([]byte, 20+len(wb)) - for { - if _, _, err := c.ReadFrom(rb); err != nil { - t.Fatalf("PacketConn.ReadFrom failed: %v", err) - } - // See BUG section. - //if net == "ip4" { - // rb = ipv4Payload(rb) - //} - if m, err = parseICMPMessage(rb); err != nil { - t.Fatalf("parseICMPMessage failed: %v", err) - } - switch m.Type { - case icmpv4EchoRequest, icmpv6EchoRequest: - continue - } - break - } - switch p := m.Body.(type) { - case *icmpEcho: - if p.ID != xid || p.Seq != xseq { - t.Fatalf("got id=%v, seqnum=%v; expected id=%v, seqnum=%v", p.ID, p.Seq, xid, xseq) - } - default: - t.Fatalf("got type=%v, code=%v; expected type=%v, code=%v", m.Type, m.Code, typ, 0) - } - } -} - -func ipv4Payload(b []byte) []byte { - if len(b) < 20 { - return b - } - hdrlen := int(b[0]&0x0f) << 2 - return b[hdrlen:] -} - var ipConnLocalNameTests = []struct { net string laddr *IPAddr @@ -251,44 +83,34 @@ var ipConnLocalNameTests = []struct { } func TestIPConnLocalName(t *testing.T) { - switch runtime.GOOS { - case "nacl", "plan9", "windows": - t.Skipf("skipping test on %q", runtime.GOOS) - default: - if os.Getuid() != 0 { - t.Skip("skipping test; must be root") - } - } - for _, tt := range ipConnLocalNameTests { + if !testableNetwork(tt.net) { + t.Logf("skipping %s test", tt.net) + continue + } c, err := ListenIP(tt.net, tt.laddr) if err != nil { - t.Fatalf("ListenIP failed: %v", err) + t.Fatal(err) } defer c.Close() if la := c.LocalAddr(); la == nil { - t.Fatal("IPConn.LocalAddr failed") + t.Fatal("should not fail") } } } func TestIPConnRemoteName(t *testing.T) { - switch runtime.GOOS { - case "plan9", "windows": - t.Skipf("skipping test on %q", runtime.GOOS) - default: - if os.Getuid() != 0 { - t.Skip("skipping test; must be root") - } + if !testableNetwork("ip:tcp") { + t.Skip("ip:tcp test") } raddr := &IPAddr{IP: IPv4(127, 0, 0, 1).To4()} c, err := DialIP("ip:tcp", &IPAddr{IP: IPv4(127, 0, 0, 1)}, raddr) if err != nil { - t.Fatalf("DialIP failed: %v", err) + t.Fatal(err) } defer c.Close() if !reflect.DeepEqual(raddr, c.RemoteAddr()) { - t.Fatalf("got %#v, expected %#v", c.RemoteAddr(), raddr) + t.Fatalf("got %#v; want %#v", c.RemoteAddr(), raddr) } } diff --git a/libgo/go/net/iprawsock.go b/libgo/go/net/iprawsock.go index 5cc361390ff..f02df7fa8d1 100644 --- a/libgo/go/net/iprawsock.go +++ b/libgo/go/net/iprawsock.go @@ -17,13 +17,21 @@ func (a *IPAddr) String() string { if a == nil { return "" } + ip := ipEmptyString(a.IP) if a.Zone != "" { - return a.IP.String() + "%" + a.Zone + return ip + "%" + a.Zone } - return a.IP.String() + return ip } -func (a *IPAddr) toAddr() Addr { +func (a *IPAddr) isWildcard() bool { + if a == nil || a.IP == nil { + return true + } + return a.IP.IsUnspecified() +} + +func (a *IPAddr) opAddr() Addr { if a == nil { return nil } @@ -46,9 +54,9 @@ func ResolveIPAddr(net, addr string) (*IPAddr, error) { default: return nil, UnknownNetworkError(net) } - a, err := resolveInternetAddr(afnet, addr, noDeadline) + addrs, err := internetAddrList(afnet, addr, noDeadline) if err != nil { return nil, err } - return a.toAddr().(*IPAddr), nil + return addrs.first(isIPv4).(*IPAddr), nil } diff --git a/libgo/go/net/iprawsock_plan9.go b/libgo/go/net/iprawsock_plan9.go index e62d116b817..b027adc53a7 100644 --- a/libgo/go/net/iprawsock_plan9.go +++ b/libgo/go/net/iprawsock_plan9.go @@ -23,12 +23,12 @@ type IPConn struct { // Timeout() == true after a fixed time limit; see SetDeadline and // SetReadDeadline. func (c *IPConn) ReadFromIP(b []byte) (int, *IPAddr, error) { - return 0, nil, syscall.EPLAN9 + return 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9} } // ReadFrom implements the PacketConn ReadFrom method. func (c *IPConn) ReadFrom(b []byte) (int, Addr, error) { - return 0, nil, syscall.EPLAN9 + return 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9} } // ReadMsgIP reads a packet from c, copying the payload into b and the @@ -36,7 +36,7 @@ func (c *IPConn) ReadFrom(b []byte) (int, Addr, error) { // 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 *IPConn) ReadMsgIP(b, oob []byte) (n, oobn, flags int, addr *IPAddr, err error) { - return 0, 0, 0, nil, syscall.EPLAN9 + return 0, 0, 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9} } // WriteToIP writes an IP packet to addr via c, copying the payload @@ -47,19 +47,19 @@ func (c *IPConn) ReadMsgIP(b, oob []byte) (n, oobn, flags int, addr *IPAddr, err // SetWriteDeadline. On packet-oriented connections, write timeouts // are rare. func (c *IPConn) WriteToIP(b []byte, addr *IPAddr) (int, error) { - return 0, syscall.EPLAN9 + return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr.opAddr(), Err: syscall.EPLAN9} } // WriteTo implements the PacketConn WriteTo method. func (c *IPConn) WriteTo(b []byte, addr Addr) (int, error) { - return 0, syscall.EPLAN9 + return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr, Err: syscall.EPLAN9} } // WriteMsgIP 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 *IPConn) WriteMsgIP(b, oob []byte, addr *IPAddr) (n, oobn int, err error) { - return 0, 0, syscall.EPLAN9 + return 0, 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr.opAddr(), Err: syscall.EPLAN9} } // DialIP connects to the remote address raddr on the network protocol @@ -70,7 +70,7 @@ func DialIP(netProto string, laddr, raddr *IPAddr) (*IPConn, error) { } func dialIP(netProto string, laddr, raddr *IPAddr, deadline time.Time) (*IPConn, error) { - return nil, syscall.EPLAN9 + return nil, &OpError{Op: "dial", Net: netProto, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: syscall.EPLAN9} } // ListenIP listens for incoming IP packets addressed to the local @@ -78,5 +78,5 @@ func dialIP(netProto string, laddr, raddr *IPAddr, deadline time.Time) (*IPConn, // methods can be used to receive and send IP packets with per-packet // addressing. func ListenIP(netProto string, laddr *IPAddr) (*IPConn, error) { - return nil, syscall.EPLAN9 + return nil, &OpError{Op: "listen", Net: netProto, Source: nil, Addr: laddr.opAddr(), Err: syscall.EPLAN9} } diff --git a/libgo/go/net/iprawsock_posix.go b/libgo/go/net/iprawsock_posix.go index 99b081ba8c8..9417606ce94 100644 --- a/libgo/go/net/iprawsock_posix.go +++ b/libgo/go/net/iprawsock_posix.go @@ -43,13 +43,6 @@ 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) { if a == nil { return nil, nil @@ -83,24 +76,41 @@ func (c *IPConn) ReadFromIP(b []byte) (int, *IPAddr, error) { switch sa := sa.(type) { case *syscall.SockaddrInet4: addr = &IPAddr{IP: sa.Addr[0:]} - if len(b) >= IPv4len { // discard ipv4 header - hsize := (int(b[0]) & 0xf) * 4 - copy(b, b[hsize:]) - n -= hsize - } + n = stripIPv4Header(n, b) case *syscall.SockaddrInet6: addr = &IPAddr{IP: sa.Addr[0:], Zone: zoneToString(int(sa.ZoneId))} } + if err != nil { + err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } return n, addr, err } +func stripIPv4Header(n int, b []byte) int { + if len(b) < 20 { + return n + } + l := int(b[0]&0x0f) << 2 + if 20 > l || l > len(b) { + return n + } + if b[0]>>4 != 4 { + return n + } + copy(b, b[l:]) + return n - l +} + // ReadFrom implements the PacketConn ReadFrom method. func (c *IPConn) ReadFrom(b []byte) (int, Addr, error) { if !c.ok() { return 0, nil, syscall.EINVAL } n, addr, err := c.ReadFromIP(b) - return n, addr.toAddr(), err + if addr == nil { + return n, nil, err + } + return n, addr, err } // ReadMsgIP reads a packet from c, copying the payload into b and the @@ -119,6 +129,9 @@ func (c *IPConn) ReadMsgIP(b, oob []byte) (n, oobn, flags int, addr *IPAddr, err case *syscall.SockaddrInet6: addr = &IPAddr{IP: sa.Addr[0:], Zone: zoneToString(int(sa.ZoneId))} } + if err != nil { + err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } return } @@ -134,16 +147,20 @@ func (c *IPConn) WriteToIP(b []byte, addr *IPAddr) (int, error) { return 0, syscall.EINVAL } if c.fd.isConnected { - return 0, &OpError{Op: "write", Net: c.fd.net, Addr: addr, Err: ErrWriteToConnected} + return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: ErrWriteToConnected} } if addr == nil { - return 0, &OpError{Op: "write", Net: c.fd.net, Addr: nil, Err: errMissingAddress} + return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: nil, Err: errMissingAddress} } sa, err := addr.sockaddr(c.fd.family) if err != nil { - return 0, &OpError{"write", c.fd.net, addr, err} + return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err} + } + n, err := c.fd.writeTo(b, sa) + if err != nil { + err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err} } - return c.fd.writeTo(b, sa) + return n, err } // WriteTo implements the PacketConn WriteTo method. @@ -153,7 +170,7 @@ func (c *IPConn) WriteTo(b []byte, addr Addr) (int, error) { } a, ok := addr.(*IPAddr) if !ok { - return 0, &OpError{"write", c.fd.net, addr, syscall.EINVAL} + return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: syscall.EINVAL} } return c.WriteToIP(b, a) } @@ -166,16 +183,21 @@ func (c *IPConn) WriteMsgIP(b, oob []byte, addr *IPAddr) (n, oobn int, err error return 0, 0, syscall.EINVAL } if c.fd.isConnected { - return 0, 0, &OpError{Op: "write", Net: c.fd.net, Addr: addr, Err: ErrWriteToConnected} + return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: ErrWriteToConnected} } if addr == nil { - return 0, 0, &OpError{Op: "write", Net: c.fd.net, Addr: nil, Err: errMissingAddress} + return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: nil, Err: errMissingAddress} } - sa, err := addr.sockaddr(c.fd.family) + var sa syscall.Sockaddr + sa, err = addr.sockaddr(c.fd.family) if err != nil { - return 0, 0, &OpError{"write", c.fd.net, addr, err} + return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err} } - return c.fd.writeMsg(b, oob, sa) + n, oobn, err = c.fd.writeMsg(b, oob, sa) + if err != nil { + err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err} + } + return } // DialIP connects to the remote address raddr on the network protocol @@ -188,19 +210,19 @@ func DialIP(netProto string, laddr, raddr *IPAddr) (*IPConn, error) { func dialIP(netProto string, laddr, raddr *IPAddr, deadline time.Time) (*IPConn, error) { net, proto, err := parseNetwork(netProto) if err != nil { - return nil, &OpError{Op: "dial", Net: netProto, Addr: raddr, Err: err} + return nil, &OpError{Op: "dial", Net: netProto, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err} } switch net { case "ip", "ip4", "ip6": default: - return nil, &OpError{Op: "dial", Net: netProto, Addr: raddr, Err: UnknownNetworkError(netProto)} + return nil, &OpError{Op: "dial", Net: netProto, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(netProto)} } if raddr == nil { - return nil, &OpError{Op: "dial", Net: netProto, Addr: nil, Err: errMissingAddress} + return nil, &OpError{Op: "dial", Net: netProto, Source: laddr.opAddr(), Addr: nil, Err: errMissingAddress} } fd, err := internetSocket(net, laddr, raddr, deadline, syscall.SOCK_RAW, proto, "dial") if err != nil { - return nil, &OpError{Op: "dial", Net: netProto, Addr: raddr, Err: err} + return nil, &OpError{Op: "dial", Net: netProto, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err} } return newIPConn(fd), nil } @@ -212,16 +234,16 @@ func dialIP(netProto string, laddr, raddr *IPAddr, deadline time.Time) (*IPConn, func ListenIP(netProto string, laddr *IPAddr) (*IPConn, error) { net, proto, err := parseNetwork(netProto) if err != nil { - return nil, &OpError{Op: "dial", Net: netProto, Addr: laddr, Err: err} + return nil, &OpError{Op: "listen", Net: netProto, Source: nil, Addr: laddr.opAddr(), Err: err} } switch net { case "ip", "ip4", "ip6": default: - return nil, &OpError{Op: "listen", Net: netProto, Addr: laddr, Err: UnknownNetworkError(netProto)} + return nil, &OpError{Op: "listen", Net: netProto, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(netProto)} } fd, err := internetSocket(net, laddr, nil, noDeadline, syscall.SOCK_RAW, proto, "listen") if err != nil { - return nil, &OpError{Op: "listen", Net: netProto, Addr: laddr, Err: err} + return nil, &OpError{Op: "listen", Net: netProto, Source: nil, Addr: laddr.opAddr(), Err: err} } return newIPConn(fd), nil } diff --git a/libgo/go/net/ipsock.go b/libgo/go/net/ipsock.go index dda85780308..6e75c33d534 100644 --- a/libgo/go/net/ipsock.go +++ b/libgo/go/net/ipsock.go @@ -26,113 +26,82 @@ var ( supportsIPv4map bool ) -func init() { - sysInit() - supportsIPv4 = probeIPv4Stack() - supportsIPv6, supportsIPv4map = probeIPv6Stack() -} +// An addrList represents a list of network endpoint addresses. +type addrList []Addr -// A netaddr represents a network endpoint address or a list of -// network endpoint addresses. -type netaddr interface { - // toAddr returns the address represented in Addr interface. - // It returns a nil interface when the address is nil. - toAddr() Addr +// isIPv4 returns true if the Addr contains an IPv4 address. +func isIPv4(addr Addr) bool { + switch addr := addr.(type) { + case *TCPAddr: + return addr.IP.To4() != nil + case *UDPAddr: + return addr.IP.To4() != nil + case *IPAddr: + return addr.IP.To4() != nil + } + return false } -// An addrList represents a list of network endpoint addresses. -type addrList []netaddr +// first returns the first address which satisfies strategy, or if +// none do, then the first address of any kind. +func (addrs addrList) first(strategy func(Addr) bool) Addr { + for _, addr := range addrs { + if strategy(addr) { + return addr + } + } + return addrs[0] +} -func (al addrList) toAddr() Addr { - switch len(al) { - case 0: - return nil - case 1: - return al[0].toAddr() - default: - // For now, we'll roughly pick first one without - // considering dealing with any preferences such as - // DNS TTL, transport path quality, network routing - // information. - return al[0].toAddr() +// partition divides an address list into two categories, using a +// strategy function to assign a boolean label to each address. +// The first address, and any with a matching label, are returned as +// primaries, while addresses with the opposite label are returned +// as fallbacks. For non-empty inputs, primaries is guaranteed to be +// non-empty. +func (addrs addrList) partition(strategy func(Addr) bool) (primaries, fallbacks addrList) { + var primaryLabel bool + for i, addr := range addrs { + label := strategy(addr) + if i == 0 || label == primaryLabel { + primaryLabel = label + primaries = append(primaries, addr) + } else { + fallbacks = append(fallbacks, addr) + } } + return } var errNoSuitableAddress = errors.New("no suitable address found") -// firstFavoriteAddr returns an address or a list of addresses that -// implement the netaddr interface. Known filters are nil, ipv4only -// and ipv6only. It returns any address when filter is nil. The result -// contains at least one address when error is nil. -func firstFavoriteAddr(filter func(IP) IP, ips []IP, inetaddr func(IP) netaddr) (netaddr, error) { - if filter != nil { - return firstSupportedAddr(filter, ips, inetaddr) - } - var ( - ipv4, ipv6, swap bool - list addrList - ) +// filterAddrList applies a filter to a list of IP addresses, +// yielding a list of Addr objects. Known filters are nil, ipv4only, +// and ipv6only. It returns every address when the filter is nil. +// The result contains at least one address when error is nil. +func filterAddrList(filter func(IPAddr) bool, ips []IPAddr, inetaddr func(IPAddr) Addr) (addrList, error) { + var addrs addrList for _, ip := range ips { - // We'll take any IP address, but since the dialing - // code does not yet try multiple addresses - // effectively, prefer to use an IPv4 address if - // possible. This is especially relevant if localhost - // resolves to [ipv6-localhost, ipv4-localhost]. Too - // much code assumes localhost == ipv4-localhost. - if ip4 := ipv4only(ip); ip4 != nil && !ipv4 { - list = append(list, inetaddr(ip4)) - ipv4 = true - if ipv6 { - swap = true - } - } else if ip6 := ipv6only(ip); ip6 != nil && !ipv6 { - list = append(list, inetaddr(ip6)) - ipv6 = true - } - if ipv4 && ipv6 { - if swap { - list[0], list[1] = list[1], list[0] - } - break + if filter == nil || filter(ip) { + addrs = append(addrs, inetaddr(ip)) } } - switch len(list) { - case 0: + if len(addrs) == 0 { return nil, errNoSuitableAddress - case 1: - return list[0], nil - default: - return list, nil - } -} - -func firstSupportedAddr(filter func(IP) IP, ips []IP, inetaddr func(IP) netaddr) (netaddr, error) { - for _, ip := range ips { - if ip := filter(ip); ip != nil { - return inetaddr(ip), nil - } } - return nil, errNoSuitableAddress + return addrs, nil } -// ipv4only returns IPv4 addresses that we can use with the kernel's -// IPv4 addressing modes. If ip is an IPv4 address, ipv4only returns ip. -// Otherwise it returns nil. -func ipv4only(ip IP) IP { - if supportsIPv4 && ip.To4() != nil { - return ip - } - return nil +// ipv4only reports whether the kernel supports IPv4 addressing mode +// and addr is an IPv4 address. +func ipv4only(addr IPAddr) bool { + return supportsIPv4 && addr.IP.To4() != nil } -// ipv6only returns IPv6 addresses that we can use with the kernel's -// IPv6 addressing modes. It returns IPv4-mapped IPv6 addresses as -// nils and returns other IPv6 address types as IPv6 addresses. -func ipv6only(ip IP) IP { - if supportsIPv6 && len(ip) == IPv6len && ip.To4() == nil { - return ip - } - return nil +// ipv6only reports whether the kernel supports IPv6 addressing mode +// and addr is an IPv6 address except IPv4-mapped IPv6 address. +func ipv6only(addr IPAddr) bool { + return supportsIPv6 && len(addr.IP) == IPv6len && addr.IP.To4() == nil } // SplitHostPort splits a network address of the form "host:port", @@ -153,7 +122,7 @@ func SplitHostPort(hostport string) (host, port string, err error) { // Expect the first ']' just before the last ':'. end := byteIndex(hostport, ']') if end < 0 { - err = &AddrError{"missing ']' in address", hostport} + err = &AddrError{Err: "missing ']' in address", Addr: hostport} return } switch end + 1 { @@ -182,11 +151,11 @@ func SplitHostPort(hostport string) (host, port string, err error) { } } if byteIndex(hostport[j:], '[') >= 0 { - err = &AddrError{"unexpected '[' in address", hostport} + err = &AddrError{Err: "unexpected '[' in address", Addr: hostport} return } if byteIndex(hostport[k:], ']') >= 0 { - err = &AddrError{"unexpected ']' in address", hostport} + err = &AddrError{Err: "unexpected ']' in address", Addr: hostport} return } @@ -194,15 +163,15 @@ func SplitHostPort(hostport string) (host, port string, err error) { return missingPort: - err = &AddrError{"missing port in address", hostport} + err = &AddrError{Err: "missing port in address", Addr: hostport} return tooManyColons: - err = &AddrError{"too many colons in address", hostport} + err = &AddrError{Err: "too many colons in address", Addr: hostport} return missingBrackets: - err = &AddrError{"missing brackets in address", hostport} + err = &AddrError{Err: "missing brackets in address", Addr: hostport} return } @@ -228,17 +197,15 @@ func JoinHostPort(host, port string) string { return host + ":" + port } -// resolveInternetAddr resolves addr that is either a literal IP -// address or a DNS name and returns an internet protocol family -// address. It returns a list that contains a pair of different -// address family addresses when addr is a DNS name and the name has -// multiple address family records. The result contains at least one -// address when error is nil. -func resolveInternetAddr(net, addr string, deadline time.Time) (netaddr, error) { +// internetAddrList resolves addr, which may be a literal IP +// address or a DNS name, and returns a list of internet protocol +// family addresses. The result contains at least one address when +// error is nil. +func internetAddrList(net, addr string, deadline time.Time) (addrList, error) { var ( - err error - host, port, zone string - portnum int + err error + host, port string + portnum int ) switch net { case "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6": @@ -257,43 +224,43 @@ func resolveInternetAddr(net, addr string, deadline time.Time) (netaddr, error) default: return nil, UnknownNetworkError(net) } - inetaddr := func(ip IP) netaddr { + inetaddr := func(ip IPAddr) Addr { switch net { case "tcp", "tcp4", "tcp6": - return &TCPAddr{IP: ip, Port: portnum, Zone: zone} + return &TCPAddr{IP: ip.IP, Port: portnum, Zone: ip.Zone} case "udp", "udp4", "udp6": - return &UDPAddr{IP: ip, Port: portnum, Zone: zone} + return &UDPAddr{IP: ip.IP, Port: portnum, Zone: ip.Zone} case "ip", "ip4", "ip6": - return &IPAddr{IP: ip, Zone: zone} + return &IPAddr{IP: ip.IP, Zone: ip.Zone} default: panic("unexpected network: " + net) } } if host == "" { - return inetaddr(nil), nil + return addrList{inetaddr(IPAddr{})}, nil } // Try as a literal IP address. var ip IP if ip = parseIPv4(host); ip != nil { - return inetaddr(ip), nil + return addrList{inetaddr(IPAddr{IP: ip})}, nil } + var zone string if ip, zone = parseIPv6(host, true); ip != nil { - return inetaddr(ip), nil + return addrList{inetaddr(IPAddr{IP: ip, Zone: zone})}, nil } // Try as a DNS name. - host, zone = splitHostZone(host) ips, err := lookupIPDeadline(host, deadline) if err != nil { return nil, err } - var filter func(IP) IP + var filter func(IPAddr) bool if net != "" && net[len(net)-1] == '4' { filter = ipv4only } - if net != "" && net[len(net)-1] == '6' || zone != "" { + if net != "" && net[len(net)-1] == '6' { filter = ipv6only } - return firstFavoriteAddr(filter, ips, inetaddr) + return filterAddrList(filter, ips, inetaddr) } func zoneToString(zone int) string { @@ -303,7 +270,7 @@ func zoneToString(zone int) string { if ifi, err := InterfaceByIndex(zone); err == nil { return ifi.Name } - return itod(uint(zone)) + return uitoa(uint(zone)) } func zoneToInt(zone string) int { diff --git a/libgo/go/net/ipsock_plan9.go b/libgo/go/net/ipsock_plan9.go index 94ceea31b03..9da6ec3053b 100644 --- a/libgo/go/net/ipsock_plan9.go +++ b/libgo/go/net/ipsock_plan9.go @@ -7,7 +7,6 @@ package net import ( - "errors" "os" "syscall" ) @@ -60,15 +59,15 @@ func parsePlan9Addr(s string) (ip IP, iport int, err error) { if i >= 0 { addr = ParseIP(s[:i]) if addr == nil { - return nil, 0, errors.New("parsing IP failed") + return nil, 0, &ParseError{Type: "IP address", Text: s} } } p, _, ok := dtoi(s[i+1:], 0) if !ok { - return nil, 0, errors.New("parsing port failed") + return nil, 0, &ParseError{Type: "port", Text: s} } if p < 0 || p > 0xFFFF { - return nil, 0, &AddrError{"invalid port", string(p)} + return nil, 0, &AddrError{Err: "invalid port", Addr: string(p)} } return addr, p, nil } @@ -95,7 +94,7 @@ func readPlan9Addr(proto, filename string) (addr Addr, err error) { case "udp": addr = &UDPAddr{IP: ip, Port: port} default: - return nil, errors.New("unknown protocol " + proto) + return nil, UnknownNetworkError(proto) } return addr, nil } @@ -141,6 +140,24 @@ func netErr(e error) { if !ok { return } + nonNilInterface := func(a Addr) bool { + switch a := a.(type) { + case *TCPAddr: + return a == nil + case *UDPAddr: + return a == nil + case *IPAddr: + return a == nil + default: + return false + } + } + if nonNilInterface(oe.Source) { + oe.Source = nil + } + if nonNilInterface(oe.Addr) { + oe.Addr = nil + } if pe, ok := oe.Err.(*os.PathError); ok { if _, ok = pe.Err.(syscall.ErrorString); ok { oe.Err = pe.Err @@ -152,23 +169,23 @@ func dialPlan9(net string, laddr, raddr Addr) (fd *netFD, err error) { defer func() { netErr(err) }() f, dest, proto, name, err := startPlan9(net, raddr) if err != nil { - return nil, &OpError{"dial", net, raddr, err} + return nil, &OpError{Op: "dial", Net: net, Source: laddr, Addr: raddr, Err: err} } _, err = f.WriteString("connect " + dest) if err != nil { f.Close() - return nil, &OpError{"dial", f.Name(), raddr, err} + return nil, &OpError{Op: "dial", Net: f.Name(), Source: laddr, Addr: raddr, Err: err} } data, err := os.OpenFile(netdir+"/"+proto+"/"+name+"/data", os.O_RDWR, 0) if err != nil { f.Close() - return nil, &OpError{"dial", net, raddr, err} + return nil, &OpError{Op: "dial", Net: net, Source: laddr, Addr: raddr, Err: err} } laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local") if err != nil { data.Close() f.Close() - return nil, &OpError{"dial", proto, raddr, err} + return nil, &OpError{Op: "dial", Net: proto, Source: laddr, Addr: raddr, Err: err} } return newFD(proto, name, f, data, laddr, raddr) } @@ -177,52 +194,52 @@ func listenPlan9(net string, laddr Addr) (fd *netFD, err error) { defer func() { netErr(err) }() f, dest, proto, name, err := startPlan9(net, laddr) if err != nil { - return nil, &OpError{"listen", net, laddr, err} + return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err} } _, err = f.WriteString("announce " + dest) if err != nil { f.Close() - return nil, &OpError{"announce", proto, laddr, err} + return nil, &OpError{Op: "announce", Net: proto, Source: nil, Addr: laddr, Err: err} } laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local") if err != nil { f.Close() - return nil, &OpError{Op: "listen", Net: net, Err: err} + return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err} } return newFD(proto, name, f, nil, laddr, nil) } -func (l *netFD) netFD() (*netFD, error) { - return newFD(l.proto, l.n, l.ctl, l.data, l.laddr, l.raddr) +func (fd *netFD) netFD() (*netFD, error) { + return newFD(fd.net, fd.n, fd.ctl, fd.data, fd.laddr, fd.raddr) } -func (l *netFD) acceptPlan9() (fd *netFD, err error) { +func (fd *netFD) acceptPlan9() (nfd *netFD, err error) { defer func() { netErr(err) }() - if err := l.readLock(); err != nil { + if err := fd.readLock(); err != nil { return nil, err } - defer l.readUnlock() - f, err := os.Open(l.dir + "/listen") + defer fd.readUnlock() + f, err := os.Open(fd.dir + "/listen") if err != nil { - return nil, &OpError{"accept", l.dir + "/listen", l.laddr, err} + return nil, &OpError{Op: "accept", Net: fd.dir + "/listen", Source: nil, Addr: fd.laddr, Err: err} } var buf [16]byte n, err := f.Read(buf[:]) if err != nil { f.Close() - return nil, &OpError{"accept", l.dir + "/listen", l.laddr, err} + return nil, &OpError{Op: "accept", Net: fd.dir + "/listen", Source: nil, Addr: fd.laddr, Err: err} } name := string(buf[:n]) - data, err := os.OpenFile(netdir+"/"+l.proto+"/"+name+"/data", os.O_RDWR, 0) + data, err := os.OpenFile(netdir+"/"+fd.net+"/"+name+"/data", os.O_RDWR, 0) if err != nil { f.Close() - return nil, &OpError{"accept", l.proto, l.laddr, err} + return nil, &OpError{Op: "accept", Net: fd.net, Source: nil, Addr: fd.laddr, Err: err} } - raddr, err := readPlan9Addr(l.proto, netdir+"/"+l.proto+"/"+name+"/remote") + raddr, err := readPlan9Addr(fd.net, netdir+"/"+fd.net+"/"+name+"/remote") if err != nil { data.Close() f.Close() - return nil, &OpError{"accept", l.proto, l.laddr, err} + return nil, &OpError{Op: "accept", Net: fd.net, Source: nil, Addr: fd.laddr, Err: err} } - return newFD(l.proto, name, f, data, l.laddr, raddr) + return newFD(fd.net, name, f, data, fd.laddr, raddr) } diff --git a/libgo/go/net/ipsock_posix.go b/libgo/go/net/ipsock_posix.go index f9ebe40a21e..83eaf855b4c 100644 --- a/libgo/go/net/ipsock_posix.go +++ b/libgo/go/net/ipsock_posix.go @@ -9,17 +9,25 @@ package net import ( + "runtime" "syscall" "time" ) +// BUG(rsc,mikio): On DragonFly BSD and OpenBSD, listening on the +// "tcp" and "udp" networks does not listen for both IPv4 and IPv6 +// connections. This is due to the fact that IPv4 traffic will not be +// routed to an IPv6 socket - two separate sockets are required if +// both address families are to be supported. +// See inet6(4) for details. + func probeIPv4Stack() bool { - s, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_TCP) + s, err := socketFunc(syscall.AF_INET, syscall.SOCK_STREAM, syscall.IPPROTO_TCP) switch err { case syscall.EAFNOSUPPORT, syscall.EPROTONOSUPPORT: return false case nil: - closesocket(s) + closeFunc(s) } return true } @@ -41,20 +49,35 @@ func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) { var probes = []struct { laddr TCPAddr value int - ok bool }{ // IPv6 communication capability {laddr: TCPAddr{IP: ParseIP("::1")}, value: 1}, // IPv6 IPv4-mapped address communication capability {laddr: TCPAddr{IP: IPv4(127, 0, 0, 1)}, value: 0}, } + var supps [2]bool + switch runtime.GOOS { + case "dragonfly", "openbsd": + // Some released versions of DragonFly BSD pretend to + // accept IPV6_V6ONLY=0 successfully, but the state + // still stays IPV6_V6ONLY=1. Eventually DragonFly BSD + // stops preteding, but the transition period would + // cause unpredictable behavior and we need to avoid + // it. + // + // OpenBSD also doesn't support IPV6_V6ONLY=0 but it + // never pretends to accept IPV6_V6OLY=0. It always + // returns an error and we don't need to probe the + // capability. + probes = probes[:1] + } for i := range probes { - s, err := syscall.Socket(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_TCP) + s, err := socketFunc(syscall.AF_INET6, syscall.SOCK_STREAM, syscall.IPPROTO_TCP) if err != nil { continue } - defer closesocket(s) + defer closeFunc(s) syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, probes[i].value) sa, err := probes[i].laddr.sockaddr(syscall.AF_INET6) if err != nil { @@ -63,10 +86,10 @@ func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) { if err := syscall.Bind(s, sa); err != nil { continue } - probes[i].ok = true + supps[i] = true } - return probes[0].ok, probes[1].ok + return supps[0], supps[1] } // favoriteAddrFamily returns the appropriate address family to @@ -144,7 +167,7 @@ func ipToSockaddr(family int, ip IP, port int, zone string) (syscall.Sockaddr, e ip = IPv4zero } if ip = ip.To4(); ip == nil { - return nil, InvalidAddrError("non-IPv4 address") + return nil, &AddrError{Err: "non-IPv4 address", Addr: ip.String()} } sa := new(syscall.SockaddrInet4) for i := 0; i < IPv4len; i++ { @@ -163,7 +186,7 @@ func ipToSockaddr(family int, ip IP, port int, zone string) (syscall.Sockaddr, e ip = IPv6zero } if ip = ip.To16(); ip == nil { - return nil, InvalidAddrError("non-IPv6 address") + return nil, &AddrError{Err: "non-IPv6 address", Addr: ip.String()} } sa := new(syscall.SockaddrInet6) for i := 0; i < IPv6len; i++ { @@ -173,5 +196,5 @@ func ipToSockaddr(family int, ip IP, port int, zone string) (syscall.Sockaddr, e sa.ZoneId = uint32(zoneToInt(zone)) return sa, nil } - return nil, InvalidAddrError("unexpected socket family") + return nil, &AddrError{Err: "invalid address family", Addr: ip.String()} } diff --git a/libgo/go/net/ipsock_test.go b/libgo/go/net/ipsock_test.go index 9ecaaec69f6..b36557a1575 100644 --- a/libgo/go/net/ipsock_test.go +++ b/libgo/go/net/ipsock_test.go @@ -9,185 +9,274 @@ import ( "testing" ) -var testInetaddr = func(ip IP) netaddr { return &TCPAddr{IP: ip, Port: 5682} } +var testInetaddr = func(ip IPAddr) Addr { return &TCPAddr{IP: ip.IP, Port: 5682, Zone: ip.Zone} } -var firstFavoriteAddrTests = []struct { - filter func(IP) IP - ips []IP - inetaddr func(IP) netaddr - addr netaddr - err error +var addrListTests = []struct { + filter func(IPAddr) bool + ips []IPAddr + inetaddr func(IPAddr) Addr + first Addr + primaries addrList + fallbacks addrList + err error }{ { nil, - []IP{ - IPv4(127, 0, 0, 1), - IPv6loopback, + []IPAddr{ + {IP: IPv4(127, 0, 0, 1)}, + {IP: IPv6loopback}, }, testInetaddr, - addrList{ - &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682}, - &TCPAddr{IP: IPv6loopback, Port: 5682}, - }, + &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682}, + addrList{&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682}}, + addrList{&TCPAddr{IP: IPv6loopback, Port: 5682}}, nil, }, { nil, - []IP{ - IPv6loopback, - IPv4(127, 0, 0, 1), + []IPAddr{ + {IP: IPv6loopback}, + {IP: IPv4(127, 0, 0, 1)}, }, testInetaddr, - addrList{ - &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682}, - &TCPAddr{IP: IPv6loopback, Port: 5682}, - }, + &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682}, + addrList{&TCPAddr{IP: IPv6loopback, Port: 5682}}, + addrList{&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682}}, nil, }, { nil, - []IP{ - IPv4(127, 0, 0, 1), - IPv4(192, 168, 0, 1), + []IPAddr{ + {IP: IPv4(127, 0, 0, 1)}, + {IP: IPv4(192, 168, 0, 1)}, }, testInetaddr, &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682}, + addrList{ + &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682}, + &TCPAddr{IP: IPv4(192, 168, 0, 1), Port: 5682}, + }, + nil, nil, }, { nil, - []IP{ - IPv6loopback, - ParseIP("fe80::1"), + []IPAddr{ + {IP: IPv6loopback}, + {IP: ParseIP("fe80::1"), Zone: "eth0"}, }, testInetaddr, &TCPAddr{IP: IPv6loopback, Port: 5682}, + addrList{ + &TCPAddr{IP: IPv6loopback, Port: 5682}, + &TCPAddr{IP: ParseIP("fe80::1"), Port: 5682, Zone: "eth0"}, + }, + nil, nil, }, { nil, - []IP{ - IPv4(127, 0, 0, 1), - IPv4(192, 168, 0, 1), - IPv6loopback, - ParseIP("fe80::1"), + []IPAddr{ + {IP: IPv4(127, 0, 0, 1)}, + {IP: IPv4(192, 168, 0, 1)}, + {IP: IPv6loopback}, + {IP: ParseIP("fe80::1"), Zone: "eth0"}, }, testInetaddr, + &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682}, addrList{ &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682}, + &TCPAddr{IP: IPv4(192, 168, 0, 1), Port: 5682}, + }, + addrList{ &TCPAddr{IP: IPv6loopback, Port: 5682}, + &TCPAddr{IP: ParseIP("fe80::1"), Port: 5682, Zone: "eth0"}, }, nil, }, { nil, - []IP{ - IPv6loopback, - ParseIP("fe80::1"), - IPv4(127, 0, 0, 1), - IPv4(192, 168, 0, 1), + []IPAddr{ + {IP: IPv6loopback}, + {IP: ParseIP("fe80::1"), Zone: "eth0"}, + {IP: IPv4(127, 0, 0, 1)}, + {IP: IPv4(192, 168, 0, 1)}, }, testInetaddr, + &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682}, addrList{ - &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682}, &TCPAddr{IP: IPv6loopback, Port: 5682}, + &TCPAddr{IP: ParseIP("fe80::1"), Port: 5682, Zone: "eth0"}, + }, + addrList{ + &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682}, + &TCPAddr{IP: IPv4(192, 168, 0, 1), Port: 5682}, }, nil, }, { nil, - []IP{ - IPv4(127, 0, 0, 1), - IPv6loopback, - IPv4(192, 168, 0, 1), - ParseIP("fe80::1"), + []IPAddr{ + {IP: IPv4(127, 0, 0, 1)}, + {IP: IPv6loopback}, + {IP: IPv4(192, 168, 0, 1)}, + {IP: ParseIP("fe80::1"), Zone: "eth0"}, }, testInetaddr, + &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682}, addrList{ &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682}, + &TCPAddr{IP: IPv4(192, 168, 0, 1), Port: 5682}, + }, + addrList{ &TCPAddr{IP: IPv6loopback, Port: 5682}, + &TCPAddr{IP: ParseIP("fe80::1"), Port: 5682, Zone: "eth0"}, }, nil, }, { nil, - []IP{ - IPv6loopback, - IPv4(127, 0, 0, 1), - ParseIP("fe80::1"), - IPv4(192, 168, 0, 1), + []IPAddr{ + {IP: IPv6loopback}, + {IP: IPv4(127, 0, 0, 1)}, + {IP: ParseIP("fe80::1"), Zone: "eth0"}, + {IP: IPv4(192, 168, 0, 1)}, }, testInetaddr, + &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682}, addrList{ - &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682}, &TCPAddr{IP: IPv6loopback, Port: 5682}, + &TCPAddr{IP: ParseIP("fe80::1"), Port: 5682, Zone: "eth0"}, + }, + addrList{ + &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682}, + &TCPAddr{IP: IPv4(192, 168, 0, 1), Port: 5682}, }, nil, }, { ipv4only, - []IP{ - IPv4(127, 0, 0, 1), - IPv6loopback, + []IPAddr{ + {IP: IPv4(127, 0, 0, 1)}, + {IP: IPv6loopback}, }, testInetaddr, &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682}, + addrList{&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682}}, + nil, nil, }, { ipv4only, - []IP{ - IPv6loopback, - IPv4(127, 0, 0, 1), + []IPAddr{ + {IP: IPv6loopback}, + {IP: IPv4(127, 0, 0, 1)}, }, testInetaddr, &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682}, + addrList{&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682}}, + nil, nil, }, { ipv6only, - []IP{ - IPv4(127, 0, 0, 1), - IPv6loopback, + []IPAddr{ + {IP: IPv4(127, 0, 0, 1)}, + {IP: IPv6loopback}, }, testInetaddr, &TCPAddr{IP: IPv6loopback, Port: 5682}, + addrList{&TCPAddr{IP: IPv6loopback, Port: 5682}}, + nil, nil, }, { ipv6only, - []IP{ - IPv6loopback, - IPv4(127, 0, 0, 1), + []IPAddr{ + {IP: IPv6loopback}, + {IP: IPv4(127, 0, 0, 1)}, }, testInetaddr, &TCPAddr{IP: IPv6loopback, Port: 5682}, + addrList{&TCPAddr{IP: IPv6loopback, Port: 5682}}, + nil, nil, }, - {nil, nil, testInetaddr, nil, errNoSuitableAddress}, + {nil, nil, testInetaddr, nil, nil, nil, errNoSuitableAddress}, - {ipv4only, nil, testInetaddr, nil, errNoSuitableAddress}, - {ipv4only, []IP{IPv6loopback}, testInetaddr, nil, errNoSuitableAddress}, + {ipv4only, nil, testInetaddr, nil, nil, nil, errNoSuitableAddress}, + {ipv4only, []IPAddr{{IP: IPv6loopback}}, testInetaddr, nil, nil, nil, errNoSuitableAddress}, - {ipv6only, nil, testInetaddr, nil, errNoSuitableAddress}, - {ipv6only, []IP{IPv4(127, 0, 0, 1)}, testInetaddr, nil, errNoSuitableAddress}, + {ipv6only, nil, testInetaddr, nil, nil, nil, errNoSuitableAddress}, + {ipv6only, []IPAddr{{IP: IPv4(127, 0, 0, 1)}}, testInetaddr, nil, nil, nil, errNoSuitableAddress}, } -func TestFirstFavoriteAddr(t *testing.T) { +func TestAddrList(t *testing.T) { if !supportsIPv4 || !supportsIPv6 { - t.Skip("ipv4 or ipv6 is not supported") + t.Skip("both IPv4 and IPv6 are required") } - for i, tt := range firstFavoriteAddrTests { - addr, err := firstFavoriteAddr(tt.filter, tt.ips, tt.inetaddr) + for i, tt := range addrListTests { + addrs, err := filterAddrList(tt.filter, tt.ips, tt.inetaddr) if err != tt.err { - t.Errorf("#%v: got %v; expected %v", i, err, tt.err) + t.Errorf("#%v: got %v; want %v", i, err, tt.err) + } + if tt.err != nil { + if len(addrs) != 0 { + t.Errorf("#%v: got %v; want 0", i, len(addrs)) + } + continue + } + first := addrs.first(isIPv4) + if !reflect.DeepEqual(first, tt.first) { + t.Errorf("#%v: got %v; want %v", i, first, tt.first) + } + primaries, fallbacks := addrs.partition(isIPv4) + if !reflect.DeepEqual(primaries, tt.primaries) { + t.Errorf("#%v: got %v; want %v", i, primaries, tt.primaries) + } + if !reflect.DeepEqual(fallbacks, tt.fallbacks) { + t.Errorf("#%v: got %v; want %v", i, fallbacks, tt.fallbacks) } - if !reflect.DeepEqual(addr, tt.addr) { - t.Errorf("#%v: got %v; expected %v", i, addr, tt.addr) + expectedLen := len(primaries) + len(fallbacks) + if len(addrs) != expectedLen { + t.Errorf("#%v: got %v; want %v", i, len(addrs), expectedLen) + } + } +} + +func TestAddrListPartition(t *testing.T) { + addrs := addrList{ + &IPAddr{IP: ParseIP("fe80::"), Zone: "eth0"}, + &IPAddr{IP: ParseIP("fe80::1"), Zone: "eth0"}, + &IPAddr{IP: ParseIP("fe80::2"), Zone: "eth0"}, + } + cases := []struct { + lastByte byte + primaries addrList + fallbacks addrList + }{ + {0, addrList{addrs[0]}, addrList{addrs[1], addrs[2]}}, + {1, addrList{addrs[0], addrs[2]}, addrList{addrs[1]}}, + {2, addrList{addrs[0], addrs[1]}, addrList{addrs[2]}}, + {3, addrList{addrs[0], addrs[1], addrs[2]}, nil}, + } + for i, tt := range cases { + // Inverting the function's output should not affect the outcome. + for _, invert := range []bool{false, true} { + primaries, fallbacks := addrs.partition(func(a Addr) bool { + ip := a.(*IPAddr).IP + return (ip[len(ip)-1] == tt.lastByte) != invert + }) + if !reflect.DeepEqual(primaries, tt.primaries) { + t.Errorf("#%v: got %v; want %v", i, primaries, tt.primaries) + } + if !reflect.DeepEqual(fallbacks, tt.fallbacks) { + t.Errorf("#%v: got %v; want %v", i, fallbacks, tt.fallbacks) + } } } } diff --git a/libgo/go/net/listen_test.go b/libgo/go/net/listen_test.go new file mode 100644 index 00000000000..d5627f2556d --- /dev/null +++ b/libgo/go/net/listen_test.go @@ -0,0 +1,685 @@ +// 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 !plan9 + +package net + +import ( + "fmt" + "os" + "runtime" + "syscall" + "testing" +) + +func (ln *TCPListener) port() string { + _, port, err := SplitHostPort(ln.Addr().String()) + if err != nil { + return "" + } + return port +} + +func (c *UDPConn) port() string { + _, port, err := SplitHostPort(c.LocalAddr().String()) + if err != nil { + return "" + } + return port +} + +var tcpListenerTests = []struct { + network string + address string +}{ + {"tcp", ""}, + {"tcp", "0.0.0.0"}, + {"tcp", "::ffff:0.0.0.0"}, + {"tcp", "::"}, + + {"tcp", "127.0.0.1"}, + {"tcp", "::ffff:127.0.0.1"}, + {"tcp", "::1"}, + + {"tcp4", ""}, + {"tcp4", "0.0.0.0"}, + {"tcp4", "::ffff:0.0.0.0"}, + + {"tcp4", "127.0.0.1"}, + {"tcp4", "::ffff:127.0.0.1"}, + + {"tcp6", ""}, + {"tcp6", "::"}, + + {"tcp6", "::1"}, +} + +// 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": + t.Skipf("not supported on %s", runtime.GOOS) + } + + for _, tt := range tcpListenerTests { + if !testableListenArgs(tt.network, JoinHostPort(tt.address, "0"), "") { + t.Logf("skipping %s test", tt.network+" "+tt.address) + continue + } + + ln1, err := Listen(tt.network, JoinHostPort(tt.address, "0")) + if err != nil { + t.Fatal(err) + } + if err := checkFirstListener(tt.network, ln1); err != nil { + ln1.Close() + t.Fatal(err) + } + ln2, err := Listen(tt.network, JoinHostPort(tt.address, ln1.(*TCPListener).port())) + if err == nil { + ln2.Close() + } + if err := checkSecondListener(tt.network, tt.address, err); err != nil { + ln1.Close() + t.Fatal(err) + } + ln1.Close() + } +} + +var udpListenerTests = []struct { + network string + address string +}{ + {"udp", ""}, + {"udp", "0.0.0.0"}, + {"udp", "::ffff:0.0.0.0"}, + {"udp", "::"}, + + {"udp", "127.0.0.1"}, + {"udp", "::ffff:127.0.0.1"}, + {"udp", "::1"}, + + {"udp4", ""}, + {"udp4", "0.0.0.0"}, + {"udp4", "::ffff:0.0.0.0"}, + + {"udp4", "127.0.0.1"}, + {"udp4", "::ffff:127.0.0.1"}, + + {"udp6", ""}, + {"udp6", "::"}, + + {"udp6", "::1"}, +} + +// 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": + t.Skipf("not supported on %s", runtime.GOOS) + } + + for _, tt := range udpListenerTests { + if !testableListenArgs(tt.network, JoinHostPort(tt.address, "0"), "") { + t.Logf("skipping %s test", tt.network+" "+tt.address) + continue + } + + c1, err := ListenPacket(tt.network, JoinHostPort(tt.address, "0")) + if err != nil { + t.Fatal(err) + } + if err := checkFirstListener(tt.network, c1); err != nil { + c1.Close() + t.Fatal(err) + } + c2, err := ListenPacket(tt.network, JoinHostPort(tt.address, c1.(*UDPConn).port())) + if err == nil { + c2.Close() + } + if err := checkSecondListener(tt.network, tt.address, err); err != nil { + c1.Close() + t.Fatal(err) + } + c1.Close() + } +} + +var dualStackTCPListenerTests = []struct { + network1, address1 string // first listener + network2, address2 string // second listener + 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) + + {"tcp", "", "tcp", "", syscall.EADDRINUSE}, + {"tcp", "", "tcp", "0.0.0.0", syscall.EADDRINUSE}, + {"tcp", "0.0.0.0", "tcp", "", syscall.EADDRINUSE}, + + {"tcp", "", "tcp", "::", syscall.EADDRINUSE}, + {"tcp", "::", "tcp", "", syscall.EADDRINUSE}, + {"tcp", "0.0.0.0", "tcp", "::", syscall.EADDRINUSE}, + {"tcp", "::", "tcp", "0.0.0.0", syscall.EADDRINUSE}, + {"tcp", "::ffff:0.0.0.0", "tcp", "::", syscall.EADDRINUSE}, + {"tcp", "::", "tcp", "::ffff:0.0.0.0", syscall.EADDRINUSE}, + + {"tcp4", "", "tcp6", "", nil}, + {"tcp6", "", "tcp4", "", nil}, + {"tcp4", "0.0.0.0", "tcp6", "::", nil}, + {"tcp6", "::", "tcp4", "0.0.0.0", nil}, + + {"tcp", "127.0.0.1", "tcp", "::1", nil}, + {"tcp", "::1", "tcp", "127.0.0.1", nil}, + {"tcp4", "127.0.0.1", "tcp6", "::1", nil}, + {"tcp6", "::1", "tcp4", "127.0.0.1", nil}, +} + +// TestDualStackTCPListener tests both single and double listen +// to a test listener with various address families, different +// listening address and same port. +func TestDualStackTCPListener(t *testing.T) { + switch runtime.GOOS { + case "dragonfly", "nacl", "plan9": // re-enable on dragonfly once the new IP control block management has landed + t.Skipf("not supported on %s", runtime.GOOS) + } + if !supportsIPv4 || !supportsIPv6 { + t.Skip("both IPv4 and IPv6 are required") + } + + for _, tt := range dualStackTCPListenerTests { + if !testableListenArgs(tt.network1, JoinHostPort(tt.address1, "0"), "") { + t.Logf("skipping %s test", tt.network1+" "+tt.address1) + continue + } + + if !supportsIPv4map && differentWildcardAddr(tt.address1, tt.address2) { + tt.xerr = nil + } + var firstErr, secondErr error + for i := 0; i < 5; i++ { + lns, err := newDualStackListener() + if err != nil { + t.Fatal(err) + } + port := lns[0].port() + for _, ln := range lns { + ln.Close() + } + var ln1 Listener + ln1, firstErr = Listen(tt.network1, JoinHostPort(tt.address1, port)) + if firstErr != nil { + continue + } + if err := checkFirstListener(tt.network1, ln1); err != nil { + ln1.Close() + t.Fatal(err) + } + ln2, err := Listen(tt.network2, JoinHostPort(tt.address2, ln1.(*TCPListener).port())) + if err == nil { + ln2.Close() + } + if secondErr = checkDualStackSecondListener(tt.network2, tt.address2, err, tt.xerr); secondErr != nil { + ln1.Close() + continue + } + ln1.Close() + break + } + if firstErr != nil { + t.Error(firstErr) + } + if secondErr != nil { + t.Error(secondErr) + } + } +} + +var dualStackUDPListenerTests = []struct { + network1, address1 string // first listener + network2, address2 string // second listener + xerr error // expected error value, nil or other +}{ + {"udp", "", "udp", "", syscall.EADDRINUSE}, + {"udp", "", "udp", "0.0.0.0", syscall.EADDRINUSE}, + {"udp", "0.0.0.0", "udp", "", syscall.EADDRINUSE}, + + {"udp", "", "udp", "::", syscall.EADDRINUSE}, + {"udp", "::", "udp", "", syscall.EADDRINUSE}, + {"udp", "0.0.0.0", "udp", "::", syscall.EADDRINUSE}, + {"udp", "::", "udp", "0.0.0.0", syscall.EADDRINUSE}, + {"udp", "::ffff:0.0.0.0", "udp", "::", syscall.EADDRINUSE}, + {"udp", "::", "udp", "::ffff:0.0.0.0", syscall.EADDRINUSE}, + + {"udp4", "", "udp6", "", nil}, + {"udp6", "", "udp4", "", nil}, + {"udp4", "0.0.0.0", "udp6", "::", nil}, + {"udp6", "::", "udp4", "0.0.0.0", nil}, + + {"udp", "127.0.0.1", "udp", "::1", nil}, + {"udp", "::1", "udp", "127.0.0.1", nil}, + {"udp4", "127.0.0.1", "udp6", "::1", nil}, + {"udp6", "::1", "udp4", "127.0.0.1", nil}, +} + +// 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 "dragonfly", "nacl", "plan9": // re-enable on dragonfly once the new IP control block management has landed + t.Skipf("not supported on %s", runtime.GOOS) + } + if !supportsIPv4 || !supportsIPv6 { + t.Skip("both IPv4 and IPv6 are required") + } + + for _, tt := range dualStackUDPListenerTests { + if !testableListenArgs(tt.network1, JoinHostPort(tt.address1, "0"), "") { + t.Logf("skipping %s test", tt.network1+" "+tt.address1) + continue + } + + if !supportsIPv4map && differentWildcardAddr(tt.address1, tt.address2) { + tt.xerr = nil + } + var firstErr, secondErr error + for i := 0; i < 5; i++ { + cs, err := newDualStackPacketListener() + if err != nil { + t.Fatal(err) + } + port := cs[0].port() + for _, c := range cs { + c.Close() + } + var c1 PacketConn + c1, firstErr = ListenPacket(tt.network1, JoinHostPort(tt.address1, port)) + if firstErr != nil { + continue + } + if err := checkFirstListener(tt.network1, c1); err != nil { + c1.Close() + t.Fatal(err) + } + c2, err := ListenPacket(tt.network2, JoinHostPort(tt.address2, c1.(*UDPConn).port())) + if err == nil { + c2.Close() + } + if secondErr = checkDualStackSecondListener(tt.network2, tt.address2, err, tt.xerr); secondErr != nil { + c1.Close() + continue + } + c1.Close() + break + } + if firstErr != nil { + t.Error(firstErr) + } + if secondErr != nil { + t.Error(secondErr) + } + } +} + +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(network string, ln interface{}) error { + switch network { + case "tcp": + fd := ln.(*TCPListener).fd + if err := checkDualStackAddrFamily(fd); err != nil { + return err + } + case "tcp4": + fd := ln.(*TCPListener).fd + if fd.family != syscall.AF_INET { + return fmt.Errorf("%v got %v; want %v", fd.laddr, fd.family, syscall.AF_INET) + } + case "tcp6": + fd := ln.(*TCPListener).fd + if fd.family != syscall.AF_INET6 { + return fmt.Errorf("%v got %v; want %v", fd.laddr, fd.family, syscall.AF_INET6) + } + case "udp": + fd := ln.(*UDPConn).fd + if err := checkDualStackAddrFamily(fd); err != nil { + return err + } + case "udp4": + fd := ln.(*UDPConn).fd + if fd.family != syscall.AF_INET { + return fmt.Errorf("%v got %v; want %v", fd.laddr, fd.family, syscall.AF_INET) + } + case "udp6": + fd := ln.(*UDPConn).fd + if fd.family != syscall.AF_INET6 { + return fmt.Errorf("%v got %v; want %v", fd.laddr, fd.family, syscall.AF_INET6) + } + default: + return UnknownNetworkError(network) + } + return nil +} + +func checkSecondListener(network, address string, err error) error { + switch network { + case "tcp", "tcp4", "tcp6": + if err == nil { + return fmt.Errorf("%s should fail", network+" "+address) + } + case "udp", "udp4", "udp6": + if err == nil { + return fmt.Errorf("%s should fail", network+" "+address) + } + default: + return UnknownNetworkError(network) + } + return nil +} + +func checkDualStackSecondListener(network, address string, err, xerr error) error { + switch network { + case "tcp", "tcp4", "tcp6": + if xerr == nil && err != nil || xerr != nil && err == nil { + return fmt.Errorf("%s got %v; want %v", network+" "+address, err, xerr) + } + case "udp", "udp4", "udp6": + if xerr == nil && err != nil || xerr != nil && err == nil { + return fmt.Errorf("%s got %v; want %v", network+" "+address, err, xerr) + } + default: + return UnknownNetworkError(network) + } + return nil +} + +func checkDualStackAddrFamily(fd *netFD) error { + 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 { + return fmt.Errorf("Listen(%s, %v) returns %v; want %v", fd.net, fd.laddr, fd.family, syscall.AF_INET6) + } + } else { + if fd.family != a.family() { + return fmt.Errorf("Listen(%s, %v) returns %v; want %v", fd.net, fd.laddr, fd.family, a.family()) + } + } + 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 { + return fmt.Errorf("ListenPacket(%s, %v) returns %v; want %v", fd.net, fd.laddr, fd.family, syscall.AF_INET6) + } + } else { + if fd.family != a.family() { + return fmt.Errorf("ListenPacket(%s, %v) returns %v; want %v", fd.net, fd.laddr, fd.family, a.family()) + } + } + default: + return fmt.Errorf("unexpected protocol address type: %T", a) + } + return nil +} + +func TestWildWildcardListener(t *testing.T) { + switch runtime.GOOS { + case "plan9": + t.Skipf("not supported on %s", runtime.GOOS) + } + if testing.Short() || !*testExternal { + t.Skip("avoid external network") + } + + defer func() { + if p := recover(); p != nil { + t.Fatalf("panicked: %v", p) + } + }() + + if ln, err := Listen("tcp", ""); err == nil { + ln.Close() + } + if ln, err := ListenPacket("udp", ""); err == nil { + ln.Close() + } + if ln, err := ListenTCP("tcp", nil); err == nil { + ln.Close() + } + if ln, err := ListenUDP("udp", nil); err == nil { + ln.Close() + } + if ln, err := ListenIP("ip:icmp", nil); err == nil { + ln.Close() + } +} + +var ipv4MulticastListenerTests = []struct { + net string + gaddr *UDPAddr // see RFC 4727 +}{ + {"udp", &UDPAddr{IP: IPv4(224, 0, 0, 254), Port: 12345}}, + + {"udp4", &UDPAddr{IP: IPv4(224, 0, 0, 254), Port: 12345}}, +} + +// TestIPv4MulticastListener tests both single and double listen to a +// test listener with same address family, same group address and same +// port. +func TestIPv4MulticastListener(t *testing.T) { + switch runtime.GOOS { + case "android", "nacl", "plan9": + t.Skipf("not supported on %s", runtime.GOOS) + case "solaris": + t.Skipf("not supported on solaris, see golang.org/issue/7399") + } + + closer := func(cs []*UDPConn) { + for _, c := range cs { + if c != nil { + c.Close() + } + } + } + + for _, ifi := range []*Interface{loopbackInterface(), nil} { + // Note that multicast interface assignment by system + // is not recommended because it usually relies on + // routing stuff for finding out an appropriate + // nexthop containing both network and link layer + // adjacencies. + if ifi == nil && !*testExternal { + continue + } + for _, tt := range ipv4MulticastListenerTests { + var err error + cs := make([]*UDPConn, 2) + if cs[0], err = ListenMulticastUDP(tt.net, ifi, tt.gaddr); err != nil { + t.Fatal(err) + } + if err := checkMulticastListener(cs[0], tt.gaddr.IP); err != nil { + closer(cs) + t.Fatal(err) + } + if cs[1], err = ListenMulticastUDP(tt.net, ifi, tt.gaddr); err != nil { + closer(cs) + t.Fatal(err) + } + if err := checkMulticastListener(cs[1], tt.gaddr.IP); err != nil { + closer(cs) + t.Fatal(err) + } + closer(cs) + } + } +} + +var ipv6MulticastListenerTests = []struct { + net string + gaddr *UDPAddr // see RFC 4727 +}{ + {"udp", &UDPAddr{IP: ParseIP("ff01::114"), Port: 12345}}, + {"udp", &UDPAddr{IP: ParseIP("ff02::114"), Port: 12345}}, + {"udp", &UDPAddr{IP: ParseIP("ff04::114"), Port: 12345}}, + {"udp", &UDPAddr{IP: ParseIP("ff05::114"), Port: 12345}}, + {"udp", &UDPAddr{IP: ParseIP("ff08::114"), Port: 12345}}, + {"udp", &UDPAddr{IP: ParseIP("ff0e::114"), Port: 12345}}, + + {"udp6", &UDPAddr{IP: ParseIP("ff01::114"), Port: 12345}}, + {"udp6", &UDPAddr{IP: ParseIP("ff02::114"), Port: 12345}}, + {"udp6", &UDPAddr{IP: ParseIP("ff04::114"), Port: 12345}}, + {"udp6", &UDPAddr{IP: ParseIP("ff05::114"), Port: 12345}}, + {"udp6", &UDPAddr{IP: ParseIP("ff08::114"), Port: 12345}}, + {"udp6", &UDPAddr{IP: ParseIP("ff0e::114"), Port: 12345}}, +} + +// TestIPv6MulticastListener tests both single and double listen to a +// test listener with same address family, same group address and same +// port. +func TestIPv6MulticastListener(t *testing.T) { + switch runtime.GOOS { + case "plan9": + t.Skipf("not supported on %s", runtime.GOOS) + case "solaris": + t.Skipf("not supported on solaris, see issue 7399") + } + if !supportsIPv6 { + t.Skip("ipv6 is not supported") + } + if os.Getuid() != 0 { + t.Skip("must be root") + } + + closer := func(cs []*UDPConn) { + for _, c := range cs { + if c != nil { + c.Close() + } + } + } + + for _, ifi := range []*Interface{loopbackInterface(), nil} { + // Note that multicast interface assignment by system + // is not recommended because it usually relies on + // routing stuff for finding out an appropriate + // nexthop containing both network and link layer + // adjacencies. + if ifi == nil && (!*testExternal || !*testIPv6) { + continue + } + for _, tt := range ipv6MulticastListenerTests { + var err error + cs := make([]*UDPConn, 2) + if cs[0], err = ListenMulticastUDP(tt.net, ifi, tt.gaddr); err != nil { + t.Fatal(err) + } + if err := checkMulticastListener(cs[0], tt.gaddr.IP); err != nil { + closer(cs) + t.Fatal(err) + } + if cs[1], err = ListenMulticastUDP(tt.net, ifi, tt.gaddr); err != nil { + closer(cs) + t.Fatal(err) + } + if err := checkMulticastListener(cs[1], tt.gaddr.IP); err != nil { + closer(cs) + t.Fatal(err) + } + closer(cs) + } + } +} + +func checkMulticastListener(c *UDPConn, ip IP) error { + if ok, err := multicastRIBContains(ip); err != nil { + return err + } else if !ok { + return fmt.Errorf("%s not found in multicast rib", ip.String()) + } + la := c.LocalAddr() + if la, ok := la.(*UDPAddr); !ok || la.Port == 0 { + return fmt.Errorf("got %v; want a proper address with non-zero port number", la) + } + return nil +} + +func multicastRIBContains(ip IP) (bool, error) { + switch runtime.GOOS { + case "dragonfly", "netbsd", "openbsd", "plan9", "solaris", "windows": + return true, nil // not implemented yet + case "linux": + if runtime.GOARCH == "arm" || runtime.GOARCH == "alpha" { + return true, nil // not implemented yet + } + } + ift, err := Interfaces() + if err != nil { + return false, err + } + for _, ifi := range ift { + ifmat, err := ifi.MulticastAddrs() + if err != nil { + return false, err + } + for _, ifma := range ifmat { + if ifma.(*IPAddr).IP.Equal(ip) { + return true, nil + } + } + } + return false, nil +} diff --git a/libgo/go/net/lookup.go b/libgo/go/net/lookup.go index aeffe6c9b72..a7ceee823f1 100644 --- a/libgo/go/net/lookup.go +++ b/libgo/go/net/lookup.go @@ -4,7 +4,10 @@ package net -import "time" +import ( + "internal/singleflight" + "time" +) // protocols contains minimal mappings between internet protocol // names and numbers for platforms that don't have a complete list of @@ -22,36 +25,60 @@ var protocols = map[string]int{ // LookupHost looks up the given host using the local resolver. // It returns an array of that host's addresses. func LookupHost(host string) (addrs []string, err error) { + // Make sure that no matter what we do later, host=="" is rejected. + // ParseIP, for example, does accept empty strings. + if host == "" { + return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host} + } + if ip := ParseIP(host); ip != nil { + return []string{host}, nil + } return lookupHost(host) } // LookupIP looks up host using the local resolver. // It returns an array of that host's IPv4 and IPv6 addresses. -func LookupIP(host string) (addrs []IP, err error) { - return lookupIPMerge(host) +func LookupIP(host string) (ips []IP, err error) { + // Make sure that no matter what we do later, host=="" is rejected. + // ParseIP, for example, does accept empty strings. + if host == "" { + return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host} + } + if ip := ParseIP(host); ip != nil { + return []IP{ip}, nil + } + addrs, err := lookupIPMerge(host) + if err != nil { + return + } + ips = make([]IP, len(addrs)) + for i, addr := range addrs { + ips[i] = addr.IP + } + return } -var lookupGroup singleflight +var lookupGroup singleflight.Group // lookupIPMerge wraps lookupIP, but makes sure that for any given // host, only one lookup is in-flight at a time. The returned memory // is always owned by the caller. -func lookupIPMerge(host string) (addrs []IP, err error) { +func lookupIPMerge(host string) (addrs []IPAddr, err error) { addrsi, err, shared := lookupGroup.Do(host, func() (interface{}, error) { - return lookupIP(host) + return testHookLookupIP(lookupIP, host) }) return lookupIPReturn(addrsi, err, shared) } // lookupIPReturn turns the return values from singleflight.Do into // the return values from LookupIP. -func lookupIPReturn(addrsi interface{}, err error, shared bool) ([]IP, error) { +func lookupIPReturn(addrsi interface{}, err error, shared bool) ([]IPAddr, error) { if err != nil { return nil, err } - addrs := addrsi.([]IP) + addrs := addrsi.([]IPAddr) if shared { - clone := make([]IP, len(addrs)) + clone := make([]IPAddr, len(addrs)) copy(clone, addrs) addrs = clone } @@ -59,7 +86,7 @@ func lookupIPReturn(addrsi interface{}, err error, shared bool) ([]IP, error) { } // lookupIPDeadline looks up a hostname with a deadline. -func lookupIPDeadline(host string, deadline time.Time) (addrs []IP, err error) { +func lookupIPDeadline(host string, deadline time.Time) (addrs []IPAddr, err error) { if deadline.IsZero() { return lookupIPMerge(host) } @@ -76,7 +103,7 @@ func lookupIPDeadline(host string, deadline time.Time) (addrs []IP, err error) { defer t.Stop() ch := lookupGroup.DoChan(host, func() (interface{}, error) { - return lookupIP(host) + return testHookLookupIP(lookupIP, host) }) select { @@ -90,7 +117,7 @@ func lookupIPDeadline(host string, deadline time.Time) (addrs []IP, err error) { return nil, errTimeout case r := <-ch: - return lookupIPReturn(r.v, r.err, r.shared) + return lookupIPReturn(r.Val, r.Err, r.Shared) } } @@ -121,22 +148,22 @@ func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err err } // LookupMX returns the DNS MX records for the given domain name sorted by preference. -func LookupMX(name string) (mx []*MX, err error) { +func LookupMX(name string) (mxs []*MX, err error) { return lookupMX(name) } // LookupNS returns the DNS NS records for the given domain name. -func LookupNS(name string) (ns []*NS, err error) { +func LookupNS(name string) (nss []*NS, err error) { return lookupNS(name) } // LookupTXT returns the DNS TXT records for the given domain name. -func LookupTXT(name string) (txt []string, err error) { +func LookupTXT(name string) (txts []string, err error) { return lookupTXT(name) } // LookupAddr performs a reverse lookup for the given address, returning a list // of names mapping to that address. -func LookupAddr(addr string) (name []string, err error) { +func LookupAddr(addr string) (names []string, err error) { return lookupAddr(addr) } diff --git a/libgo/go/net/lookup_plan9.go b/libgo/go/net/lookup_plan9.go index b80ac10e0d9..c6274640bb7 100644 --- a/libgo/go/net/lookup_plan9.go +++ b/libgo/go/net/lookup_plan9.go @@ -101,19 +101,18 @@ func lookupProtocol(name string) (proto int, err error) { if err != nil { return 0, err } - unknownProtoError := errors.New("unknown IP protocol specified: " + name) if len(lines) == 0 { - return 0, unknownProtoError + return 0, UnknownNetworkError(name) } f := getFields(lines[0]) if len(f) < 2 { - return 0, unknownProtoError + return 0, UnknownNetworkError(name) } s := f[1] if n, _, ok := dtoi(s, byteIndex(s, '=')+1); ok { return n, nil } - return 0, unknownProtoError + return 0, UnknownNetworkError(name) } func lookupHost(host string) (addrs []string, err error) { @@ -147,14 +146,16 @@ loop: return } -func lookupIP(host string) (ips []IP, err error) { - addrs, err := LookupHost(host) +func lookupIP(host string) (addrs []IPAddr, err error) { + lits, err := LookupHost(host) if err != nil { return } - for _, addr := range addrs { - if ip := ParseIP(addr); ip != nil { - ips = append(ips, ip) + for _, lit := range lits { + host, zone := splitHostZone(lit) + if ip := ParseIP(host); ip != nil { + addr := IPAddr{IP: ip, Zone: zone} + addrs = append(addrs, addr) } } return @@ -171,7 +172,7 @@ func lookupPort(network, service string) (port int, err error) { if err != nil { return } - unknownPortError := &AddrError{"unknown port", network + "/" + service} + unknownPortError := &AddrError{Err: "unknown port", Addr: network + "/" + service} if len(lines) == 0 { return 0, unknownPortError } diff --git a/libgo/go/net/lookup_stub.go b/libgo/go/net/lookup_stub.go index 502aafb2702..5636198f881 100644 --- a/libgo/go/net/lookup_stub.go +++ b/libgo/go/net/lookup_stub.go @@ -16,7 +16,7 @@ func lookupHost(host string) (addrs []string, err error) { return nil, syscall.ENOPROTOOPT } -func lookupIP(host string) (ips []IP, err error) { +func lookupIP(host string) (addrs []IPAddr, err error) { return nil, syscall.ENOPROTOOPT } diff --git a/libgo/go/net/lookup_test.go b/libgo/go/net/lookup_test.go index 057e1322b99..86957b55756 100644 --- a/libgo/go/net/lookup_test.go +++ b/libgo/go/net/lookup_test.go @@ -2,18 +2,34 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// TODO It would be nice to use a mock DNS server, to eliminate -// external dependencies. - package net import ( - "flag" + "bytes" + "fmt" "strings" "testing" + "time" ) -var testExternal = flag.Bool("external", true, "allow use of external networks during long test") +func lookupLocalhost(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, error) { + switch host { + case "localhost": + return []IPAddr{ + {IP: IPv4(127, 0, 0, 1)}, + {IP: IPv6loopback}, + }, nil + default: + return fn(host) + } +} + +// The Lookup APIs use various sources such as local database, DNS or +// mDNS, and may use platform-dependent DNS stub resolver if possible. +// The APIs accept any of forms for a query; host name in various +// encodings, UTF-8 encoded net name, domain name, FQDN or absolute +// FQDN, but the result would be one of the forms and it depends on +// the circumstances. var lookupGoogleSRVTests = []struct { service, proto, name string @@ -21,17 +37,30 @@ var lookupGoogleSRVTests = []struct { }{ { "xmpp-server", "tcp", "google.com", - ".google.com", ".google.com", + "google.com", "google.com", + }, + { + "xmpp-server", "tcp", "google.com.", + "google.com", "google.com", + }, + + // non-standard back door + { + "", "", "_xmpp-server._tcp.google.com", + "google.com", "google.com", }, { - "", "", "_xmpp-server._tcp.google.com", // non-standard back door - ".google.com", ".google.com", + "", "", "_xmpp-server._tcp.google.com.", + "google.com", "google.com", }, } func TestLookupGoogleSRV(t *testing.T) { if testing.Short() || !*testExternal { - t.Skip("skipping test to avoid external network") + t.Skip("avoid external network") + } + if !supportsIPv4 || !*testIPv4 { + t.Skip("IPv4 is required") } for _, tt := range lookupGoogleSRVTests { @@ -42,90 +71,128 @@ func TestLookupGoogleSRV(t *testing.T) { if len(srvs) == 0 { t.Error("got no record") } - if !strings.Contains(cname, tt.cname) { - t.Errorf("got %q; want %q", cname, tt.cname) + if !strings.HasSuffix(cname, tt.cname) && !strings.HasSuffix(cname, tt.cname+".") { + t.Errorf("got %s; want %s", cname, tt.cname) } for _, srv := range srvs { - if !strings.Contains(srv.Target, tt.target) { - t.Errorf("got %v; want a record containing %q", srv, tt.target) + if !strings.HasSuffix(srv.Target, tt.target) && !strings.HasSuffix(srv.Target, tt.target+".") { + t.Errorf("got %v; want a record containing %s", srv, tt.target) } } } } +var lookupGmailMXTests = []struct { + name, host string +}{ + {"gmail.com", "google.com"}, + {"gmail.com.", "google.com"}, +} + func TestLookupGmailMX(t *testing.T) { if testing.Short() || !*testExternal { - t.Skip("skipping test to avoid external network") + t.Skip("avoid external network") } - - mxs, err := LookupMX("gmail.com") - if err != nil { - t.Fatal(err) - } - if len(mxs) == 0 { - t.Error("got no record") + if !supportsIPv4 || !*testIPv4 { + t.Skip("IPv4 is required") } - for _, mx := range mxs { - if !strings.Contains(mx.Host, ".google.com") { - t.Errorf("got %v; want a record containing .google.com.", mx) + + for _, tt := range lookupGmailMXTests { + mxs, err := LookupMX(tt.name) + if err != nil { + t.Fatal(err) + } + if len(mxs) == 0 { + t.Error("got no record") + } + for _, mx := range mxs { + if !strings.HasSuffix(mx.Host, tt.host) && !strings.HasSuffix(mx.Host, tt.host+".") { + t.Errorf("got %v; want a record containing %s", mx, tt.host) + } } } } +var lookupGmailNSTests = []struct { + name, host string +}{ + {"gmail.com", "google.com"}, + {"gmail.com.", "google.com"}, +} + func TestLookupGmailNS(t *testing.T) { if testing.Short() || !*testExternal { - t.Skip("skipping test to avoid external network") + t.Skip("avoid external network") } - - nss, err := LookupNS("gmail.com") - if err != nil { - t.Fatal(err) - } - if len(nss) == 0 { - t.Error("got no record") + if !supportsIPv4 || !*testIPv4 { + t.Skip("IPv4 is required") } - for _, ns := range nss { - if !strings.Contains(ns.Host, ".google.com") { - t.Errorf("got %v; want a record containing .google.com.", ns) + + for _, tt := range lookupGmailNSTests { + nss, err := LookupNS(tt.name) + if err != nil { + t.Fatal(err) + } + if len(nss) == 0 { + t.Error("got no record") + } + for _, ns := range nss { + if !strings.HasSuffix(ns.Host, tt.host) && !strings.HasSuffix(ns.Host, tt.host+".") { + t.Errorf("got %v; want a record containing %s", ns, tt.host) + } } } } +var lookupGmailTXTTests = []struct { + name, txt, host string +}{ + {"gmail.com", "spf", "google.com"}, + {"gmail.com.", "spf", "google.com"}, +} + func TestLookupGmailTXT(t *testing.T) { if testing.Short() || !*testExternal { - t.Skip("skipping test to avoid external network") + t.Skip("avoid external network") } - - txts, err := LookupTXT("gmail.com") - if err != nil { - t.Fatal(err) + if !supportsIPv4 || !*testIPv4 { + t.Skip("IPv4 is required") } - if len(txts) == 0 { - t.Error("got no record") - } - for _, txt := range txts { - if !strings.Contains(txt, "spf") { - t.Errorf("got %q; want a spf record", txt) + + for _, tt := range lookupGmailTXTTests { + txts, err := LookupTXT(tt.name) + if err != nil { + t.Fatal(err) + } + if len(txts) == 0 { + t.Error("got no record") + } + for _, txt := range txts { + if !strings.Contains(txt, tt.txt) || (!strings.HasSuffix(txt, tt.host) && !strings.HasSuffix(txt, tt.host+".")) { + t.Errorf("got %s; want a record containing %s, %s", txt, tt.txt, tt.host) + } } } } -var lookupGooglePublicDNSAddrs = []struct { - addr string - name string +var lookupGooglePublicDNSAddrTests = []struct { + addr, name string }{ - {"8.8.8.8", ".google.com."}, - {"8.8.4.4", ".google.com."}, - {"2001:4860:4860::8888", ".google.com."}, - {"2001:4860:4860::8844", ".google.com."}, + {"8.8.8.8", ".google.com"}, + {"8.8.4.4", ".google.com"}, + {"2001:4860:4860::8888", ".google.com"}, + {"2001:4860:4860::8844", ".google.com"}, } func TestLookupGooglePublicDNSAddr(t *testing.T) { if testing.Short() || !*testExternal { - t.Skip("skipping test to avoid external network") + t.Skip("avoid external network") + } + if !supportsIPv4 || !supportsIPv6 || !*testIPv4 || !*testIPv6 { + t.Skip("both IPv4 and IPv6 are required") } - for _, tt := range lookupGooglePublicDNSAddrs { + for _, tt := range lookupGooglePublicDNSAddrTests { names, err := LookupAddr(tt.addr) if err != nil { t.Fatal(err) @@ -134,61 +201,97 @@ func TestLookupGooglePublicDNSAddr(t *testing.T) { t.Error("got no record") } for _, name := range names { - if !strings.HasSuffix(name, tt.name) { - t.Errorf("got %q; want a record containing %q", name, tt.name) + if !strings.HasSuffix(name, tt.name) && !strings.HasSuffix(name, tt.name+".") { + t.Errorf("got %s; want a record containing %s", name, tt.name) } } } } +var lookupIANACNAMETests = []struct { + name, cname string +}{ + {"www.iana.org", "icann.org"}, + {"www.iana.org.", "icann.org"}, +} + func TestLookupIANACNAME(t *testing.T) { if testing.Short() || !*testExternal { - t.Skip("skipping test to avoid external network") + t.Skip("avoid external network") } - - cname, err := LookupCNAME("www.iana.org") - if err != nil { - t.Fatal(err) + if !supportsIPv4 || !*testIPv4 { + t.Skip("IPv4 is required") } - if !strings.HasSuffix(cname, ".icann.org.") { - t.Errorf("got %q; want a record containing .icann.org.", cname) + + for _, tt := range lookupIANACNAMETests { + cname, err := LookupCNAME(tt.name) + if err != nil { + t.Fatal(err) + } + if !strings.HasSuffix(cname, tt.cname) && !strings.HasSuffix(cname, tt.cname+".") { + t.Errorf("got %s; want a record containing %s", cname, tt.cname) + } } } +var lookupGoogleHostTests = []struct { + name string +}{ + {"google.com"}, + {"google.com."}, +} + func TestLookupGoogleHost(t *testing.T) { if testing.Short() || !*testExternal { - t.Skip("skipping test to avoid external network") + t.Skip("avoid external network") } - - addrs, err := LookupHost("google.com") - if err != nil { - t.Fatal(err) - } - if len(addrs) == 0 { - t.Error("got no record") + if !supportsIPv4 || !*testIPv4 { + t.Skip("IPv4 is required") } - for _, addr := range addrs { - if ParseIP(addr) == nil { - t.Errorf("got %q; want a literal ip address", addr) + + for _, tt := range lookupGoogleHostTests { + addrs, err := LookupHost(tt.name) + if err != nil { + t.Fatal(err) + } + if len(addrs) == 0 { + t.Error("got no record") + } + for _, addr := range addrs { + if ParseIP(addr) == nil { + t.Errorf("got %q; want a literal IP address", addr) + } } } } +var lookupGoogleIPTests = []struct { + name string +}{ + {"google.com"}, + {"google.com."}, +} + func TestLookupGoogleIP(t *testing.T) { if testing.Short() || !*testExternal { - t.Skip("skipping test to avoid external network") + t.Skip("avoid external network") } - - ips, err := LookupIP("google.com") - if err != nil { - t.Fatal(err) - } - if len(ips) == 0 { - t.Error("got no record") + if !supportsIPv4 || !*testIPv4 { + t.Skip("IPv4 is required") } - for _, ip := range ips { - if ip.To4() == nil && ip.To16() == nil { - t.Errorf("got %v; want an ip address", ip) + + for _, tt := range lookupGoogleIPTests { + ips, err := LookupIP(tt.name) + if err != nil { + t.Fatal(err) + } + if len(ips) == 0 { + t.Error("got no record") + } + for _, ip := range ips { + if ip.To4() == nil && ip.To16() == nil { + t.Errorf("got %v; want an IP address", ip) + } } } } @@ -229,3 +332,172 @@ func TestReverseAddress(t *testing.T) { } } } + +func TestLookupIPDeadline(t *testing.T) { + if !*testDNSFlood { + t.Skip("test disabled; use -dnsflood to enable") + } + + const N = 5000 + const timeout = 3 * time.Second + c := make(chan error, 2*N) + for i := 0; i < N; i++ { + name := fmt.Sprintf("%d.net-test.golang.org", i) + go func() { + _, err := lookupIPDeadline(name, time.Now().Add(timeout/2)) + c <- err + }() + go func() { + _, err := lookupIPDeadline(name, time.Now().Add(timeout)) + c <- err + }() + } + qstats := struct { + succeeded, failed int + timeout, temporary, other int + unknown int + }{} + deadline := time.After(timeout + time.Second) + for i := 0; i < 2*N; i++ { + select { + case <-deadline: + t.Fatal("deadline exceeded") + case err := <-c: + switch err := err.(type) { + case nil: + qstats.succeeded++ + case Error: + qstats.failed++ + if err.Timeout() { + qstats.timeout++ + } + if err.Temporary() { + qstats.temporary++ + } + if !err.Timeout() && !err.Temporary() { + qstats.other++ + } + default: + qstats.failed++ + qstats.unknown++ + } + } + } + + // A high volume of DNS queries for sub-domain of golang.org + // would be coordinated by authoritative or recursive server, + // or stub resolver which implements query-response rate + // limitation, so we can expect some query successes and more + // failures including timeout, temporary and other here. + // As a rule, unknown must not be shown but it might possibly + // happen due to issue 4856 for now. + t.Logf("%v succeeded, %v failed (%v timeout, %v temporary, %v other, %v unknown)", qstats.succeeded, qstats.failed, qstats.timeout, qstats.temporary, qstats.other, qstats.unknown) +} + +func TestLookupDots(t *testing.T) { + if testing.Short() || !*testExternal { + t.Skipf("skipping external network test") + } + + fixup := forceGoDNS() + defer fixup() + testDots(t, "go") + + if forceCgoDNS() { + testDots(t, "cgo") + } +} + +func testDots(t *testing.T, mode string) { + names, err := LookupAddr("8.8.8.8") // Google dns server + if err != nil { + t.Errorf("LookupAddr(8.8.8.8): %v (mode=%v)", err, mode) + } else { + for _, name := range names { + if !strings.HasSuffix(name, ".google.com.") { + t.Errorf("LookupAddr(8.8.8.8) = %v, want names ending in .google.com. with trailing dot (mode=%v)", names, mode) + break + } + } + } + + cname, err := LookupCNAME("www.mit.edu") + if err != nil || !strings.HasSuffix(cname, ".") { + t.Errorf("LookupCNAME(www.mit.edu) = %v, %v, want cname ending in . with trailing dot (mode=%v)", cname, err, mode) + } + + mxs, err := LookupMX("google.com") + if err != nil { + t.Errorf("LookupMX(google.com): %v (mode=%v)", err, mode) + } else { + for _, mx := range mxs { + if !strings.HasSuffix(mx.Host, ".google.com.") { + t.Errorf("LookupMX(google.com) = %v, want names ending in .google.com. with trailing dot (mode=%v)", mxString(mxs), mode) + break + } + } + } + + nss, err := LookupNS("google.com") + if err != nil { + t.Errorf("LookupNS(google.com): %v (mode=%v)", err, mode) + } else { + for _, ns := range nss { + if !strings.HasSuffix(ns.Host, ".google.com.") { + t.Errorf("LookupNS(google.com) = %v, want names ending in .google.com. with trailing dot (mode=%v)", nsString(nss), mode) + break + } + } + } + + cname, srvs, err := LookupSRV("xmpp-server", "tcp", "google.com") + if err != nil { + t.Errorf("LookupSRV(xmpp-server, tcp, google.com): %v (mode=%v)", err, mode) + } else { + if !strings.HasSuffix(cname, ".google.com.") { + t.Errorf("LookupSRV(xmpp-server, tcp, google.com) returned cname=%v, want name ending in .google.com. with trailing dot (mode=%v)", cname, mode) + } + for _, srv := range srvs { + if !strings.HasSuffix(srv.Target, ".google.com.") { + t.Errorf("LookupSRV(xmpp-server, tcp, google.com) returned addrs=%v, want names ending in .google.com. with trailing dot (mode=%v)", srvString(srvs), mode) + break + } + } + } +} + +func mxString(mxs []*MX) string { + var buf bytes.Buffer + sep := "" + fmt.Fprintf(&buf, "[") + for _, mx := range mxs { + fmt.Fprintf(&buf, "%s%s:%d", sep, mx.Host, mx.Pref) + sep = " " + } + fmt.Fprintf(&buf, "]") + return buf.String() +} + +func nsString(nss []*NS) string { + var buf bytes.Buffer + sep := "" + fmt.Fprintf(&buf, "[") + for _, ns := range nss { + fmt.Fprintf(&buf, "%s%s", sep, ns.Host) + sep = " " + } + fmt.Fprintf(&buf, "]") + return buf.String() +} + +func srvString(srvs []*SRV) string { + var buf bytes.Buffer + sep := "" + fmt.Fprintf(&buf, "[") + for _, srv := range srvs { + fmt.Fprintf(&buf, "%s%s:%d:%d:%d", sep, srv.Target, srv.Port, srv.Priority, srv.Weight) + sep = " " + } + fmt.Fprintf(&buf, "]") + return buf.String() +} diff --git a/libgo/go/net/lookup_unix.go b/libgo/go/net/lookup_unix.go index a54578456d7..a64da8bcb50 100644 --- a/libgo/go/net/lookup_unix.go +++ b/libgo/go/net/lookup_unix.go @@ -6,10 +6,7 @@ package net -import ( - "errors" - "sync" -) +import "sync" var onceReadProtocols sync.Once @@ -43,126 +40,120 @@ func readProtocols() { // lookupProtocol looks up IP protocol name in /etc/protocols and // returns correspondent protocol number. -func lookupProtocol(name string) (proto int, err error) { +func lookupProtocol(name string) (int, error) { onceReadProtocols.Do(readProtocols) proto, found := protocols[name] if !found { - return 0, errors.New("unknown IP protocol specified: " + name) + return 0, &AddrError{Err: "unknown IP protocol specified", Addr: name} } - return + return proto, nil } func lookupHost(host string) (addrs []string, err error) { - addrs, err, ok := cgoLookupHost(host) - if !ok { - addrs, err = goLookupHost(host) + order := systemConf().hostLookupOrder(host) + if order == hostLookupCgo { + if addrs, err, ok := cgoLookupHost(host); ok { + return addrs, err + } + // cgo not available (or netgo); fall back to Go's DNS resolver + order = hostLookupFilesDNS } - return + return goLookupHostOrder(host, order) } -func lookupIP(host string) (addrs []IP, err error) { - addrs, err, ok := cgoLookupIP(host) - if !ok { - addrs, err = goLookupIP(host) +func lookupIP(host string) (addrs []IPAddr, err error) { + order := systemConf().hostLookupOrder(host) + if order == hostLookupCgo { + if addrs, err, ok := cgoLookupIP(host); ok { + return addrs, err + } + // cgo not available (or netgo); fall back to Go's DNS resolver + order = hostLookupFilesDNS } - return + return goLookupIPOrder(host, order) } -func lookupPort(network, service string) (port int, err error) { - port, err, ok := cgoLookupPort(network, service) - if !ok { - port, err = goLookupPort(network, service) +func lookupPort(network, service string) (int, error) { + if systemConf().canUseCgo() { + if port, err, ok := cgoLookupPort(network, service); ok { + return port, err + } } - return + return goLookupPort(network, service) } -func lookupCNAME(name string) (cname string, err error) { - cname, err, ok := cgoLookupCNAME(name) - if !ok { - cname, err = goLookupCNAME(name) +func lookupCNAME(name string) (string, error) { + if systemConf().canUseCgo() { + if cname, err, ok := cgoLookupCNAME(name); ok { + return cname, err + } } - return + return goLookupCNAME(name) } -func lookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) { +func lookupSRV(service, proto, name string) (string, []*SRV, error) { var target string if service == "" && proto == "" { target = name } else { target = "_" + service + "._" + proto + "." + name } - var records []dnsRR - cname, records, err = lookup(target, dnsTypeSRV) + cname, rrs, err := lookup(target, dnsTypeSRV) if err != nil { - return + return "", nil, err } - addrs = make([]*SRV, len(records)) - for i, rr := range records { - r := rr.(*dnsRR_SRV) - addrs[i] = &SRV{r.Target, r.Port, r.Priority, r.Weight} + srvs := make([]*SRV, len(rrs)) + for i, rr := range rrs { + rr := rr.(*dnsRR_SRV) + srvs[i] = &SRV{Target: rr.Target, Port: rr.Port, Priority: rr.Priority, Weight: rr.Weight} } - byPriorityWeight(addrs).sort() - return + byPriorityWeight(srvs).sort() + return cname, srvs, nil } -func lookupMX(name string) (mx []*MX, err error) { - _, records, err := lookup(name, dnsTypeMX) +func lookupMX(name string) ([]*MX, error) { + _, rrs, err := lookup(name, dnsTypeMX) if err != nil { - return + return nil, err } - mx = make([]*MX, len(records)) - for i, rr := range records { - r := rr.(*dnsRR_MX) - mx[i] = &MX{r.Mx, r.Pref} + mxs := make([]*MX, len(rrs)) + for i, rr := range rrs { + rr := rr.(*dnsRR_MX) + mxs[i] = &MX{Host: rr.Mx, Pref: rr.Pref} } - byPref(mx).sort() - return + byPref(mxs).sort() + return mxs, nil } -func lookupNS(name string) (ns []*NS, err error) { - _, records, err := lookup(name, dnsTypeNS) +func lookupNS(name string) ([]*NS, error) { + _, rrs, err := lookup(name, dnsTypeNS) if err != nil { - return + return nil, err } - ns = make([]*NS, len(records)) - for i, r := range records { - r := r.(*dnsRR_NS) - ns[i] = &NS{r.Ns} + nss := make([]*NS, len(rrs)) + for i, rr := range rrs { + nss[i] = &NS{Host: rr.(*dnsRR_NS).Ns} } - return + return nss, nil } -func lookupTXT(name string) (txt []string, err error) { - _, records, err := lookup(name, dnsTypeTXT) +func lookupTXT(name string) ([]string, error) { + _, rrs, err := lookup(name, dnsTypeTXT) if err != nil { - return + return nil, err } - txt = make([]string, len(records)) - for i, r := range records { - txt[i] = r.(*dnsRR_TXT).Txt + txts := make([]string, len(rrs)) + for i, rr := range rrs { + txts[i] = rr.(*dnsRR_TXT).Txt } - return + return txts, nil } -func lookupAddr(addr string) (name []string, err error) { - name = lookupStaticAddr(addr) - if len(name) > 0 { - return - } - var arpa string - arpa, err = reverseaddr(addr) - if err != nil { - return - } - var records []dnsRR - _, records, err = lookup(arpa, dnsTypePTR) - if err != nil { - return - } - name = make([]string, len(records)) - for i := range records { - r := records[i].(*dnsRR_PTR) - name[i] = r.Ptr +func lookupAddr(addr string) ([]string, error) { + if systemConf().canUseCgo() { + if ptrs, err, ok := cgoLookupPTR(addr); ok { + return ptrs, err + } } - return + return goLookupPTR(addr) } diff --git a/libgo/go/net/lookup_windows.go b/libgo/go/net/lookup_windows.go index 6a925b0a7ad..1b6d392f660 100644 --- a/libgo/go/net/lookup_windows.go +++ b/libgo/go/net/lookup_windows.go @@ -19,13 +19,13 @@ var ( func getprotobyname(name string) (proto int, err error) { p, err := syscall.GetProtoByName(name) if err != nil { - return 0, os.NewSyscallError("GetProtoByName", err) + return 0, os.NewSyscallError("getorotobyname", err) } return int(p.Proto), nil } // lookupProtocol looks up IP protocol name and returns correspondent protocol number. -func lookupProtocol(name string) (proto int, err error) { +func lookupProtocol(name string) (int, error) { // GetProtoByName return value is stored in thread local storage. // Start new os thread before the call to prevent races. type result struct { @@ -46,47 +46,48 @@ func lookupProtocol(name string) (proto int, err error) { if proto, ok := protocols[name]; ok { return proto, nil } + r.err = &DNSError{Err: r.err.Error(), Name: name} } return r.proto, r.err } -func lookupHost(name string) (addrs []string, err error) { +func lookupHost(name string) ([]string, error) { ips, err := LookupIP(name) if err != nil { - return + return nil, err } - addrs = make([]string, 0, len(ips)) + addrs := make([]string, 0, len(ips)) for _, ip := range ips { addrs = append(addrs, ip.String()) } - return + return addrs, nil } -func gethostbyname(name string) (addrs []IP, err error) { +func gethostbyname(name string) (addrs []IPAddr, err error) { // caller already acquired thread h, err := syscall.GetHostByName(name) if err != nil { - return nil, os.NewSyscallError("GetHostByName", err) + return nil, os.NewSyscallError("gethostbyname", err) } switch h.AddrType { case syscall.AF_INET: i := 0 - addrs = make([]IP, 100) // plenty of room to grow + addrs = make([]IPAddr, 100) // plenty of room to grow for p := (*[100](*[4]byte))(unsafe.Pointer(h.AddrList)); i < cap(addrs) && p[i] != nil; i++ { - addrs[i] = IPv4(p[i][0], p[i][1], p[i][2], p[i][3]) + addrs[i] = IPAddr{IP: IPv4(p[i][0], p[i][1], p[i][2], p[i][3])} } addrs = addrs[0:i] default: // TODO(vcc): Implement non IPv4 address lookups. - return nil, os.NewSyscallError("LookupIP", syscall.EWINDOWS) + return nil, syscall.EWINDOWS } return addrs, nil } -func oldLookupIP(name string) (addrs []IP, err error) { +func oldLookupIP(name string) ([]IPAddr, error) { // GetHostByName return value is stored in thread local storage. // Start new os thread before the call to prevent races. type result struct { - addrs []IP + addrs []IPAddr err error } ch := make(chan result) @@ -99,10 +100,13 @@ func oldLookupIP(name string) (addrs []IP, err error) { ch <- result{addrs: addrs, err: err} }() r := <-ch + if r.err != nil { + r.err = &DNSError{Err: r.err.Error(), Name: name} + } return r.addrs, r.err } -func newLookupIP(name string) (addrs []IP, err error) { +func newLookupIP(name string) ([]IPAddr, error) { acquireThread() defer releaseThread() hints := syscall.AddrinfoW{ @@ -113,27 +117,28 @@ func newLookupIP(name string) (addrs []IP, err error) { var result *syscall.AddrinfoW e := syscall.GetAddrInfoW(syscall.StringToUTF16Ptr(name), nil, &hints, &result) if e != nil { - return nil, os.NewSyscallError("GetAddrInfoW", e) + return nil, &DNSError{Err: os.NewSyscallError("getaddrinfow", e).Error(), Name: name} } defer syscall.FreeAddrInfoW(result) - addrs = make([]IP, 0, 5) + addrs := make([]IPAddr, 0, 5) for ; result != nil; result = result.Next { addr := unsafe.Pointer(result.Addr) switch result.Family { case syscall.AF_INET: a := (*syscall.RawSockaddrInet4)(addr).Addr - addrs = append(addrs, IPv4(a[0], a[1], a[2], a[3])) + addrs = append(addrs, IPAddr{IP: IPv4(a[0], a[1], a[2], a[3])}) case syscall.AF_INET6: a := (*syscall.RawSockaddrInet6)(addr).Addr - addrs = append(addrs, IP{a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]}) + zone := zoneToString(int((*syscall.RawSockaddrInet6)(addr).Scope_id)) + addrs = append(addrs, IPAddr{IP: IP{a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15]}, Zone: zone}) default: - return nil, os.NewSyscallError("LookupIP", syscall.EWINDOWS) + return nil, &DNSError{Err: syscall.EWINDOWS.Error(), Name: name} } } return addrs, nil } -func getservbyname(network, service string) (port int, err error) { +func getservbyname(network, service string) (int, error) { acquireThread() defer releaseThread() switch network { @@ -144,12 +149,12 @@ func getservbyname(network, service string) (port int, err error) { } s, err := syscall.GetServByName(service, network) if err != nil { - return 0, os.NewSyscallError("GetServByName", err) + return 0, os.NewSyscallError("getservbyname", err) } return int(syscall.Ntohs(s.Port)), nil } -func oldLookupPort(network, service string) (port int, err error) { +func oldLookupPort(network, service string) (int, error) { // GetServByName return value is stored in thread local storage. // Start new os thread before the call to prevent races. type result struct { @@ -166,10 +171,13 @@ func oldLookupPort(network, service string) (port int, err error) { ch <- result{port: port, err: err} }() r := <-ch + if r.err != nil { + r.err = &DNSError{Err: r.err.Error(), Name: network + "/" + service} + } return r.port, r.err } -func newLookupPort(network, service string) (port int, err error) { +func newLookupPort(network, service string) (int, error) { acquireThread() defer releaseThread() var stype int32 @@ -187,11 +195,11 @@ func newLookupPort(network, service string) (port int, err error) { var result *syscall.AddrinfoW e := syscall.GetAddrInfoW(nil, syscall.StringToUTF16Ptr(service), &hints, &result) if e != nil { - return 0, os.NewSyscallError("GetAddrInfoW", e) + return 0, &DNSError{Err: os.NewSyscallError("getaddrinfow", e).Error(), Name: network + "/" + service} } defer syscall.FreeAddrInfoW(result) if result == nil { - return 0, os.NewSyscallError("LookupPort", syscall.EINVAL) + return 0, &DNSError{Err: syscall.EINVAL.Error(), Name: network + "/" + service} } addr := unsafe.Pointer(result.Addr) switch result.Family { @@ -202,10 +210,10 @@ func newLookupPort(network, service string) (port int, err error) { a := (*syscall.RawSockaddrInet6)(addr) return int(syscall.Ntohs(a.Port)), nil } - return 0, os.NewSyscallError("LookupPort", syscall.EINVAL) + return 0, &DNSError{Err: syscall.EINVAL.Error(), Name: network + "/" + service} } -func lookupCNAME(name string) (cname string, err error) { +func lookupCNAME(name string) (string, error) { acquireThread() defer releaseThread() var r *syscall.DNSRecord @@ -219,16 +227,16 @@ func lookupCNAME(name string) (cname string, err error) { return name, nil } if e != nil { - return "", os.NewSyscallError("LookupCNAME", e) + return "", &DNSError{Err: os.NewSyscallError("dnsquery", e).Error(), Name: name} } defer syscall.DnsRecordListFree(r, 1) resolved := resolveCNAME(syscall.StringToUTF16Ptr(name), r) - cname = syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(resolved))[:]) + "." - return + cname := syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(resolved))[:]) + "." + return cname, nil } -func lookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) { +func lookupSRV(service, proto, name string) (string, []*SRV, error) { acquireThread() defer releaseThread() var target string @@ -240,78 +248,78 @@ func lookupSRV(service, proto, name string) (cname string, addrs []*SRV, err err var r *syscall.DNSRecord e := syscall.DnsQuery(target, syscall.DNS_TYPE_SRV, 0, nil, &r, nil) if e != nil { - return "", nil, os.NewSyscallError("LookupSRV", e) + return "", nil, &DNSError{Err: os.NewSyscallError("dnsquery", e).Error(), Name: target} } defer syscall.DnsRecordListFree(r, 1) - addrs = make([]*SRV, 0, 10) + srvs := make([]*SRV, 0, 10) for _, p := range validRecs(r, syscall.DNS_TYPE_SRV, target) { v := (*syscall.DNSSRVData)(unsafe.Pointer(&p.Data[0])) - addrs = append(addrs, &SRV{syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Target))[:]), v.Port, v.Priority, v.Weight}) + srvs = append(srvs, &SRV{syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Target))[:]), v.Port, v.Priority, v.Weight}) } - byPriorityWeight(addrs).sort() - return name, addrs, nil + byPriorityWeight(srvs).sort() + return name, srvs, nil } -func lookupMX(name string) (mx []*MX, err error) { +func lookupMX(name string) ([]*MX, error) { acquireThread() defer releaseThread() var r *syscall.DNSRecord e := syscall.DnsQuery(name, syscall.DNS_TYPE_MX, 0, nil, &r, nil) if e != nil { - return nil, os.NewSyscallError("LookupMX", e) + return nil, &DNSError{Err: os.NewSyscallError("dnsquery", e).Error(), Name: name} } defer syscall.DnsRecordListFree(r, 1) - mx = make([]*MX, 0, 10) + mxs := make([]*MX, 0, 10) for _, p := range validRecs(r, syscall.DNS_TYPE_MX, name) { v := (*syscall.DNSMXData)(unsafe.Pointer(&p.Data[0])) - mx = append(mx, &MX{syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.NameExchange))[:]) + ".", v.Preference}) + mxs = append(mxs, &MX{syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.NameExchange))[:]) + ".", v.Preference}) } - byPref(mx).sort() - return mx, nil + byPref(mxs).sort() + return mxs, nil } -func lookupNS(name string) (ns []*NS, err error) { +func lookupNS(name string) ([]*NS, error) { acquireThread() defer releaseThread() var r *syscall.DNSRecord e := syscall.DnsQuery(name, syscall.DNS_TYPE_NS, 0, nil, &r, nil) if e != nil { - return nil, os.NewSyscallError("LookupNS", e) + return nil, &DNSError{Err: os.NewSyscallError("dnsquery", e).Error(), Name: name} } defer syscall.DnsRecordListFree(r, 1) - ns = make([]*NS, 0, 10) + nss := make([]*NS, 0, 10) for _, p := range validRecs(r, syscall.DNS_TYPE_NS, name) { v := (*syscall.DNSPTRData)(unsafe.Pointer(&p.Data[0])) - ns = append(ns, &NS{syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Host))[:]) + "."}) + nss = append(nss, &NS{syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Host))[:]) + "."}) } - return ns, nil + return nss, nil } -func lookupTXT(name string) (txt []string, err error) { +func lookupTXT(name string) ([]string, error) { acquireThread() defer releaseThread() var r *syscall.DNSRecord e := syscall.DnsQuery(name, syscall.DNS_TYPE_TEXT, 0, nil, &r, nil) if e != nil { - return nil, os.NewSyscallError("LookupTXT", e) + return nil, &DNSError{Err: os.NewSyscallError("dnsquery", e).Error(), Name: name} } defer syscall.DnsRecordListFree(r, 1) - txt = make([]string, 0, 10) + txts := make([]string, 0, 10) for _, p := range validRecs(r, syscall.DNS_TYPE_TEXT, name) { d := (*syscall.DNSTXTData)(unsafe.Pointer(&p.Data[0])) for _, v := range (*[1 << 10]*uint16)(unsafe.Pointer(&(d.StringArray[0])))[:d.StringCount] { s := syscall.UTF16ToString((*[1 << 20]uint16)(unsafe.Pointer(v))[:]) - txt = append(txt, s) + txts = append(txts, s) } } - return + return txts, nil } -func lookupAddr(addr string) (name []string, err error) { +func lookupAddr(addr string) ([]string, error) { acquireThread() defer releaseThread() arpa, err := reverseaddr(addr) @@ -321,16 +329,16 @@ func lookupAddr(addr string) (name []string, err error) { var r *syscall.DNSRecord e := syscall.DnsQuery(arpa, syscall.DNS_TYPE_PTR, 0, nil, &r, nil) if e != nil { - return nil, os.NewSyscallError("LookupAddr", e) + return nil, &DNSError{Err: os.NewSyscallError("dnsquery", e).Error(), Name: addr} } defer syscall.DnsRecordListFree(r, 1) - name = make([]string, 0, 10) + ptrs := make([]string, 0, 10) for _, p := range validRecs(r, syscall.DNS_TYPE_PTR, arpa) { v := (*syscall.DNSPTRData)(unsafe.Pointer(&p.Data[0])) - name = append(name, syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Host))[:])) + ptrs = append(ptrs, syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Host))[:])) } - return name, nil + return ptrs, nil } const dnsSectionMask = 0x0003 diff --git a/libgo/go/net/mac.go b/libgo/go/net/mac.go index d616b1f689f..8594a9146ae 100644 --- a/libgo/go/net/mac.go +++ b/libgo/go/net/mac.go @@ -2,12 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// MAC address manipulations - package net -import "errors" - const hexDigit = "0123456789abcdef" // A HardwareAddr represents a physical hardware address. @@ -82,5 +78,5 @@ func ParseMAC(s string) (hw HardwareAddr, err error) { return hw, nil error: - return nil, errors.New("invalid MAC address: " + s) + return nil, &AddrError{Err: "invalid MAC address", Addr: s} } diff --git a/libgo/go/net/mac_test.go b/libgo/go/net/mac_test.go index 8f9dc6685f8..0af0c014f50 100644 --- a/libgo/go/net/mac_test.go +++ b/libgo/go/net/mac_test.go @@ -10,7 +10,7 @@ import ( "testing" ) -var mactests = []struct { +var parseMACTests = []struct { in string out HardwareAddr err string @@ -36,19 +36,18 @@ var mactests = []struct { {"0123.4567.89AB.CDEF", HardwareAddr{1, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, ""}, } -func match(err error, s string) bool { - if s == "" { - return err == nil +func TestParseMAC(t *testing.T) { + match := func(err error, s string) bool { + if s == "" { + return err == nil + } + return err != nil && strings.Contains(err.Error(), s) } - return err != nil && strings.Contains(err.Error(), s) -} -func TestMACParseString(t *testing.T) { - for i, tt := range mactests { + for i, tt := range parseMACTests { 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) + 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. diff --git a/libgo/go/net/mail/example_test.go b/libgo/go/net/mail/example_test.go new file mode 100644 index 00000000000..972cfd6c424 --- /dev/null +++ b/libgo/go/net/mail/example_test.go @@ -0,0 +1,79 @@ +// Copyright 2015 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 + +package mail_test + +import ( + "fmt" + "io/ioutil" + "log" + "net/mail" + "strings" +) + +func ExampleParseAddressList() { + const list = "Alice , Bob , Eve " + emails, err := mail.ParseAddressList(list) + if err != nil { + log.Fatal(err) + } + + for _, v := range emails { + fmt.Println(v.Name, v.Address) + } + + // Output: + // Alice alice@example.com + // Bob bob@example.com + // Eve eve@example.com +} + +func ExampleParseAddress() { + e, err := mail.ParseAddress("Alice ") + if err != nil { + log.Fatal(err) + } + + fmt.Println(e.Name, e.Address) + + // Output: + // Alice alice@example.com +} + +func ExampleReadMessage() { + msg := `Date: Mon, 23 Jun 2015 11:40:36 -0400 +From: Gopher +To: Another Gopher +Subject: Gophers at Gophercon + +Message body +` + + r := strings.NewReader(msg) + m, err := mail.ReadMessage(r) + if err != nil { + log.Fatal(err) + } + + header := m.Header + fmt.Println("Date:", header.Get("Date")) + fmt.Println("From:", header.Get("From")) + fmt.Println("To:", header.Get("To")) + fmt.Println("Subject:", header.Get("Subject")) + + body, err := ioutil.ReadAll(m.Body) + if err != nil { + log.Fatal(err) + } + fmt.Printf("%s", body) + + // Output: + // Date: Mon, 23 Jun 2015 11:40:36 -0400 + // From: Gopher + // To: Another Gopher + // Subject: Gophers at Gophercon + // Message body +} diff --git a/libgo/go/net/mail/message.go b/libgo/go/net/mail/message.go index 19aa888d872..266ac50a38d 100644 --- a/libgo/go/net/mail/message.go +++ b/libgo/go/net/mail/message.go @@ -18,17 +18,14 @@ package mail import ( "bufio" "bytes" - "encoding/base64" "errors" "fmt" "io" - "io/ioutil" "log" + "mime" "net/textproto" - "strconv" "strings" "time" - "unicode" ) var debug = debugT(false) @@ -141,22 +138,79 @@ type Address struct { // Parses a single RFC 5322 address, e.g. "Barry Gibbs " func ParseAddress(address string) (*Address, error) { - return newAddrParser(address).parseAddress() + return (&addrParser{s: address}).parseAddress() } // ParseAddressList parses the given string as a list of addresses. func ParseAddressList(list string) ([]*Address, error) { - return newAddrParser(list).parseAddressList() + return (&addrParser{s: list}).parseAddressList() +} + +// An AddressParser is an RFC 5322 address parser. +type AddressParser struct { + // WordDecoder optionally specifies a decoder for RFC 2047 encoded-words. + WordDecoder *mime.WordDecoder +} + +// Parse parses a single RFC 5322 address of the +// form "Gogh Fir " or "foo@example.com". +func (p *AddressParser) Parse(address string) (*Address, error) { + return (&addrParser{s: address, dec: p.WordDecoder}).parseAddress() +} + +// ParseList parses the given string as a list of comma-separated addresses +// of the form "Gogh Fir " or "foo@example.com". +func (p *AddressParser) ParseList(list string) ([]*Address, error) { + return (&addrParser{s: list, dec: p.WordDecoder}).parseAddressList() } // String formats the address as a valid RFC 5322 address. // If the address's name contains non-ASCII characters // the name will be rendered according to RFC 2047. func (a *Address) String() string { - s := "<" + a.Address + ">" + + // Format address local@domain + at := strings.LastIndex(a.Address, "@") + var local, domain string + if at < 0 { + // This is a malformed address ("@" is required in addr-spec); + // treat the whole address as local-part. + local = a.Address + } else { + local, domain = a.Address[:at], a.Address[at+1:] + } + + // Add quotes if needed + // TODO: rendering quoted local part and rendering printable name + // should be merged in helper function. + quoteLocal := false + for i := 0; i < len(local); i++ { + ch := local[i] + if isAtext(ch, false) { + continue + } + if ch == '.' { + // Dots are okay if they are surrounded by atext. + // We only need to check that the previous byte is + // not a dot, and this isn't the end of the string. + if i > 0 && local[i-1] != '.' && i < len(local)-1 { + continue + } + } + quoteLocal = true + break + } + if quoteLocal { + local = quoteString(local) + + } + + s := "<" + local + "@" + domain + ">" + if a.Name == "" { return s } + // If every character is printable ASCII, quoting is simple. allPrintable := true for i := 0; i < len(a.Name); i++ { @@ -180,28 +234,12 @@ func (a *Address) String() string { return b.String() } - // UTF-8 "Q" encoding - b := bytes.NewBufferString("=?utf-8?q?") - for i := 0; i < len(a.Name); i++ { - switch c := a.Name[i]; { - case c == ' ': - b.WriteByte('_') - case isVchar(c) && c != '=' && c != '?' && c != '_': - b.WriteByte(c) - default: - fmt.Fprintf(b, "=%02X", c) - } - } - b.WriteString("?= ") - b.WriteString(s) - return b.String() + return mime.QEncoding.Encode("utf-8", a.Name) + " " + s } -type addrParser []byte - -func newAddrParser(s string) *addrParser { - p := addrParser(s) - return &p +type addrParser struct { + s string + dec *mime.WordDecoder // may be nil } func (p *addrParser) parseAddressList() ([]*Address, error) { @@ -227,7 +265,7 @@ func (p *addrParser) parseAddressList() ([]*Address, error) { // parseAddress parses a single RFC 5322 address at the start of p. func (p *addrParser) parseAddress() (addr *Address, err error) { - debug.Printf("parseAddress: %q", *p) + debug.Printf("parseAddress: %q", p.s) p.skipSpace() if p.empty() { return nil, errors.New("mail: no address") @@ -246,7 +284,7 @@ func (p *addrParser) parseAddress() (addr *Address, err error) { }, err } debug.Printf("parseAddress: not an addr-spec: %v", err) - debug.Printf("parseAddress: state is now %q", *p) + debug.Printf("parseAddress: state is now %q", p.s) // display-name var displayName string @@ -280,7 +318,7 @@ func (p *addrParser) parseAddress() (addr *Address, err error) { // consumeAddrSpec parses a single RFC 5322 addr-spec at the start of p. func (p *addrParser) consumeAddrSpec() (spec string, err error) { - debug.Printf("consumeAddrSpec: %q", *p) + debug.Printf("consumeAddrSpec: %q", p.s) orig := *p defer func() { @@ -302,7 +340,7 @@ func (p *addrParser) consumeAddrSpec() (spec string, err error) { } else { // dot-atom debug.Printf("consumeAddrSpec: parsing dot-atom") - localPart, err = p.consumeAtom(true) + localPart, err = p.consumeAtom(true, false) } if err != nil { debug.Printf("consumeAddrSpec: failed: %v", err) @@ -320,7 +358,7 @@ func (p *addrParser) consumeAddrSpec() (spec string, err error) { return "", errors.New("mail: no domain in addr-spec") } // TODO(dsymonds): Handle domain-literal - domain, err = p.consumeAtom(true) + domain, err = p.consumeAtom(true, false) if err != nil { return "", err } @@ -330,7 +368,7 @@ func (p *addrParser) consumeAddrSpec() (spec string, err error) { // consumePhrase parses the RFC 5322 phrase at the start of p. func (p *addrParser) consumePhrase() (phrase string, err error) { - debug.Printf("consumePhrase: [%s]", *p) + debug.Printf("consumePhrase: [%s]", p.s) // phrase = 1*word var words []string for { @@ -347,12 +385,11 @@ func (p *addrParser) consumePhrase() (phrase string, err error) { // atom // We actually parse dot-atom here to be more permissive // than what RFC 5322 specifies. - word, err = p.consumeAtom(true) + word, err = p.consumeAtom(true, true) } - // RFC 2047 encoded-word starts with =?, ends with ?=, and has two other ?s. - if err == nil && strings.HasPrefix(word, "=?") && strings.HasSuffix(word, "?=") && strings.Count(word, "?") == 4 { - word, err = decodeRFC2047Word(word) + if err == nil { + word, err = p.decodeRFC2047Word(word) } if err != nil { @@ -380,16 +417,16 @@ Loop: if i >= p.len() { return "", errors.New("mail: unclosed quoted-string") } - switch c := (*p)[i]; { + switch c := p.s[i]; { case c == '"': break Loop case c == '\\': if i+1 == p.len() { return "", errors.New("mail: unclosed quoted-string") } - qsb = append(qsb, (*p)[i+1]) + qsb = append(qsb, p.s[i+1]) i += 2 - case isQtext(c), c == ' ' || c == '\t': + case isQtext(c), c == ' ': // qtext (printable US-ASCII excluding " and \), or // FWS (almost; we're ignoring CRLF) qsb = append(qsb, c) @@ -398,20 +435,36 @@ Loop: return "", fmt.Errorf("mail: bad character in quoted-string: %q", c) } } - *p = (*p)[i+1:] + p.s = p.s[i+1:] + if len(qsb) == 0 { + return "", errors.New("mail: empty quoted-string") + } return string(qsb), nil } // consumeAtom parses an RFC 5322 atom at the start of p. // If dot is true, consumeAtom parses an RFC 5322 dot-atom instead. -func (p *addrParser) consumeAtom(dot bool) (atom string, err error) { +// If permissive is true, consumeAtom will not fail on +// leading/trailing/double dots in the atom (see golang.org/issue/4938). +func (p *addrParser) consumeAtom(dot bool, permissive bool) (atom string, err error) { if !isAtext(p.peek(), false) { return "", errors.New("mail: invalid string") } i := 1 - for ; i < p.len() && isAtext((*p)[i], dot); i++ { + for ; i < p.len() && isAtext(p.s[i], dot); i++ { + } + atom, p.s = string(p.s[:i]), p.s[i:] + if !permissive { + if strings.HasPrefix(atom, ".") { + return "", errors.New("mail: leading dot in atom") + } + if strings.Contains(atom, "..") { + return "", errors.New("mail: double dot in atom") + } + if strings.HasSuffix(atom, ".") { + return "", errors.New("mail: trailing dot in atom") + } } - atom, *p = string((*p)[:i]), (*p)[i:] return atom, nil } @@ -419,17 +472,17 @@ func (p *addrParser) consume(c byte) bool { if p.empty() || p.peek() != c { return false } - *p = (*p)[1:] + p.s = p.s[1:] return true } // skipSpace skips the leading space and tab characters. func (p *addrParser) skipSpace() { - *p = bytes.TrimLeft(*p, " \t") + p.s = strings.TrimLeft(p.s, " \t") } func (p *addrParser) peek() byte { - return (*p)[0] + return p.s[0] } func (p *addrParser) empty() bool { @@ -437,87 +490,37 @@ func (p *addrParser) empty() bool { } func (p *addrParser) len() int { - return len(*p) + return len(p.s) } -func decodeRFC2047Word(s string) (string, error) { - fields := strings.Split(s, "?") - if len(fields) != 5 || fields[0] != "=" || fields[4] != "=" { - return "", errors.New("address not RFC 2047 encoded") - } - charset, enc := strings.ToLower(fields[1]), strings.ToLower(fields[2]) - if charset != "us-ascii" && charset != "iso-8859-1" && charset != "utf-8" { - return "", fmt.Errorf("charset not supported: %q", charset) +func (p *addrParser) decodeRFC2047Word(s string) (string, error) { + if p.dec != nil { + return p.dec.DecodeHeader(s) } - in := bytes.NewBufferString(fields[3]) - var r io.Reader - switch enc { - case "b": - r = base64.NewDecoder(base64.StdEncoding, in) - case "q": - r = qDecoder{r: in} - default: - return "", fmt.Errorf("RFC 2047 encoding not supported: %q", enc) + dec, err := rfc2047Decoder.Decode(s) + if err == nil { + return dec, nil } - dec, err := ioutil.ReadAll(r) - if err != nil { - return "", err + if _, ok := err.(charsetError); ok { + return s, err } - switch charset { - case "us-ascii": - b := new(bytes.Buffer) - for _, c := range dec { - if c >= 0x80 { - b.WriteRune(unicode.ReplacementChar) - } else { - b.WriteRune(rune(c)) - } - } - return b.String(), nil - case "iso-8859-1": - b := new(bytes.Buffer) - for _, c := range dec { - b.WriteRune(rune(c)) - } - return b.String(), nil - case "utf-8": - return string(dec), nil - } - panic("unreachable") + // Ignore invalid RFC 2047 encoded-word errors. + return s, nil } -type qDecoder struct { - r io.Reader - scratch [2]byte +var rfc2047Decoder = mime.WordDecoder{ + CharsetReader: func(charset string, input io.Reader) (io.Reader, error) { + return nil, charsetError(charset) + }, } -func (qd qDecoder) Read(p []byte) (n int, err error) { - // This method writes at most one byte into p. - if len(p) == 0 { - return 0, nil - } - if _, err := qd.r.Read(qd.scratch[:1]); err != nil { - return 0, err - } - switch c := qd.scratch[0]; { - case c == '=': - if _, err := io.ReadFull(qd.r, qd.scratch[:2]); err != nil { - return 0, err - } - x, err := strconv.ParseInt(string(qd.scratch[:2]), 16, 64) - if err != nil { - return 0, fmt.Errorf("mail: invalid RFC 2047 encoding: %q", qd.scratch[:2]) - } - p[0] = byte(x) - case c == '_': - p[0] = ' ' - default: - p[0] = c - } - return 1, nil +type charsetError string + +func (e charsetError) Error() string { + return fmt.Sprintf("charset not supported: %q", string(e)) } var atextChars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZ" + @@ -525,7 +528,7 @@ var atextChars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789" + "!#$%&'*+-/=?^_`{|}~") -// isAtext returns true if c is an RFC 5322 atext character. +// isAtext reports whether c is an RFC 5322 atext character. // If dot is true, period is included. func isAtext(c byte, dot bool) bool { if dot && c == '.' { @@ -534,7 +537,7 @@ func isAtext(c byte, dot bool) bool { return bytes.IndexByte(atextChars, c) >= 0 } -// isQtext returns true if c is an RFC 5322 qtext character. +// isQtext reports whether c is an RFC 5322 qtext character. func isQtext(c byte) bool { // Printable US-ASCII, excluding backslash or quote. if c == '\\' || c == '"' { @@ -543,13 +546,30 @@ func isQtext(c byte) bool { return '!' <= c && c <= '~' } -// isVchar returns true if c is an RFC 5322 VCHAR character. +// quoteString renders a string as a RFC5322 quoted-string. +func quoteString(s string) string { + var buf bytes.Buffer + buf.WriteByte('"') + for _, c := range s { + ch := byte(c) + if isQtext(ch) || isWSP(ch) { + buf.WriteByte(ch) + } else if isVchar(ch) { + buf.WriteByte('\\') + buf.WriteByte(ch) + } + } + buf.WriteByte('"') + return buf.String() +} + +// isVchar reports whether c is an RFC 5322 VCHAR character. func isVchar(c byte) bool { // Visible (printing) characters. return '!' <= c && c <= '~' } -// isWSP returns true if c is a WSP (white space). +// isWSP reports whether c is a WSP (white space). // WSP is a space or horizontal tab (RFC5234 Appendix B). func isWSP(c byte) bool { return c == ' ' || c == '\t' diff --git a/libgo/go/net/mail/message_test.go b/libgo/go/net/mail/message_test.go index 6ba48be04fa..1b422743f95 100644 --- a/libgo/go/net/mail/message_test.go +++ b/libgo/go/net/mail/message_test.go @@ -6,7 +6,9 @@ package mail import ( "bytes" + "io" "io/ioutil" + "mime" "reflect" "strings" "testing" @@ -278,6 +280,175 @@ func TestAddressParsing(t *testing.T) { } } +func TestAddressParser(t *testing.T) { + tests := []struct { + addrsStr string + exp []*Address + }{ + // Bare address + { + `jdoe@machine.example`, + []*Address{{ + Address: "jdoe@machine.example", + }}, + }, + // RFC 5322, Appendix A.1.1 + { + `John Doe `, + []*Address{{ + Name: "John Doe", + Address: "jdoe@machine.example", + }}, + }, + // RFC 5322, Appendix A.1.2 + { + `"Joe Q. Public" `, + []*Address{{ + Name: "Joe Q. Public", + Address: "john.q.public@example.com", + }}, + }, + { + `Mary Smith , jdoe@example.org, Who? `, + []*Address{ + { + Name: "Mary Smith", + Address: "mary@x.test", + }, + { + Address: "jdoe@example.org", + }, + { + Name: "Who?", + Address: "one@y.test", + }, + }, + }, + { + `, "Giant; \"Big\" Box" `, + []*Address{ + { + Address: "boss@nil.test", + }, + { + Name: `Giant; "Big" Box`, + Address: "sysservices@example.net", + }, + }, + }, + // RFC 2047 "Q"-encoded ISO-8859-1 address. + { + `=?iso-8859-1?q?J=F6rg_Doe?= `, + []*Address{ + { + Name: `Jörg Doe`, + Address: "joerg@example.com", + }, + }, + }, + // RFC 2047 "Q"-encoded US-ASCII address. Dumb but legal. + { + `=?us-ascii?q?J=6Frg_Doe?= `, + []*Address{ + { + Name: `Jorg Doe`, + Address: "joerg@example.com", + }, + }, + }, + // RFC 2047 "Q"-encoded ISO-8859-15 address. + { + `=?ISO-8859-15?Q?J=F6rg_Doe?= `, + []*Address{ + { + Name: `Jörg Doe`, + Address: "joerg@example.com", + }, + }, + }, + // RFC 2047 "B"-encoded windows-1252 address. + { + `=?windows-1252?q?Andr=E9?= Pirard `, + []*Address{ + { + Name: `André Pirard`, + Address: "PIRARD@vm1.ulg.ac.be", + }, + }, + }, + // Custom example of RFC 2047 "B"-encoded ISO-8859-15 address. + { + `=?ISO-8859-15?B?SvZyZw==?= `, + []*Address{ + { + Name: `Jörg`, + Address: "joerg@example.com", + }, + }, + }, + // Custom example of RFC 2047 "B"-encoded UTF-8 address. + { + `=?UTF-8?B?SsO2cmc=?= `, + []*Address{ + { + Name: `Jörg`, + Address: "joerg@example.com", + }, + }, + }, + // Custom example with "." in name. For issue 4938 + { + `Asem H. `, + []*Address{ + { + Name: `Asem H.`, + Address: "noreply@example.com", + }, + }, + }, + } + + ap := AddressParser{WordDecoder: &mime.WordDecoder{ + CharsetReader: func(charset string, input io.Reader) (io.Reader, error) { + in, err := ioutil.ReadAll(input) + if err != nil { + return nil, err + } + + switch charset { + case "iso-8859-15": + in = bytes.Replace(in, []byte("\xf6"), []byte("ö"), -1) + case "windows-1252": + in = bytes.Replace(in, []byte("\xe9"), []byte("é"), -1) + } + + return bytes.NewReader(in), nil + }, + }} + + for _, test := range tests { + if len(test.exp) == 1 { + addr, err := ap.Parse(test.addrsStr) + if err != nil { + t.Errorf("Failed parsing (single) %q: %v", test.addrsStr, err) + continue + } + if !reflect.DeepEqual([]*Address{addr}, test.exp) { + t.Errorf("Parse (single) of %q: got %+v, want %+v", test.addrsStr, addr, test.exp) + } + } + + addrs, err := ap.ParseList(test.addrsStr) + if err != nil { + t.Errorf("Failed parsing (list) %q: %v", test.addrsStr, err) + continue + } + if !reflect.DeepEqual(addrs, test.exp) { + t.Errorf("Parse (list) of %q: got %+v, want %+v", test.addrsStr, addrs, test.exp) + } + } +} + func TestAddressFormatting(t *testing.T) { tests := []struct { addr *Address @@ -287,6 +458,14 @@ func TestAddressFormatting(t *testing.T) { &Address{Address: "bob@example.com"}, "", }, + { // quoted local parts: RFC 5322, 3.4.1. and 3.2.4. + &Address{Address: `my@idiot@address@example.com`}, + `<"my@idiot@address"@example.com>`, + }, + { // quoted local parts + &Address{Address: ` @example.com`}, + `<" "@example.com>`, + }, { &Address{Name: "Bob", Address: "bob@example.com"}, `"Bob" `, @@ -304,6 +483,14 @@ func TestAddressFormatting(t *testing.T) { &Address{Name: "Böb Jacöb", Address: "bob@example.com"}, `=?utf-8?q?B=C3=B6b_Jac=C3=B6b?= `, }, + { // https://golang.org/issue/12098 + &Address{Name: "Rob", Address: ""}, + `"Rob" <@>`, + }, + { // https://golang.org/issue/12098 + &Address{Name: "Rob", Address: "@"}, + `"Rob" <@>`, + }, } for _, test := range tests { s := test.addr.String() @@ -312,3 +499,90 @@ func TestAddressFormatting(t *testing.T) { } } } + +// Check if all valid addresses can be parsed, formatted and parsed again +func TestAddressParsingAndFormatting(t *testing.T) { + + // Should pass + tests := []string{ + ``, + ``, + `<".bob"@example.com>`, + `<" "@example.com>`, + ``, + `<"dot.and space"@example.com>`, + `<"very.unusual.@.unusual.com"@example.com>`, + ``, + ``, + "<#!$%&'*+-/=?^_`{}|~@example.org>", + `<"very.(),:;<>[]\".VERY.\"very@\\ \"very\".unusual"@strange.example.com>`, // escaped quotes + `<"()<>[]:,;@\\\"!#$%&'*+-/=?^_{}| ~.a"@example.org>`, // escaped backslashes + `<"Abc\\@def"@example.com>`, + `<"Joe\\Blow"@example.com>`, + ``, + ``, + `<_somename@example.com>`, + ``, + `<~@example.com>`, + `<"..."@test.com>`, + `<"john..doe"@example.com>`, + `<"john.doe."@example.com>`, + `<".john.doe"@example.com>`, + `<"."@example.com>`, + `<".."@example.com>`, + `<"0:"@0>`, + } + + for _, test := range tests { + addr, err := ParseAddress(test) + if err != nil { + t.Errorf("Couldn't parse address %s: %s", test, err.Error()) + continue + } + str := addr.String() + addr, err = ParseAddress(str) + if err != nil { + t.Errorf("ParseAddr(%q) error: %v", test, err) + continue + } + + if addr.String() != test { + t.Errorf("String() round-trip = %q; want %q", addr, test) + continue + } + + } + + // Should fail + badTests := []string{ + ``, + ``, + `i[j\k]l@example.com>`, + ``, + ``, + ``, + ``, + ``, + ``, + ``, + ``, + `<.john.doe@example.com>`, + `<@example.com>`, + `<.@example.com>`, + ``, + `< @example.com>`, + `<""test""blah""@example.com>`, + `<""@0>`, + "<\"\t0\"@0>", + } + + for _, test := range badTests { + _, err := ParseAddress(test) + if err == nil { + t.Errorf("Should have failed to parse address: %s", test) + continue + } + + } + +} diff --git a/libgo/go/net/main_cloexec_test.go b/libgo/go/net/main_cloexec_test.go new file mode 100644 index 00000000000..79038195859 --- /dev/null +++ b/libgo/go/net/main_cloexec_test.go @@ -0,0 +1,25 @@ +// Copyright 2015 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 freebsd linux + +package net + +func init() { + extraTestHookInstallers = append(extraTestHookInstallers, installAccept4TestHook) + extraTestHookUninstallers = append(extraTestHookUninstallers, uninstallAccept4TestHook) +} + +var ( + // Placeholders for saving original socket system calls. + origAccept4 = accept4Func +) + +func installAccept4TestHook() { + accept4Func = sw.Accept4 +} + +func uninstallAccept4TestHook() { + accept4Func = origAccept4 +} diff --git a/libgo/go/net/main_plan9_test.go b/libgo/go/net/main_plan9_test.go new file mode 100644 index 00000000000..94501cada9a --- /dev/null +++ b/libgo/go/net/main_plan9_test.go @@ -0,0 +1,15 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package net + +func installTestHooks() {} + +func uninstallTestHooks() {} + +func forceCloseSockets() {} + +func enableSocketConnect() {} + +func disableSocketConnect(network string) {} diff --git a/libgo/go/net/main_posix_test.go b/libgo/go/net/main_posix_test.go new file mode 100644 index 00000000000..ead311c3cdd --- /dev/null +++ b/libgo/go/net/main_posix_test.go @@ -0,0 +1,50 @@ +// Copyright 2015 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 !plan9 + +package net + +import ( + "net/internal/socktest" + "strings" + "syscall" +) + +func enableSocketConnect() { + sw.Set(socktest.FilterConnect, nil) +} + +func disableSocketConnect(network string) { + ss := strings.Split(network, ":") + sw.Set(socktest.FilterConnect, func(so *socktest.Status) (socktest.AfterFilter, error) { + switch ss[0] { + case "tcp4": + if so.Cookie.Family() == syscall.AF_INET && so.Cookie.Type() == syscall.SOCK_STREAM { + return nil, syscall.EHOSTUNREACH + } + case "udp4": + if so.Cookie.Family() == syscall.AF_INET && so.Cookie.Type() == syscall.SOCK_DGRAM { + return nil, syscall.EHOSTUNREACH + } + case "ip4": + if so.Cookie.Family() == syscall.AF_INET && so.Cookie.Type() == syscall.SOCK_RAW { + return nil, syscall.EHOSTUNREACH + } + case "tcp6": + if so.Cookie.Family() == syscall.AF_INET6 && so.Cookie.Type() == syscall.SOCK_STREAM { + return nil, syscall.EHOSTUNREACH + } + case "udp6": + if so.Cookie.Family() == syscall.AF_INET6 && so.Cookie.Type() == syscall.SOCK_DGRAM { + return nil, syscall.EHOSTUNREACH + } + case "ip6": + if so.Cookie.Family() == syscall.AF_INET6 && so.Cookie.Type() == syscall.SOCK_RAW { + return nil, syscall.EHOSTUNREACH + } + } + return nil, nil + }) +} diff --git a/libgo/go/net/main_test.go b/libgo/go/net/main_test.go new file mode 100644 index 00000000000..f3f8b1a9002 --- /dev/null +++ b/libgo/go/net/main_test.go @@ -0,0 +1,204 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package net + +import ( + "flag" + "fmt" + "net/internal/socktest" + "os" + "runtime" + "sort" + "strings" + "sync" + "testing" +) + +var ( + sw socktest.Switch + + // uninstallTestHooks runs just before a run of benchmarks. + testHookUninstaller sync.Once +) + +var ( + testDNSFlood = flag.Bool("dnsflood", false, "whether to test DNS query flooding") + + testExternal = flag.Bool("external", true, "allow use of external networks during long test") + + // If external IPv4 connectivity exists, we can try dialing + // non-node/interface local scope IPv4 addresses. + // On Windows, Lookup APIs may not return IPv4-related + // resource records when a node has no external IPv4 + // connectivity. + testIPv4 = flag.Bool("ipv4", true, "assume external IPv4 connectivity exists") + + // If external IPv6 connectivity exists, we can try dialing + // non-node/interface local scope IPv6 addresses. + // On Windows, Lookup APIs may not return IPv6-related + // resource records when a node has no external IPv6 + // connectivity. + testIPv6 = flag.Bool("ipv6", false, "assume external IPv6 connectivity exists") +) + +func TestMain(m *testing.M) { + setupTestData() + installTestHooks() + + st := m.Run() + + testHookUninstaller.Do(uninstallTestHooks) + if testing.Verbose() { + printRunningGoroutines() + printInflightSockets() + printSocketStats() + } + forceCloseSockets() + os.Exit(st) +} + +type ipv6LinkLocalUnicastTest struct { + network, address string + nameLookup bool +} + +var ( + ipv6LinkLocalUnicastTCPTests []ipv6LinkLocalUnicastTest + ipv6LinkLocalUnicastUDPTests []ipv6LinkLocalUnicastTest +) + +func setupTestData() { + if supportsIPv4 { + resolveTCPAddrTests = append(resolveTCPAddrTests, []resolveTCPAddrTest{ + {"tcp", "localhost:1", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 1}, nil}, + {"tcp4", "localhost:2", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 2}, nil}, + }...) + resolveUDPAddrTests = append(resolveUDPAddrTests, []resolveUDPAddrTest{ + {"udp", "localhost:1", &UDPAddr{IP: IPv4(127, 0, 0, 1), Port: 1}, nil}, + {"udp4", "localhost:2", &UDPAddr{IP: IPv4(127, 0, 0, 1), Port: 2}, nil}, + }...) + resolveIPAddrTests = append(resolveIPAddrTests, []resolveIPAddrTest{ + {"ip", "localhost", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil}, + {"ip4", "localhost", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil}, + }...) + } + + if supportsIPv6 { + resolveTCPAddrTests = append(resolveTCPAddrTests, resolveTCPAddrTest{"tcp6", "localhost:3", &TCPAddr{IP: IPv6loopback, Port: 3}, nil}) + resolveUDPAddrTests = append(resolveUDPAddrTests, resolveUDPAddrTest{"udp6", "localhost:3", &UDPAddr{IP: IPv6loopback, Port: 3}, nil}) + resolveIPAddrTests = append(resolveIPAddrTests, resolveIPAddrTest{"ip6", "localhost", &IPAddr{IP: IPv6loopback}, nil}) + } + + ifi := loopbackInterface() + if ifi != nil { + index := fmt.Sprintf("%v", ifi.Index) + resolveTCPAddrTests = append(resolveTCPAddrTests, []resolveTCPAddrTest{ + {"tcp6", "[fe80::1%" + ifi.Name + "]:1", &TCPAddr{IP: ParseIP("fe80::1"), Port: 1, Zone: zoneToString(ifi.Index)}, nil}, + {"tcp6", "[fe80::1%" + index + "]:2", &TCPAddr{IP: ParseIP("fe80::1"), Port: 2, Zone: index}, nil}, + }...) + resolveUDPAddrTests = append(resolveUDPAddrTests, []resolveUDPAddrTest{ + {"udp6", "[fe80::1%" + ifi.Name + "]:1", &UDPAddr{IP: ParseIP("fe80::1"), Port: 1, Zone: zoneToString(ifi.Index)}, nil}, + {"udp6", "[fe80::1%" + index + "]:2", &UDPAddr{IP: ParseIP("fe80::1"), Port: 2, Zone: index}, nil}, + }...) + resolveIPAddrTests = append(resolveIPAddrTests, []resolveIPAddrTest{ + {"ip6", "fe80::1%" + ifi.Name, &IPAddr{IP: ParseIP("fe80::1"), Zone: zoneToString(ifi.Index)}, nil}, + {"ip6", "fe80::1%" + index, &IPAddr{IP: ParseIP("fe80::1"), Zone: index}, nil}, + }...) + } + + addr := ipv6LinkLocalUnicastAddr(ifi) + if addr != "" { + if runtime.GOOS != "dragonfly" { + ipv6LinkLocalUnicastTCPTests = append(ipv6LinkLocalUnicastTCPTests, []ipv6LinkLocalUnicastTest{ + {"tcp", "[" + addr + "%" + ifi.Name + "]:0", false}, + }...) + ipv6LinkLocalUnicastUDPTests = append(ipv6LinkLocalUnicastUDPTests, []ipv6LinkLocalUnicastTest{ + {"udp", "[" + addr + "%" + ifi.Name + "]:0", false}, + }...) + } + ipv6LinkLocalUnicastTCPTests = append(ipv6LinkLocalUnicastTCPTests, []ipv6LinkLocalUnicastTest{ + {"tcp6", "[" + addr + "%" + ifi.Name + "]:0", false}, + }...) + ipv6LinkLocalUnicastUDPTests = append(ipv6LinkLocalUnicastUDPTests, []ipv6LinkLocalUnicastTest{ + {"udp6", "[" + addr + "%" + ifi.Name + "]:0", false}, + }...) + switch runtime.GOOS { + case "darwin", "dragonfly", "freebsd", "openbsd", "netbsd": + ipv6LinkLocalUnicastTCPTests = append(ipv6LinkLocalUnicastTCPTests, []ipv6LinkLocalUnicastTest{ + {"tcp", "[localhost%" + ifi.Name + "]:0", true}, + {"tcp6", "[localhost%" + ifi.Name + "]:0", true}, + }...) + ipv6LinkLocalUnicastUDPTests = append(ipv6LinkLocalUnicastUDPTests, []ipv6LinkLocalUnicastTest{ + {"udp", "[localhost%" + ifi.Name + "]:0", true}, + {"udp6", "[localhost%" + ifi.Name + "]:0", true}, + }...) + case "linux": + ipv6LinkLocalUnicastTCPTests = append(ipv6LinkLocalUnicastTCPTests, []ipv6LinkLocalUnicastTest{ + {"tcp", "[ip6-localhost%" + ifi.Name + "]:0", true}, + {"tcp6", "[ip6-localhost%" + ifi.Name + "]:0", true}, + }...) + ipv6LinkLocalUnicastUDPTests = append(ipv6LinkLocalUnicastUDPTests, []ipv6LinkLocalUnicastTest{ + {"udp", "[ip6-localhost%" + ifi.Name + "]:0", true}, + {"udp6", "[ip6-localhost%" + ifi.Name + "]:0", true}, + }...) + } + } +} + +func printRunningGoroutines() { + gss := runningGoroutines() + if len(gss) == 0 { + return + } + fmt.Fprintf(os.Stderr, "Running goroutines:\n") + for _, gs := range gss { + fmt.Fprintf(os.Stderr, "%v\n", gs) + } + fmt.Fprintf(os.Stderr, "\n") +} + +// runningGoroutines returns a list of remaining goroutines. +func runningGoroutines() []string { + var gss []string + b := make([]byte, 2<<20) + b = b[:runtime.Stack(b, true)] + for _, s := range strings.Split(string(b), "\n\n") { + ss := strings.SplitN(s, "\n", 2) + if len(ss) != 2 { + continue + } + stack := strings.TrimSpace(ss[1]) + if !strings.Contains(stack, "created by net") { + continue + } + gss = append(gss, stack) + } + sort.Strings(gss) + return gss +} + +func printInflightSockets() { + sos := sw.Sockets() + if len(sos) == 0 { + return + } + fmt.Fprintf(os.Stderr, "Inflight sockets:\n") + for s, so := range sos { + fmt.Fprintf(os.Stderr, "%v: %v\n", s, so) + } + fmt.Fprintf(os.Stderr, "\n") +} + +func printSocketStats() { + sts := sw.Stats() + if len(sts) == 0 { + return + } + fmt.Fprintf(os.Stderr, "Socket statistical information:\n") + for _, st := range sts { + fmt.Fprintf(os.Stderr, "%v\n", st) + } + fmt.Fprintf(os.Stderr, "\n") +} diff --git a/libgo/go/net/main_unix_test.go b/libgo/go/net/main_unix_test.go new file mode 100644 index 00000000000..bfb4cd0065c --- /dev/null +++ b/libgo/go/net/main_unix_test.go @@ -0,0 +1,52 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris + +package net + +var ( + // Placeholders for saving original socket system calls. + origSocket = socketFunc + origClose = closeFunc + origConnect = connectFunc + origListen = listenFunc + origAccept = acceptFunc + origGetsockoptInt = getsockoptIntFunc + + extraTestHookInstallers []func() + extraTestHookUninstallers []func() +) + +func installTestHooks() { + socketFunc = sw.Socket + closeFunc = sw.Close + connectFunc = sw.Connect + listenFunc = sw.Listen + acceptFunc = sw.Accept + getsockoptIntFunc = sw.GetsockoptInt + + for _, fn := range extraTestHookInstallers { + fn() + } +} + +func uninstallTestHooks() { + socketFunc = origSocket + closeFunc = origClose + connectFunc = origConnect + listenFunc = origListen + acceptFunc = origAccept + getsockoptIntFunc = origGetsockoptInt + + for _, fn := range extraTestHookUninstallers { + fn() + } +} + +func forceCloseSockets() { + for s := range sw.Sockets() { + closeFunc(s) + } +} diff --git a/libgo/go/net/main_windows_test.go b/libgo/go/net/main_windows_test.go new file mode 100644 index 00000000000..2d829743ec5 --- /dev/null +++ b/libgo/go/net/main_windows_test.go @@ -0,0 +1,36 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package net + +var ( + // Placeholders for saving original socket system calls. + origSocket = socketFunc + origClosesocket = closeFunc + origConnect = connectFunc + origConnectEx = connectExFunc + origListen = listenFunc +) + +func installTestHooks() { + socketFunc = sw.Socket + closeFunc = sw.Closesocket + connectFunc = sw.Connect + connectExFunc = sw.ConnectEx + listenFunc = sw.Listen +} + +func uninstallTestHooks() { + socketFunc = origSocket + closeFunc = origClosesocket + connectFunc = origConnect + connectExFunc = origConnectEx + listenFunc = origListen +} + +func forceCloseSockets() { + for s := range sw.Sockets() { + closeFunc(s) + } +} diff --git a/libgo/go/net/mockicmp_test.go b/libgo/go/net/mockicmp_test.go deleted file mode 100644 index e742365ea03..00000000000 --- a/libgo/go/net/mockicmp_test.go +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package net - -import "errors" - -const ( - icmpv4EchoRequest = 8 - icmpv4EchoReply = 0 - icmpv6EchoRequest = 128 - icmpv6EchoReply = 129 -) - -// icmpMessage represents an ICMP message. -type icmpMessage struct { - Type int // type - Code int // code - Checksum int // checksum - Body icmpMessageBody // body -} - -// icmpMessageBody represents an ICMP message body. -type icmpMessageBody interface { - Len() int - Marshal() ([]byte, error) -} - -// Marshal returns the binary enconding of the ICMP echo request or -// reply message m. -func (m *icmpMessage) Marshal() ([]byte, error) { - b := []byte{byte(m.Type), byte(m.Code), 0, 0} - if m.Body != nil && m.Body.Len() != 0 { - mb, err := m.Body.Marshal() - if err != nil { - return nil, err - } - b = append(b, mb...) - } - switch m.Type { - case icmpv6EchoRequest, icmpv6EchoReply: - return b, nil - } - csumcv := len(b) - 1 // checksum coverage - s := uint32(0) - for i := 0; i < csumcv; i += 2 { - s += uint32(b[i+1])<<8 | uint32(b[i]) - } - if csumcv&1 == 0 { - s += uint32(b[csumcv]) - } - s = s>>16 + s&0xffff - s = s + s>>16 - // Place checksum back in header; using ^= avoids the - // assumption the checksum bytes are zero. - b[2] ^= byte(^s) - b[3] ^= byte(^s >> 8) - return b, nil -} - -// parseICMPMessage parses b as an ICMP message. -func parseICMPMessage(b []byte) (*icmpMessage, error) { - msglen := len(b) - if msglen < 4 { - return nil, errors.New("message too short") - } - m := &icmpMessage{Type: int(b[0]), Code: int(b[1]), Checksum: int(b[2])<<8 | int(b[3])} - if msglen > 4 { - var err error - switch m.Type { - case icmpv4EchoRequest, icmpv4EchoReply, icmpv6EchoRequest, icmpv6EchoReply: - m.Body, err = parseICMPEcho(b[4:]) - if err != nil { - return nil, err - } - } - } - return m, nil -} - -// imcpEcho represenets an ICMP echo request or reply message body. -type icmpEcho struct { - ID int // identifier - Seq int // sequence number - Data []byte // data -} - -func (p *icmpEcho) Len() int { - if p == nil { - return 0 - } - return 4 + len(p.Data) -} - -// Marshal returns the binary enconding of the ICMP echo request or -// reply message body p. -func (p *icmpEcho) Marshal() ([]byte, error) { - b := make([]byte, 4+len(p.Data)) - b[0], b[1] = byte(p.ID>>8), byte(p.ID) - b[2], b[3] = byte(p.Seq>>8), byte(p.Seq) - copy(b[4:], p.Data) - return b, nil -} - -// parseICMPEcho parses b as an ICMP echo request or reply message -// body. -func parseICMPEcho(b []byte) (*icmpEcho, error) { - bodylen := len(b) - p := &icmpEcho{ID: int(b[0])<<8 | int(b[1]), Seq: int(b[2])<<8 | int(b[3])} - if bodylen > 4 { - p.Data = make([]byte, bodylen-4) - copy(p.Data, b[4:]) - } - return p, nil -} diff --git a/libgo/go/net/mockserver_test.go b/libgo/go/net/mockserver_test.go index 68ded5d7577..dd6f4df3b9c 100644 --- a/libgo/go/net/mockserver_test.go +++ b/libgo/go/net/mockserver_test.go @@ -4,11 +4,123 @@ package net -import "sync" +import ( + "errors" + "fmt" + "io/ioutil" + "os" + "sync" + "testing" + "time" +) + +// testUnixAddr uses ioutil.TempFile to get a name that is unique. +// It also uses /tmp directory in case it is prohibited to create UNIX +// sockets in TMPDIR. +func testUnixAddr() string { + f, err := ioutil.TempFile("", "go-nettest") + if err != nil { + panic(err) + } + addr := f.Name() + f.Close() + os.Remove(addr) + return addr +} + +func newLocalListener(network string) (Listener, error) { + switch network { + case "tcp", "tcp4", "tcp6": + if supportsIPv4 { + return Listen("tcp4", "127.0.0.1:0") + } + if supportsIPv6 { + return Listen("tcp6", "[::1]:0") + } + case "unix", "unixpacket": + return Listen(network, testUnixAddr()) + } + return nil, fmt.Errorf("%s is not supported", network) +} + +func newDualStackListener() (lns []*TCPListener, err error) { + var args = []struct { + network string + TCPAddr + }{ + {"tcp4", TCPAddr{IP: IPv4(127, 0, 0, 1)}}, + {"tcp6", TCPAddr{IP: IPv6loopback}}, + } + for i := 0; i < 64; i++ { + var port int + var lns []*TCPListener + for _, arg := range args { + arg.TCPAddr.Port = port + ln, err := ListenTCP(arg.network, &arg.TCPAddr) + if err != nil { + continue + } + port = ln.Addr().(*TCPAddr).Port + lns = append(lns, ln) + } + if len(lns) != len(args) { + for _, ln := range lns { + ln.Close() + } + continue + } + return lns, nil + } + return nil, errors.New("no dualstack port available") +} + +type localServer struct { + lnmu sync.RWMutex + Listener + done chan bool // signal that indicates server stopped +} + +func (ls *localServer) buildup(handler func(*localServer, Listener)) error { + go func() { + handler(ls, ls.Listener) + close(ls.done) + }() + return nil +} + +func (ls *localServer) teardown() error { + ls.lnmu.Lock() + if ls.Listener != nil { + network := ls.Listener.Addr().Network() + address := ls.Listener.Addr().String() + ls.Listener.Close() + <-ls.done + ls.Listener = nil + switch network { + case "unix", "unixpacket": + os.Remove(address) + } + } + ls.lnmu.Unlock() + return nil +} + +func newLocalServer(network string) (*localServer, error) { + ln, err := newLocalListener(network) + if err != nil { + return nil, err + } + return &localServer{Listener: ln, done: make(chan bool)}, nil +} type streamListener struct { - net, addr string - ln Listener + network, address string + Listener + done chan bool // signal that indicates server stopped +} + +func (sl *streamListener) newLocalServer() (*localServer, error) { + return &localServer{Listener: sl.Listener, done: make(chan bool)}, nil } type dualStackServer struct { @@ -20,9 +132,12 @@ type dualStackServer struct { cs []Conn // established connections at the passive open side } -func (dss *dualStackServer) buildup(server func(*dualStackServer, Listener)) error { +func (dss *dualStackServer) buildup(handler func(*dualStackServer, Listener)) error { for i := range dss.lns { - go server(dss, dss.lns[i].ln) + go func(i int) { + handler(dss, dss.lns[i].Listener) + close(dss.lns[i].done) + }(i) } return nil } @@ -34,12 +149,13 @@ func (dss *dualStackServer) putConn(c Conn) error { return nil } -func (dss *dualStackServer) teardownNetwork(net string) error { +func (dss *dualStackServer) teardownNetwork(network string) error { dss.lnmu.Lock() for i := range dss.lns { - if net == dss.lns[i].net && dss.lns[i].ln != nil { - dss.lns[i].ln.Close() - dss.lns[i].ln = nil + if network == dss.lns[i].network && dss.lns[i].Listener != nil { + dss.lns[i].Listener.Close() + <-dss.lns[i].done + dss.lns[i].Listener = nil } } dss.lnmu.Unlock() @@ -49,15 +165,18 @@ func (dss *dualStackServer) teardownNetwork(net string) error { func (dss *dualStackServer) teardown() error { dss.lnmu.Lock() for i := range dss.lns { - if dss.lns[i].ln != nil { - dss.lns[i].ln.Close() + if dss.lns[i].Listener != nil { + dss.lns[i].Listener.Close() + <-dss.lns[i].done } } + dss.lns = dss.lns[:0] dss.lnmu.Unlock() dss.cmu.Lock() for _, c := range dss.cs { c.Close() } + dss.cs = dss.cs[:0] dss.cmu.Unlock() return nil } @@ -65,18 +184,333 @@ func (dss *dualStackServer) teardown() error { func newDualStackServer(lns []streamListener) (*dualStackServer, error) { dss := &dualStackServer{lns: lns, port: "0"} for i := range dss.lns { - ln, err := Listen(dss.lns[i].net, dss.lns[i].addr+":"+dss.port) + ln, err := Listen(dss.lns[i].network, JoinHostPort(dss.lns[i].address, dss.port)) if err != nil { - dss.teardown() + for _, ln := range dss.lns[:i] { + ln.Listener.Close() + } return nil, err } - dss.lns[i].ln = ln + dss.lns[i].Listener = ln + dss.lns[i].done = make(chan bool) if dss.port == "0" { if _, dss.port, err = SplitHostPort(ln.Addr().String()); err != nil { - dss.teardown() + for _, ln := range dss.lns { + ln.Listener.Close() + } return nil, err } } } return dss, nil } + +func transponder(ln Listener, ch chan<- error) { + defer close(ch) + + switch ln := ln.(type) { + case *TCPListener: + ln.SetDeadline(time.Now().Add(someTimeout)) + case *UnixListener: + ln.SetDeadline(time.Now().Add(someTimeout)) + } + c, err := ln.Accept() + if err != nil { + if perr := parseAcceptError(err); perr != nil { + ch <- perr + } + ch <- err + return + } + defer c.Close() + + network := ln.Addr().Network() + if c.LocalAddr().Network() != network || c.LocalAddr().Network() != network { + ch <- fmt.Errorf("got %v->%v; expected %v->%v", c.LocalAddr().Network(), c.RemoteAddr().Network(), network, network) + return + } + c.SetDeadline(time.Now().Add(someTimeout)) + c.SetReadDeadline(time.Now().Add(someTimeout)) + c.SetWriteDeadline(time.Now().Add(someTimeout)) + + b := make([]byte, 256) + n, err := c.Read(b) + if err != nil { + if perr := parseReadError(err); perr != nil { + ch <- perr + } + ch <- err + return + } + if _, err := c.Write(b[:n]); err != nil { + if perr := parseWriteError(err); perr != nil { + ch <- perr + } + ch <- err + return + } +} + +func transceiver(c Conn, wb []byte, ch chan<- error) { + defer close(ch) + + c.SetDeadline(time.Now().Add(someTimeout)) + c.SetReadDeadline(time.Now().Add(someTimeout)) + c.SetWriteDeadline(time.Now().Add(someTimeout)) + + n, err := c.Write(wb) + if err != nil { + if perr := parseWriteError(err); perr != nil { + ch <- perr + } + ch <- err + return + } + if n != len(wb) { + ch <- fmt.Errorf("wrote %d; want %d", n, len(wb)) + } + rb := make([]byte, len(wb)) + n, err = c.Read(rb) + if err != nil { + if perr := parseReadError(err); perr != nil { + ch <- perr + } + ch <- err + return + } + if n != len(wb) { + ch <- fmt.Errorf("read %d; want %d", n, len(wb)) + } +} + +func timeoutReceiver(c Conn, d, min, max time.Duration, ch chan<- error) { + var err error + defer func() { ch <- err }() + + t0 := time.Now() + if err = c.SetReadDeadline(time.Now().Add(d)); err != nil { + return + } + b := make([]byte, 256) + var n int + n, err = c.Read(b) + t1 := time.Now() + if n != 0 || err == nil || !err.(Error).Timeout() { + err = fmt.Errorf("Read did not return (0, timeout): (%d, %v)", n, err) + return + } + if dt := t1.Sub(t0); min > dt || dt > max && !testing.Short() { + err = fmt.Errorf("Read took %s; expected %s", dt, d) + return + } +} + +func timeoutTransmitter(c Conn, d, min, max time.Duration, ch chan<- error) { + var err error + defer func() { ch <- err }() + + t0 := time.Now() + if err = c.SetWriteDeadline(time.Now().Add(d)); err != nil { + return + } + var n int + for { + n, err = c.Write([]byte("TIMEOUT TRANSMITTER")) + if err != nil { + break + } + } + t1 := time.Now() + if err == nil || !err.(Error).Timeout() { + err = fmt.Errorf("Write did not return (any, timeout): (%d, %v)", n, err) + return + } + if dt := t1.Sub(t0); min > dt || dt > max && !testing.Short() { + err = fmt.Errorf("Write took %s; expected %s", dt, d) + return + } +} + +func newLocalPacketListener(network string) (PacketConn, error) { + switch network { + case "udp", "udp4", "udp6": + if supportsIPv4 { + return ListenPacket("udp4", "127.0.0.1:0") + } + if supportsIPv6 { + return ListenPacket("udp6", "[::1]:0") + } + case "unixgram": + return ListenPacket(network, testUnixAddr()) + } + return nil, fmt.Errorf("%s is not supported", network) +} + +func newDualStackPacketListener() (cs []*UDPConn, err error) { + var args = []struct { + network string + UDPAddr + }{ + {"udp4", UDPAddr{IP: IPv4(127, 0, 0, 1)}}, + {"udp6", UDPAddr{IP: IPv6loopback}}, + } + for i := 0; i < 64; i++ { + var port int + var cs []*UDPConn + for _, arg := range args { + arg.UDPAddr.Port = port + c, err := ListenUDP(arg.network, &arg.UDPAddr) + if err != nil { + continue + } + port = c.LocalAddr().(*UDPAddr).Port + cs = append(cs, c) + } + if len(cs) != len(args) { + for _, c := range cs { + c.Close() + } + continue + } + return cs, nil + } + return nil, errors.New("no dualstack port available") +} + +type localPacketServer struct { + pcmu sync.RWMutex + PacketConn + done chan bool // signal that indicates server stopped +} + +func (ls *localPacketServer) buildup(handler func(*localPacketServer, PacketConn)) error { + go func() { + handler(ls, ls.PacketConn) + close(ls.done) + }() + return nil +} + +func (ls *localPacketServer) teardown() error { + ls.pcmu.Lock() + if ls.PacketConn != nil { + network := ls.PacketConn.LocalAddr().Network() + address := ls.PacketConn.LocalAddr().String() + ls.PacketConn.Close() + <-ls.done + ls.PacketConn = nil + switch network { + case "unixgram": + os.Remove(address) + } + } + ls.pcmu.Unlock() + return nil +} + +func newLocalPacketServer(network string) (*localPacketServer, error) { + c, err := newLocalPacketListener(network) + if err != nil { + return nil, err + } + return &localPacketServer{PacketConn: c, done: make(chan bool)}, nil +} + +type packetListener struct { + PacketConn +} + +func (pl *packetListener) newLocalServer() (*localPacketServer, error) { + return &localPacketServer{PacketConn: pl.PacketConn, done: make(chan bool)}, nil +} + +func packetTransponder(c PacketConn, ch chan<- error) { + defer close(ch) + + c.SetDeadline(time.Now().Add(someTimeout)) + c.SetReadDeadline(time.Now().Add(someTimeout)) + c.SetWriteDeadline(time.Now().Add(someTimeout)) + + b := make([]byte, 256) + n, peer, err := c.ReadFrom(b) + if err != nil { + if perr := parseReadError(err); perr != nil { + ch <- perr + } + ch <- err + return + } + if peer == nil { // for connected-mode sockets + switch c.LocalAddr().Network() { + case "udp": + peer, err = ResolveUDPAddr("udp", string(b[:n])) + case "unixgram": + peer, err = ResolveUnixAddr("unixgram", string(b[:n])) + } + if err != nil { + ch <- err + return + } + } + if _, err := c.WriteTo(b[:n], peer); err != nil { + if perr := parseWriteError(err); perr != nil { + ch <- perr + } + ch <- err + return + } +} + +func packetTransceiver(c PacketConn, wb []byte, dst Addr, ch chan<- error) { + defer close(ch) + + c.SetDeadline(time.Now().Add(someTimeout)) + c.SetReadDeadline(time.Now().Add(someTimeout)) + c.SetWriteDeadline(time.Now().Add(someTimeout)) + + n, err := c.WriteTo(wb, dst) + if err != nil { + if perr := parseWriteError(err); perr != nil { + ch <- perr + } + ch <- err + return + } + if n != len(wb) { + ch <- fmt.Errorf("wrote %d; want %d", n, len(wb)) + } + rb := make([]byte, len(wb)) + n, _, err = c.ReadFrom(rb) + if err != nil { + if perr := parseReadError(err); perr != nil { + ch <- perr + } + ch <- err + return + } + if n != len(wb) { + ch <- fmt.Errorf("read %d; want %d", n, len(wb)) + } +} + +func timeoutPacketReceiver(c PacketConn, d, min, max time.Duration, ch chan<- error) { + var err error + defer func() { ch <- err }() + + t0 := time.Now() + if err = c.SetReadDeadline(time.Now().Add(d)); err != nil { + return + } + b := make([]byte, 256) + var n int + n, _, err = c.ReadFrom(b) + t1 := time.Now() + if n != 0 || err == nil || !err.(Error).Timeout() { + err = fmt.Errorf("ReadFrom did not return (0, timeout): (%d, %v)", n, err) + return + } + if dt := t1.Sub(t0); min > dt || dt > max && !testing.Short() { + err = fmt.Errorf("ReadFrom took %s; expected %s", dt, d) + return + } +} diff --git a/libgo/go/net/multicast_test.go b/libgo/go/net/multicast_test.go deleted file mode 100644 index 5f253f44a45..00000000000 --- a/libgo/go/net/multicast_test.go +++ /dev/null @@ -1,188 +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 net - -import ( - "fmt" - "os" - "runtime" - "testing" -) - -var ipv4MulticastListenerTests = []struct { - net string - gaddr *UDPAddr // see RFC 4727 -}{ - {"udp", &UDPAddr{IP: IPv4(224, 0, 0, 254), Port: 12345}}, - - {"udp4", &UDPAddr{IP: IPv4(224, 0, 0, 254), Port: 12345}}, -} - -// TestIPv4MulticastListener tests both single and double listen to a -// test listener with same address family, same group address and same -// port. -func TestIPv4MulticastListener(t *testing.T) { - switch runtime.GOOS { - case "android", "nacl", "plan9": - t.Skipf("skipping test on %q", runtime.GOOS) - case "solaris": - t.Skipf("skipping test on solaris, see issue 7399") - } - - closer := func(cs []*UDPConn) { - for _, c := range cs { - if c != nil { - c.Close() - } - } - } - - for _, ifi := range []*Interface{loopbackInterface(), nil} { - // Note that multicast interface assignment by system - // is not recommended because it usually relies on - // routing stuff for finding out an appropriate - // nexthop containing both network and link layer - // adjacencies. - if ifi == nil && !*testExternal { - continue - } - for _, tt := range ipv4MulticastListenerTests { - var err error - cs := make([]*UDPConn, 2) - if cs[0], err = ListenMulticastUDP(tt.net, ifi, tt.gaddr); err != nil { - t.Fatalf("First ListenMulticastUDP on %v failed: %v", ifi, err) - } - if err := checkMulticastListener(cs[0], tt.gaddr.IP); err != nil { - closer(cs) - t.Fatal(err) - } - if cs[1], err = ListenMulticastUDP(tt.net, ifi, tt.gaddr); err != nil { - closer(cs) - t.Fatalf("Second ListenMulticastUDP on %v failed: %v", ifi, err) - } - if err := checkMulticastListener(cs[1], tt.gaddr.IP); err != nil { - closer(cs) - t.Fatal(err) - } - closer(cs) - } - } -} - -var ipv6MulticastListenerTests = []struct { - net string - gaddr *UDPAddr // see RFC 4727 -}{ - {"udp", &UDPAddr{IP: ParseIP("ff01::114"), Port: 12345}}, - {"udp", &UDPAddr{IP: ParseIP("ff02::114"), Port: 12345}}, - {"udp", &UDPAddr{IP: ParseIP("ff04::114"), Port: 12345}}, - {"udp", &UDPAddr{IP: ParseIP("ff05::114"), Port: 12345}}, - {"udp", &UDPAddr{IP: ParseIP("ff08::114"), Port: 12345}}, - {"udp", &UDPAddr{IP: ParseIP("ff0e::114"), Port: 12345}}, - - {"udp6", &UDPAddr{IP: ParseIP("ff01::114"), Port: 12345}}, - {"udp6", &UDPAddr{IP: ParseIP("ff02::114"), Port: 12345}}, - {"udp6", &UDPAddr{IP: ParseIP("ff04::114"), Port: 12345}}, - {"udp6", &UDPAddr{IP: ParseIP("ff05::114"), Port: 12345}}, - {"udp6", &UDPAddr{IP: ParseIP("ff08::114"), Port: 12345}}, - {"udp6", &UDPAddr{IP: ParseIP("ff0e::114"), Port: 12345}}, -} - -// TestIPv6MulticastListener tests both single and double listen to a -// test listener with same address family, same group address and same -// port. -func TestIPv6MulticastListener(t *testing.T) { - switch runtime.GOOS { - case "plan9": - t.Skipf("skipping test on %q", runtime.GOOS) - case "solaris": - t.Skipf("skipping test on solaris, see issue 7399") - } - if !supportsIPv6 { - t.Skip("ipv6 is not supported") - } - if os.Getuid() != 0 { - t.Skip("skipping test; must be root") - } - - closer := func(cs []*UDPConn) { - for _, c := range cs { - if c != nil { - c.Close() - } - } - } - - for _, ifi := range []*Interface{loopbackInterface(), nil} { - // Note that multicast interface assignment by system - // is not recommended because it usually relies on - // routing stuff for finding out an appropriate - // nexthop containing both network and link layer - // adjacencies. - if ifi == nil && (!*testExternal || !*testIPv6) { - continue - } - for _, tt := range ipv6MulticastListenerTests { - var err error - cs := make([]*UDPConn, 2) - if cs[0], err = ListenMulticastUDP(tt.net, ifi, tt.gaddr); err != nil { - t.Fatalf("First ListenMulticastUDP on %v failed: %v", ifi, err) - } - if err := checkMulticastListener(cs[0], tt.gaddr.IP); err != nil { - closer(cs) - t.Fatal(err) - } - if cs[1], err = ListenMulticastUDP(tt.net, ifi, tt.gaddr); err != nil { - closer(cs) - t.Fatalf("Second ListenMulticastUDP on %v failed: %v", ifi, err) - } - if err := checkMulticastListener(cs[1], tt.gaddr.IP); err != nil { - closer(cs) - t.Fatal(err) - } - closer(cs) - } - } -} - -func checkMulticastListener(c *UDPConn, ip IP) error { - if ok, err := multicastRIBContains(ip); err != nil { - return err - } else if !ok { - return fmt.Errorf("%q not found in multicast RIB", ip.String()) - } - la := c.LocalAddr() - if la, ok := la.(*UDPAddr); !ok || la.Port == 0 { - return fmt.Errorf("got %v; expected a proper address with non-zero port number", la) - } - return nil -} - -func multicastRIBContains(ip IP) (bool, error) { - switch runtime.GOOS { - case "dragonfly", "netbsd", "openbsd", "plan9", "solaris", "windows": - return true, nil // not implemented yet - case "linux": - if runtime.GOARCH == "arm" || runtime.GOARCH == "alpha" { - return true, nil // not implemented yet - } - } - ift, err := Interfaces() - if err != nil { - return false, err - } - for _, ifi := range ift { - ifmat, err := ifi.MulticastAddrs() - if err != nil { - return false, err - } - for _, ifma := range ifmat { - if ifma.(*IPAddr).IP.Equal(ip) { - return true, nil - } - } - } - return false, nil -} diff --git a/libgo/go/net/net.go b/libgo/go/net/net.go index cb31af5e347..6e84c3a100e 100644 --- a/libgo/go/net/net.go +++ b/libgo/go/net/net.go @@ -35,12 +35,49 @@ The Listen function creates servers: } go handleConnection(conn) } + +Name Resolution + +The method for resolving domain names, whether indirectly with functions like Dial +or directly with functions like LookupHost and LookupAddr, varies by operating system. + +On Unix systems, the resolver has two options for resolving names. +It can use a pure Go resolver that sends DNS requests directly to the servers +listed in /etc/resolv.conf, or it can use a cgo-based resolver that calls C +library routines such as getaddrinfo and getnameinfo. + +By default the pure Go resolver is used, because a blocked DNS request consumes +only a goroutine, while a blocked C call consumes an operating system thread. +When cgo is available, the cgo-based resolver is used instead under a variety of +conditions: on systems that do not let programs make direct DNS requests (OS X), +when the LOCALDOMAIN environment variable is present (even if empty), +when the RES_OPTIONS or HOSTALIASES environment variable is non-empty, +when the ASR_CONFIG environment variable is non-empty (OpenBSD only), +when /etc/resolv.conf or /etc/nsswitch.conf specify the use of features that the +Go resolver does not implement, and when the name being looked up ends in .local +or is an mDNS name. + +The resolver decision can be overridden by setting the netdns value of the +GODEBUG environment variable (see package runtime) to go or cgo, as in: + + export GODEBUG=netdns=go # force pure Go resolver + export GODEBUG=netdns=cgo # force cgo resolver + +The decision can also be forced while building the Go source tree +by setting the netgo or netcgo build tag. + +A numeric netdns setting, as in GODEBUG=netdns=1, causes the resolver +to print debugging information about its decisions. +To force a particular resolver while also printing debugging information, +join the two settings by a plus sign, as in GODEBUG=netdns=go+1. + +On Plan 9, the resolver always accesses /net/cs and /net/dns. + +On Windows, the resolver always uses C library functions, such as GetAddrInfo and DnsQuery. + */ package net -// TODO(rsc): -// support for raw ethernet sockets - import ( "errors" "io" @@ -49,6 +86,20 @@ import ( "time" ) +// netGo and netCgo contain the state of the build tags used +// to build this binary, and whether cgo is available. +// conf.go mirrors these into conf for easier testing. +var ( + netGo bool // set true in cgo_stub.go for build tag "netgo" (or no cgo) + netCgo bool // set true in conf_netcgo.go for build tag "netcgo" +) + +func init() { + sysInit() + supportsIPv4 = probeIPv4Stack() + supportsIPv6, supportsIPv4map = probeIPv6Stack() +} + // Addr represents a network end point address. type Addr interface { Network() string // name of the network @@ -118,7 +169,11 @@ func (c *conn) Read(b []byte) (int, error) { if !c.ok() { return 0, syscall.EINVAL } - return c.fd.Read(b) + n, err := c.fd.Read(b) + if err != nil && err != io.EOF { + err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + return n, err } // Write implements the Conn Write method. @@ -126,7 +181,11 @@ func (c *conn) Write(b []byte) (int, error) { if !c.ok() { return 0, syscall.EINVAL } - return c.fd.Write(b) + n, err := c.fd.Write(b) + if err != nil { + err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + return n, err } // Close closes the connection. @@ -134,10 +193,16 @@ func (c *conn) Close() error { if !c.ok() { return syscall.EINVAL } - return c.fd.Close() + err := c.fd.Close() + if err != nil { + err = &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + return err } // LocalAddr returns the local network address. +// The Addr returned is shared by all invocations of LocalAddr, so +// do not modify it. func (c *conn) LocalAddr() Addr { if !c.ok() { return nil @@ -146,6 +211,8 @@ func (c *conn) LocalAddr() Addr { } // RemoteAddr returns the remote network address. +// The Addr returned is shared by all invocations of RemoteAddr, so +// do not modify it. func (c *conn) RemoteAddr() Addr { if !c.ok() { return nil @@ -158,7 +225,10 @@ func (c *conn) SetDeadline(t time.Time) error { if !c.ok() { return syscall.EINVAL } - return c.fd.setDeadline(t) + if err := c.fd.setDeadline(t); err != nil { + return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err} + } + return nil } // SetReadDeadline implements the Conn SetReadDeadline method. @@ -166,7 +236,10 @@ func (c *conn) SetReadDeadline(t time.Time) error { if !c.ok() { return syscall.EINVAL } - return c.fd.setReadDeadline(t) + if err := c.fd.setReadDeadline(t); err != nil { + return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err} + } + return nil } // SetWriteDeadline implements the Conn SetWriteDeadline method. @@ -174,7 +247,10 @@ func (c *conn) SetWriteDeadline(t time.Time) error { if !c.ok() { return syscall.EINVAL } - return c.fd.setWriteDeadline(t) + if err := c.fd.setWriteDeadline(t); err != nil { + return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err} + } + return nil } // SetReadBuffer sets the size of the operating system's @@ -183,7 +259,10 @@ func (c *conn) SetReadBuffer(bytes int) error { if !c.ok() { return syscall.EINVAL } - return setReadBuffer(c.fd, bytes) + if err := setReadBuffer(c.fd, bytes); err != nil { + return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err} + } + return nil } // SetWriteBuffer sets the size of the operating system's @@ -192,7 +271,10 @@ func (c *conn) SetWriteBuffer(bytes int) error { if !c.ok() { return syscall.EINVAL } - return setWriteBuffer(c.fd, bytes) + if err := setWriteBuffer(c.fd, bytes); err != nil { + return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err} + } + return nil } // File sets the underlying os.File to blocking mode and returns a copy. @@ -202,13 +284,12 @@ func (c *conn) SetWriteBuffer(bytes int) error { // The returned os.File's file descriptor is different from the connection's. // Attempting to change properties of the original using this duplicate // may or may not have the desired effect. -func (c *conn) File() (f *os.File, err error) { return c.fd.dup() } - -// An Error represents a network error. -type Error interface { - error - Timeout() bool // Is the error a timeout? - Temporary() bool // Is the error temporary? +func (c *conn) File() (f *os.File, err error) { + f, err = c.fd.dup() + if err != nil { + err = &OpError{Op: "file", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + return } // PacketConn is a generic packet-oriented network connection. @@ -274,6 +355,13 @@ type Listener interface { Addr() Addr } +// An Error represents a network error. +type Error interface { + error + Timeout() bool // Is the error a timeout? + Temporary() bool // Is the error temporary? +} + // Various errors contained in OpError. var ( // For connection setup and write operations. @@ -281,6 +369,7 @@ var ( // For both read and write operations. errTimeout error = &timeoutError{} + errCanceled = errors.New("operation was canceled") errClosing = errors.New("use of closed network connection") ErrWriteToConnected = errors.New("use of WriteTo with pre-connected connection") ) @@ -297,7 +386,17 @@ type OpError struct { // such as "tcp" or "udp6". Net string - // Addr is the network address on which this error occurred. + // For operations involving a remote network connection, like + // Dial, Read, or Write, Source is the corresponding local + // network address. + Source Addr + + // Addr is the network address for which this error occurred. + // For local operations, like Listen or SetDeadline, Addr is + // the address of the local endpoint being manipulated. + // For operations involving a remote network connection, like + // Dial, Read, or Write, Addr is the remote address of that + // connection. Addr Addr // Err is the error that occurred during the operation. @@ -312,22 +411,21 @@ func (e *OpError) Error() string { if e.Net != "" { s += " " + e.Net } + if e.Source != nil { + s += " " + e.Source.String() + } if e.Addr != nil { - s += " " + e.Addr.String() + if e.Source != nil { + s += "->" + } else { + s += " " + } + s += e.Addr.String() } s += ": " + e.Err.Error() return s } -type temporary interface { - Temporary() bool -} - -func (e *OpError) Temporary() bool { - t, ok := e.Err.(temporary) - return ok && t.Temporary() -} - var noDeadline = time.Time{} type timeout interface { @@ -335,16 +433,45 @@ type timeout interface { } func (e *OpError) Timeout() bool { + if ne, ok := e.Err.(*os.SyscallError); ok { + t, ok := ne.Err.(timeout) + return ok && t.Timeout() + } t, ok := e.Err.(timeout) return ok && t.Timeout() } +type temporary interface { + Temporary() bool +} + +func (e *OpError) Temporary() bool { + if ne, ok := e.Err.(*os.SyscallError); ok { + t, ok := ne.Err.(temporary) + return ok && t.Temporary() + } + t, ok := e.Err.(temporary) + return ok && t.Temporary() +} + type timeoutError struct{} func (e *timeoutError) Error() string { return "i/o timeout" } func (e *timeoutError) Timeout() bool { return true } func (e *timeoutError) Temporary() bool { return true } +// A ParseError is the error type of literal network address parsers. +type ParseError struct { + // Type is the type of string that was expected, such as + // "IP address", "CIDR address". + Type string + + // Text is the malformed text string. + Text string +} + +func (e *ParseError) Error() string { return "invalid " + e.Type + ": " + e.Text } + type AddrError struct { Err string Addr string @@ -361,19 +488,14 @@ func (e *AddrError) Error() string { return s } -func (e *AddrError) Temporary() bool { - return false -} - -func (e *AddrError) Timeout() bool { - return false -} +func (e *AddrError) Timeout() bool { return false } +func (e *AddrError) Temporary() bool { return false } type UnknownNetworkError string func (e UnknownNetworkError) Error() string { return "unknown network " + string(e) } -func (e UnknownNetworkError) Temporary() bool { return false } func (e UnknownNetworkError) Timeout() bool { return false } +func (e UnknownNetworkError) Temporary() bool { return false } type InvalidAddrError string @@ -382,17 +504,50 @@ func (e InvalidAddrError) Timeout() bool { return false } func (e InvalidAddrError) Temporary() bool { return false } // DNSConfigError represents an error reading the machine's DNS configuration. +// (No longer used; kept for compatibility.) type DNSConfigError struct { Err error } -func (e *DNSConfigError) Error() string { - return "error reading DNS config: " + e.Err.Error() -} - +func (e *DNSConfigError) Error() string { return "error reading DNS config: " + e.Err.Error() } func (e *DNSConfigError) Timeout() bool { return false } func (e *DNSConfigError) Temporary() bool { return false } +// Various errors contained in DNSError. +var ( + errNoSuchHost = errors.New("no such host") +) + +// DNSError represents a DNS lookup error. +type DNSError struct { + Err string // description of the error + Name string // name looked for + Server string // server used + IsTimeout bool // if true, timed out; not all timeouts set this +} + +func (e *DNSError) Error() string { + if e == nil { + return "" + } + s := "lookup " + e.Name + if e.Server != "" { + s += " on " + e.Server + } + s += ": " + e.Err + return s +} + +// Timeout reports whether the DNS lookup is known to have timed out. +// This is not always known; a DNS lookup may fail due to a timeout +// and return a DNSError for which Timeout returns false. +func (e *DNSError) Timeout() bool { return e.IsTimeout } + +// Temporary reports whether the DNS error is known to be temporary. +// This is not always known; a DNS lookup may fail due to a temporary +// error and return a DNSError for which Temporary returns false. +func (e *DNSError) Temporary() bool { return e.IsTimeout } + type writerOnly struct { io.Writer } @@ -412,10 +567,6 @@ func genericReadFrom(w io.Writer, r io.Reader) (n int64, err error) { var threadLimit = make(chan struct{}, 500) -// Using send for acquire is fine here because we are not using this -// to protect any memory. All we care about is the number of goroutines -// making calls at a time. - func acquireThread() { threadLimit <- struct{}{} } diff --git a/libgo/go/net/net_test.go b/libgo/go/net/net_test.go index bfed4d657fd..3907ce4aa56 100644 --- a/libgo/go/net/net_test.go +++ b/libgo/go/net/net_test.go @@ -6,258 +6,251 @@ package net import ( "io" - "io/ioutil" "os" "runtime" "testing" - "time" ) -func TestShutdown(t *testing.T) { - if runtime.GOOS == "plan9" { - t.Skipf("skipping test on %q", runtime.GOOS) +func TestCloseRead(t *testing.T) { + switch runtime.GOOS { + case "nacl", "plan9": + t.Skipf("not supported on %s", runtime.GOOS) } - ln, err := Listen("tcp", "127.0.0.1:0") - if err != nil { - if ln, err = Listen("tcp6", "[::1]:0"); err != nil { - t.Fatalf("ListenTCP on :0: %v", err) + + for _, network := range []string{"tcp", "unix", "unixpacket"} { + if !testableNetwork(network) { + t.Logf("skipping %s test", network) + continue } - } - go func() { - defer ln.Close() - c, err := ln.Accept() + ln, err := newLocalListener(network) if err != nil { - t.Errorf("Accept: %v", err) - return + t.Fatal(err) } - var buf [10]byte - n, err := c.Read(buf[:]) - if n != 0 || err != io.EOF { - t.Errorf("server Read = %d, %v; want 0, io.EOF", n, err) - return + switch network { + case "unix", "unixpacket": + defer os.Remove(ln.Addr().String()) } - c.Write([]byte("response")) - c.Close() - }() + defer ln.Close() - c, err := Dial("tcp", ln.Addr().String()) - if err != nil { - t.Fatalf("Dial: %v", err) - } - defer c.Close() + c, err := Dial(ln.Addr().Network(), ln.Addr().String()) + if err != nil { + t.Fatal(err) + } + switch network { + case "unix", "unixpacket": + defer os.Remove(c.LocalAddr().String()) + } + defer c.Close() - err = c.(*TCPConn).CloseWrite() - if err != nil { - t.Fatalf("CloseWrite: %v", err) - } - var buf [10]byte - n, err := c.Read(buf[:]) - if err != nil { - t.Fatalf("client Read: %d, %v", n, err) - } - got := string(buf[:n]) - if got != "response" { - t.Errorf("read = %q, want \"response\"", got) + switch c := c.(type) { + case *TCPConn: + err = c.CloseRead() + case *UnixConn: + err = c.CloseRead() + } + if err != nil { + if perr := parseCloseError(err); perr != nil { + t.Error(perr) + } + t.Fatal(err) + } + var b [1]byte + n, err := c.Read(b[:]) + if n != 0 || err == nil { + t.Fatalf("got (%d, %v); want (0, error)", n, err) + } } } -func TestShutdownUnix(t *testing.T) { +func TestCloseWrite(t *testing.T) { switch runtime.GOOS { - case "nacl", "plan9", "windows": - t.Skipf("skipping test on %q", runtime.GOOS) + case "nacl", "plan9": + t.Skipf("not supported on %s", runtime.GOOS) } - f, err := ioutil.TempFile("", "go_net_unixtest") - if err != nil { - t.Fatalf("TempFile: %s", err) - } - f.Close() - tmpname := f.Name() - os.Remove(tmpname) - ln, err := Listen("unix", tmpname) - if err != nil { - t.Fatalf("ListenUnix on %s: %s", tmpname, err) - } - defer func() { - ln.Close() - os.Remove(tmpname) - }() - go func() { + handler := func(ls *localServer, ln Listener) { c, err := ln.Accept() if err != nil { - t.Errorf("Accept: %v", err) + t.Error(err) return } - var buf [10]byte - n, err := c.Read(buf[:]) + defer c.Close() + + var b [1]byte + n, err := c.Read(b[:]) if n != 0 || err != io.EOF { - t.Errorf("server Read = %d, %v; want 0, io.EOF", n, err) + t.Errorf("got (%d, %v); want (0, io.EOF)", n, err) + return + } + switch c := c.(type) { + case *TCPConn: + err = c.CloseWrite() + case *UnixConn: + err = c.CloseWrite() + } + if err != nil { + if perr := parseCloseError(err); perr != nil { + t.Error(perr) + } + t.Error(err) + return + } + n, err = c.Write(b[:]) + if err == nil { + t.Errorf("got (%d, %v); want (any, error)", n, err) return } - c.Write([]byte("response")) - c.Close() - }() - - c, err := Dial("unix", tmpname) - if err != nil { - t.Fatalf("Dial: %v", err) - } - defer c.Close() - - err = c.(*UnixConn).CloseWrite() - if err != nil { - t.Fatalf("CloseWrite: %v", err) - } - var buf [10]byte - n, err := c.Read(buf[:]) - if err != nil { - t.Fatalf("client Read: %d, %v", n, err) - } - got := string(buf[:n]) - if got != "response" { - t.Errorf("read = %q, want \"response\"", got) } -} -func TestTCPListenClose(t *testing.T) { - ln, err := Listen("tcp", "127.0.0.1:0") - if err != nil { - t.Fatalf("Listen failed: %v", err) - } + for _, network := range []string{"tcp", "unix", "unixpacket"} { + if !testableNetwork(network) { + t.Logf("skipping %s test", network) + continue + } - done := make(chan bool, 1) - go func() { - time.Sleep(100 * time.Millisecond) - ln.Close() - }() - go func() { - c, err := ln.Accept() - if err == nil { - c.Close() - t.Error("Accept succeeded") - } else { - t.Logf("Accept timeout error: %s (any error is fine)", err) - } - done <- true - }() - select { - case <-done: - case <-time.After(2 * time.Second): - t.Fatal("timeout waiting for TCP close") - } -} + ls, err := newLocalServer(network) + if err != nil { + t.Fatal(err) + } + defer ls.teardown() + if err := ls.buildup(handler); err != nil { + t.Fatal(err) + } -func TestUDPListenClose(t *testing.T) { - switch runtime.GOOS { - case "plan9": - t.Skipf("skipping test on %q", runtime.GOOS) - } - ln, err := ListenPacket("udp", "127.0.0.1:0") - if err != nil { - t.Fatalf("Listen failed: %v", err) - } + c, err := Dial(ls.Listener.Addr().Network(), ls.Listener.Addr().String()) + if err != nil { + t.Fatal(err) + } + switch network { + case "unix", "unixpacket": + defer os.Remove(c.LocalAddr().String()) + } + defer c.Close() - buf := make([]byte, 1000) - done := make(chan bool, 1) - go func() { - time.Sleep(100 * time.Millisecond) - ln.Close() - }() - go func() { - _, _, err = ln.ReadFrom(buf) + switch c := c.(type) { + case *TCPConn: + err = c.CloseWrite() + case *UnixConn: + err = c.CloseWrite() + } + if err != nil { + if perr := parseCloseError(err); perr != nil { + t.Error(perr) + } + t.Fatal(err) + } + var b [1]byte + n, err := c.Read(b[:]) + if n != 0 || err != io.EOF { + t.Fatalf("got (%d, %v); want (0, io.EOF)", n, err) + } + n, err = c.Write(b[:]) if err == nil { - t.Error("ReadFrom succeeded") - } else { - t.Logf("ReadFrom timeout error: %s (any error is fine)", err) - } - done <- true - }() - select { - case <-done: - case <-time.After(2 * time.Second): - t.Fatal("timeout waiting for UDP close") + t.Fatalf("got (%d, %v); want (any, error)", n, err) + } } } -func TestTCPClose(t *testing.T) { - switch runtime.GOOS { - case "plan9": - t.Skipf("skipping test on %q", runtime.GOOS) - } - l, err := Listen("tcp", "127.0.0.1:0") - if err != nil { - t.Fatal(err) - } - defer l.Close() +func TestConnClose(t *testing.T) { + for _, network := range []string{"tcp", "unix", "unixpacket"} { + if !testableNetwork(network) { + t.Logf("skipping %s test", network) + continue + } - read := func(r io.Reader) error { - var m [1]byte - _, err := r.Read(m[:]) - return err - } + ln, err := newLocalListener(network) + if err != nil { + t.Fatal(err) + } + switch network { + case "unix", "unixpacket": + defer os.Remove(ln.Addr().String()) + } + defer ln.Close() - go func() { - c, err := Dial("tcp", l.Addr().String()) + c, err := Dial(ln.Addr().Network(), ln.Addr().String()) if err != nil { - t.Errorf("Dial: %v", err) - return + t.Fatal(err) } + switch network { + case "unix", "unixpacket": + defer os.Remove(c.LocalAddr().String()) + } + defer c.Close() - go read(c) + if err := c.Close(); err != nil { + if perr := parseCloseError(err); perr != nil { + t.Error(perr) + } + t.Fatal(err) + } + var b [1]byte + n, err := c.Read(b[:]) + if n != 0 || err == nil { + t.Fatalf("got (%d, %v); want (0, error)", n, err) + } + } +} - time.Sleep(10 * time.Millisecond) - c.Close() - }() +func TestListenerClose(t *testing.T) { + for _, network := range []string{"tcp", "unix", "unixpacket"} { + if !testableNetwork(network) { + t.Logf("skipping %s test", network) + continue + } - c, err := l.Accept() - if err != nil { - t.Fatal(err) - } - defer c.Close() + ln, err := newLocalListener(network) + if err != nil { + t.Fatal(err) + } + switch network { + case "unix", "unixpacket": + defer os.Remove(ln.Addr().String()) + } + defer ln.Close() - for err == nil { - err = read(c) - } - if err != nil && err != io.EOF { - t.Fatal(err) + if err := ln.Close(); err != nil { + if perr := parseCloseError(err); perr != nil { + t.Error(perr) + } + t.Fatal(err) + } + c, err := ln.Accept() + if err == nil { + c.Close() + t.Fatal("should fail") + } } } -func TestErrorNil(t *testing.T) { - c, err := Dial("tcp", "127.0.0.1:65535") - if err == nil { - t.Fatal("Dial 127.0.0.1:65535 succeeded") - } - if c != nil { - t.Fatalf("Dial returned non-nil interface %T(%v) with err != nil", c, c) - } +func TestPacketConnClose(t *testing.T) { + for _, network := range []string{"udp", "unixgram"} { + if !testableNetwork(network) { + t.Logf("skipping %s test", network) + continue + } - // Make Listen fail by relistening on the same address. - l, err := Listen("tcp", "127.0.0.1:0") - if err != nil { - t.Fatalf("Listen 127.0.0.1:0: %v", err) - } - defer l.Close() - l1, err := Listen("tcp", l.Addr().String()) - if err == nil { - t.Fatalf("second Listen %v: %v", l.Addr(), err) - } - if l1 != nil { - t.Fatalf("Listen returned non-nil interface %T(%v) with err != nil", l1, l1) - } + c, err := newLocalPacketListener(network) + if err != nil { + t.Fatal(err) + } + switch network { + case "unixgram": + defer os.Remove(c.LocalAddr().String()) + } + defer c.Close() - // Make ListenPacket fail by relistening on the same address. - lp, err := ListenPacket("udp", "127.0.0.1:0") - if err != nil { - t.Fatalf("Listen 127.0.0.1:0: %v", err) - } - defer lp.Close() - lp1, err := ListenPacket("udp", lp.LocalAddr().String()) - if err == nil { - t.Fatalf("second Listen %v: %v", lp.LocalAddr(), err) - } - if lp1 != nil { - t.Fatalf("ListenPacket returned non-nil interface %T(%v) with err != nil", lp1, lp1) + if err := c.Close(); err != nil { + if perr := parseCloseError(err); perr != nil { + t.Error(perr) + } + t.Fatal(err) + } + var b [1]byte + n, _, err := c.ReadFrom(b[:]) + if n != 0 || err == nil { + t.Fatalf("got (%d, %v); want (0, error)", n, err) + } } } diff --git a/libgo/go/net/non_unix_test.go b/libgo/go/net/non_unix_test.go new file mode 100644 index 00000000000..eddca562f98 --- /dev/null +++ b/libgo/go/net/non_unix_test.go @@ -0,0 +1,11 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build nacl plan9 windows + +package net + +// See unix_test.go for what these (don't) do. +func forceGoDNS() func() { return func() {} } +func forceCgoDNS() bool { return false } diff --git a/libgo/go/net/nss.go b/libgo/go/net/nss.go new file mode 100644 index 00000000000..08c3e6a69fe --- /dev/null +++ b/libgo/go/net/nss.go @@ -0,0 +1,159 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd linux netbsd openbsd solaris + +package net + +import ( + "errors" + "io" + "os" +) + +// nssConf represents the state of the machine's /etc/nsswitch.conf file. +type nssConf struct { + err error // any error encountered opening or parsing the file + sources map[string][]nssSource // keyed by database (e.g. "hosts") +} + +type nssSource struct { + source string // e.g. "compat", "files", "mdns4_minimal" + criteria []nssCriterion +} + +// standardCriteria reports all specified criteria have the default +// status actions. +func (s nssSource) standardCriteria() bool { + for i, crit := range s.criteria { + if !crit.standardStatusAction(i == len(s.criteria)-1) { + return false + } + } + return true +} + +// nssCriterion is the parsed structure of one of the criteria in brackets +// after an NSS source name. +type nssCriterion struct { + negate bool // if "!" was present + status string // e.g. "success", "unavail" (lowercase) + action string // e.g. "return", "continue" (lowercase) +} + +// standardStatusAction reports whether c is equivalent to not +// specifying the criterion at all. last is whether this criteria is the +// last in the list. +func (c nssCriterion) standardStatusAction(last bool) bool { + if c.negate { + return false + } + var def string + switch c.status { + case "success": + def = "return" + case "notfound", "unavail", "tryagain": + def = "continue" + default: + // Unknown status + return false + } + if last && c.action == "return" { + return true + } + return c.action == def +} + +func parseNSSConfFile(file string) *nssConf { + f, err := os.Open(file) + if err != nil { + return &nssConf{err: err} + } + defer f.Close() + return parseNSSConf(f) +} + +func parseNSSConf(r io.Reader) *nssConf { + slurp, err := readFull(r) + if err != nil { + return &nssConf{err: err} + } + conf := new(nssConf) + conf.err = foreachLine(slurp, func(line []byte) error { + line = trimSpace(removeComment(line)) + if len(line) == 0 { + return nil + } + colon := bytesIndexByte(line, ':') + if colon == -1 { + return errors.New("no colon on line") + } + db := string(trimSpace(line[:colon])) + srcs := line[colon+1:] + for { + srcs = trimSpace(srcs) + if len(srcs) == 0 { + break + } + sp := bytesIndexByte(srcs, ' ') + var src string + if sp == -1 { + src = string(srcs) + srcs = nil // done + } else { + src = string(srcs[:sp]) + srcs = trimSpace(srcs[sp+1:]) + } + var criteria []nssCriterion + // See if there's a criteria block in brackets. + if len(srcs) > 0 && srcs[0] == '[' { + bclose := bytesIndexByte(srcs, ']') + if bclose == -1 { + return errors.New("unclosed criterion bracket") + } + var err error + criteria, err = parseCriteria(srcs[1:bclose]) + if err != nil { + return errors.New("invalid criteria: " + string(srcs[1:bclose])) + } + srcs = srcs[bclose+1:] + } + if conf.sources == nil { + conf.sources = make(map[string][]nssSource) + } + conf.sources[db] = append(conf.sources[db], nssSource{ + source: src, + criteria: criteria, + }) + } + return nil + }) + return conf +} + +// parses "foo=bar !foo=bar" +func parseCriteria(x []byte) (c []nssCriterion, err error) { + err = foreachField(x, func(f []byte) error { + not := false + if len(f) > 0 && f[0] == '!' { + not = true + f = f[1:] + } + if len(f) < 3 { + return errors.New("criterion too short") + } + eq := bytesIndexByte(f, '=') + if eq == -1 { + return errors.New("criterion lacks equal sign") + } + lowerASCIIBytes(f) + c = append(c, nssCriterion{ + negate: not, + status: string(f[:eq]), + action: string(f[eq+1:]), + }) + return nil + }) + return +} diff --git a/libgo/go/net/nss_test.go b/libgo/go/net/nss_test.go new file mode 100644 index 00000000000..371deb502d1 --- /dev/null +++ b/libgo/go/net/nss_test.go @@ -0,0 +1,169 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd linux netbsd openbsd solaris + +package net + +import ( + "reflect" + "strings" + "testing" +) + +const ubuntuTrustyAvahi = `# /etc/nsswitch.conf +# +# Example configuration of GNU Name Service Switch functionality. +# If you have the libc-doc-reference' and nfo' packages installed, try: +# nfo libc "Name Service Switch"' for information about this file. + +passwd: compat +group: compat +shadow: compat + +hosts: files mdns4_minimal [NOTFOUND=return] dns mdns4 +networks: files + +protocols: db files +services: db files +ethers: db files +rpc: db files + +netgroup: nis +` + +func TestParseNSSConf(t *testing.T) { + tests := []struct { + name string + in string + want *nssConf + }{ + { + name: "no_newline", + in: "foo: a b", + want: &nssConf{ + sources: map[string][]nssSource{ + "foo": {{source: "a"}, {source: "b"}}, + }, + }, + }, + { + name: "newline", + in: "foo: a b\n", + want: &nssConf{ + sources: map[string][]nssSource{ + "foo": {{source: "a"}, {source: "b"}}, + }, + }, + }, + { + name: "whitespace", + in: " foo:a b \n", + want: &nssConf{ + sources: map[string][]nssSource{ + "foo": {{source: "a"}, {source: "b"}}, + }, + }, + }, + { + name: "comment1", + in: " foo:a b#c\n", + want: &nssConf{ + sources: map[string][]nssSource{ + "foo": {{source: "a"}, {source: "b"}}, + }, + }, + }, + { + name: "comment2", + in: " foo:a b #c \n", + want: &nssConf{ + sources: map[string][]nssSource{ + "foo": {{source: "a"}, {source: "b"}}, + }, + }, + }, + { + name: "crit", + in: " foo:a b [!a=b X=Y ] c#d \n", + want: &nssConf{ + sources: map[string][]nssSource{ + "foo": { + {source: "a"}, + { + source: "b", + criteria: []nssCriterion{ + { + negate: true, + status: "a", + action: "b", + }, + { + status: "x", + action: "y", + }, + }, + }, + {source: "c"}, + }, + }, + }, + }, + + // Ubuntu Trusty w/ avahi-daemon, libavahi-* etc installed. + { + name: "ubuntu_trusty_avahi", + in: ubuntuTrustyAvahi, + want: &nssConf{ + sources: map[string][]nssSource{ + "passwd": {{source: "compat"}}, + "group": {{source: "compat"}}, + "shadow": {{source: "compat"}}, + "hosts": { + {source: "files"}, + { + source: "mdns4_minimal", + criteria: []nssCriterion{ + { + negate: false, + status: "notfound", + action: "return", + }, + }, + }, + {source: "dns"}, + {source: "mdns4"}, + }, + "networks": {{source: "files"}}, + "protocols": { + {source: "db"}, + {source: "files"}, + }, + "services": { + {source: "db"}, + {source: "files"}, + }, + "ethers": { + {source: "db"}, + {source: "files"}, + }, + "rpc": { + {source: "db"}, + {source: "files"}, + }, + "netgroup": { + {source: "nis"}, + }, + }, + }, + }, + } + + for _, tt := range tests { + gotConf := parseNSSConf(strings.NewReader(tt.in)) + if !reflect.DeepEqual(gotConf, tt.want) { + t.Errorf("%s: mismatch\n got %#v\nwant %#v", tt.name, gotConf, tt.want) + } + } +} diff --git a/libgo/go/net/packetconn_test.go b/libgo/go/net/packetconn_test.go index b6e4e76f930..7f3ea8a2d0c 100644 --- a/libgo/go/net/packetconn_test.go +++ b/libgo/go/net/packetconn_test.go @@ -9,49 +9,21 @@ package net import ( "os" - "runtime" - "strings" "testing" "time" ) -func packetConnTestData(t *testing.T, net string, i int) ([]byte, func()) { - switch net { - case "udp": - return []byte("UDP PACKETCONN TEST"), nil - case "ip": - if skip, skipmsg := skipRawSocketTest(t); skip { - return nil, func() { - t.Logf(skipmsg) - } - } - b, err := (&icmpMessage{ - Type: icmpv4EchoRequest, Code: 0, - Body: &icmpEcho{ - ID: os.Getpid() & 0xffff, Seq: i + 1, - Data: []byte("IP PACKETCONN TEST"), - }, - }).Marshal() - if err != nil { - return nil, func() { - t.Fatalf("icmpMessage.Marshal failed: %v", err) - } - } - return b, nil - case "unixgram": - switch runtime.GOOS { - case "nacl", "plan9", "windows": - return nil, func() { - t.Logf("skipping %q test on %q", net, runtime.GOOS) - } - default: - return []byte("UNIXGRAM PACKETCONN TEST"), nil - } - default: - return nil, func() { - t.Logf("skipping %q test", net) - } +// The full stack test cases for IPConn have been moved to the +// following: +// golang.org/x/net/ipv4 +// golang.org/x/net/ipv6 +// golang.org/x/net/icmp + +func packetConnTestData(t *testing.T, network string) ([]byte, func()) { + if !testableNetwork(network) { + return nil, func() { t.Logf("skipping %s test", network) } } + return []byte("PACKETCONN TEST"), nil } var packetConnTests = []struct { @@ -60,7 +32,6 @@ var packetConnTests = []struct { addr2 string }{ {"udp", "127.0.0.1:0", "127.0.0.1:0"}, - {"ip:icmp", "127.0.0.1", "127.0.0.1"}, {"unixgram", testUnixAddr(), testUnixAddr()}, } @@ -74,9 +45,8 @@ func TestPacketConn(t *testing.T) { } } - for i, tt := range packetConnTests { - netstr := strings.Split(tt.net, ":") - wb, skipOrFatalFn := packetConnTestData(t, netstr[0], i) + for _, tt := range packetConnTests { + wb, skipOrFatalFn := packetConnTestData(t, tt.net) if skipOrFatalFn != nil { skipOrFatalFn() continue @@ -84,37 +54,37 @@ func TestPacketConn(t *testing.T) { c1, err := ListenPacket(tt.net, tt.addr1) if err != nil { - t.Fatalf("ListenPacket failed: %v", err) + t.Fatal(err) } - defer closer(c1, netstr[0], tt.addr1, tt.addr2) + defer closer(c1, tt.net, tt.addr1, tt.addr2) c1.LocalAddr() - c1.SetDeadline(time.Now().Add(100 * time.Millisecond)) - c1.SetReadDeadline(time.Now().Add(100 * time.Millisecond)) - c1.SetWriteDeadline(time.Now().Add(100 * time.Millisecond)) + c1.SetDeadline(time.Now().Add(500 * time.Millisecond)) + c1.SetReadDeadline(time.Now().Add(500 * time.Millisecond)) + c1.SetWriteDeadline(time.Now().Add(500 * time.Millisecond)) c2, err := ListenPacket(tt.net, tt.addr2) if err != nil { - t.Fatalf("ListenPacket failed: %v", err) + t.Fatal(err) } - defer closer(c2, netstr[0], tt.addr1, tt.addr2) + defer closer(c2, tt.net, tt.addr1, tt.addr2) c2.LocalAddr() - c2.SetDeadline(time.Now().Add(100 * time.Millisecond)) - c2.SetReadDeadline(time.Now().Add(100 * time.Millisecond)) - c2.SetWriteDeadline(time.Now().Add(100 * time.Millisecond)) + c2.SetDeadline(time.Now().Add(500 * time.Millisecond)) + c2.SetReadDeadline(time.Now().Add(500 * time.Millisecond)) + c2.SetWriteDeadline(time.Now().Add(500 * time.Millisecond)) + rb2 := make([]byte, 128) if _, err := c1.WriteTo(wb, c2.LocalAddr()); err != nil { - t.Fatalf("PacketConn.WriteTo failed: %v", err) + t.Fatal(err) } - rb2 := make([]byte, 128) if _, _, err := c2.ReadFrom(rb2); err != nil { - t.Fatalf("PacketConn.ReadFrom failed: %v", err) + t.Fatal(err) } if _, err := c2.WriteTo(wb, c1.LocalAddr()); err != nil { - t.Fatalf("PacketConn.WriteTo failed: %v", err) + t.Fatal(err) } rb1 := make([]byte, 128) if _, _, err := c1.ReadFrom(rb1); err != nil { - t.Fatalf("PacketConn.ReadFrom failed: %v", err) + t.Fatal(err) } } } @@ -129,10 +99,9 @@ func TestConnAndPacketConn(t *testing.T) { } } - for i, tt := range packetConnTests { + for _, tt := range packetConnTests { var wb []byte - netstr := strings.Split(tt.net, ":") - wb, skipOrFatalFn := packetConnTestData(t, netstr[0], i) + wb, skipOrFatalFn := packetConnTestData(t, tt.net) if skipOrFatalFn != nil { skipOrFatalFn() continue @@ -140,47 +109,45 @@ func TestConnAndPacketConn(t *testing.T) { c1, err := ListenPacket(tt.net, tt.addr1) if err != nil { - t.Fatalf("ListenPacket failed: %v", err) + t.Fatal(err) } - defer closer(c1, netstr[0], tt.addr1, tt.addr2) + defer closer(c1, tt.net, tt.addr1, tt.addr2) c1.LocalAddr() - c1.SetDeadline(time.Now().Add(100 * time.Millisecond)) - c1.SetReadDeadline(time.Now().Add(100 * time.Millisecond)) - c1.SetWriteDeadline(time.Now().Add(100 * time.Millisecond)) + c1.SetDeadline(time.Now().Add(500 * time.Millisecond)) + c1.SetReadDeadline(time.Now().Add(500 * time.Millisecond)) + c1.SetWriteDeadline(time.Now().Add(500 * time.Millisecond)) c2, err := Dial(tt.net, c1.LocalAddr().String()) if err != nil { - t.Fatalf("Dial failed: %v", err) + t.Fatal(err) } defer c2.Close() c2.LocalAddr() c2.RemoteAddr() - c2.SetDeadline(time.Now().Add(100 * time.Millisecond)) - c2.SetReadDeadline(time.Now().Add(100 * time.Millisecond)) - c2.SetWriteDeadline(time.Now().Add(100 * time.Millisecond)) + c2.SetDeadline(time.Now().Add(500 * time.Millisecond)) + c2.SetReadDeadline(time.Now().Add(500 * time.Millisecond)) + c2.SetWriteDeadline(time.Now().Add(500 * time.Millisecond)) if _, err := c2.Write(wb); err != nil { - t.Fatalf("Conn.Write failed: %v", err) + t.Fatal(err) } rb1 := make([]byte, 128) if _, _, err := c1.ReadFrom(rb1); err != nil { - t.Fatalf("PacketConn.ReadFrom failed: %v", err) + t.Fatal(err) } var dst Addr - switch netstr[0] { - case "ip": - dst = &IPAddr{IP: IPv4(127, 0, 0, 1)} + switch tt.net { case "unixgram": continue default: dst = c2.LocalAddr() } if _, err := c1.WriteTo(wb, dst); err != nil { - t.Fatalf("PacketConn.WriteTo failed: %v", err) + t.Fatal(err) } rb2 := make([]byte, 128) if _, err := c2.Read(rb2); err != nil { - t.Fatalf("Conn.Read failed: %v", err) + t.Fatal(err) } } } diff --git a/libgo/go/net/parse.go b/libgo/go/net/parse.go index e1d0130c9ac..c72e1c2eaf0 100644 --- a/libgo/go/net/parse.go +++ b/libgo/go/net/parse.go @@ -171,43 +171,30 @@ func xtoi2(s string, e byte) (byte, bool) { return byte(n), ok && ei == 2 } -// Integer to decimal. -func itoa(i int) string { - var buf [30]byte - n := len(buf) - neg := false - if i < 0 { - i = -i - neg = true - } - ui := uint(i) - for ui > 0 || n == len(buf) { - n-- - buf[n] = byte('0' + ui%10) - ui /= 10 - } - if neg { - n-- - buf[n] = '-' - } - return string(buf[n:]) -} - -// Convert i to decimal string. -func itod(i uint) string { - if i == 0 { - return "0" +// Convert integer to decimal string. +func itoa(val int) string { + if val < 0 { + return "-" + uitoa(uint(-val)) } + return uitoa(uint(val)) +} - // Assemble decimal in reverse order. - var b [32]byte - bp := len(b) - for ; i > 0; i /= 10 { - bp-- - b[bp] = byte(i%10) + '0' +// Convert unsigned integer to decimal string. +func uitoa(val uint) string { + if val == 0 { // avoid string allocation + return "0" } - - return string(b[bp:]) + var buf [20]byte // big enough for 64bit value base 10 + i := len(buf) - 1 + for val >= 10 { + q := val / 10 + buf[i] = byte('0' + val - q*10) + i-- + val = q + } + // val < 10 + buf[i] = byte('0' + val) + return string(buf[i:]) } // Convert i to a hexadecimal string. Leading zeros are not printed. @@ -245,3 +232,155 @@ func last(s string, b byte) int { } return i } + +// lowerASCIIBytes makes x ASCII lowercase in-place. +func lowerASCIIBytes(x []byte) { + for i, b := range x { + if 'A' <= b && b <= 'Z' { + x[i] += 'a' - 'A' + } + } +} + +// lowerASCII returns the ASCII lowercase version of b. +func lowerASCII(b byte) byte { + if 'A' <= b && b <= 'Z' { + return b + ('a' - 'A') + } + return b +} + +// trimSpace returns x without any leading or trailing ASCII whitespace. +func trimSpace(x []byte) []byte { + for len(x) > 0 && isSpace(x[0]) { + x = x[1:] + } + for len(x) > 0 && isSpace(x[len(x)-1]) { + x = x[:len(x)-1] + } + return x +} + +// isSpace reports whether b is an ASCII space character. +func isSpace(b byte) bool { + return b == ' ' || b == '\t' || b == '\n' || b == '\r' +} + +// removeComment returns line, removing any '#' byte and any following +// bytes. +func removeComment(line []byte) []byte { + if i := bytesIndexByte(line, '#'); i != -1 { + return line[:i] + } + return line +} + +// foreachLine runs fn on each line of x. +// Each line (except for possibly the last) ends in '\n'. +// It returns the first non-nil error returned by fn. +func foreachLine(x []byte, fn func(line []byte) error) error { + for len(x) > 0 { + nl := bytesIndexByte(x, '\n') + if nl == -1 { + return fn(x) + } + line := x[:nl+1] + x = x[nl+1:] + if err := fn(line); err != nil { + return err + } + } + return nil +} + +// foreachField runs fn on each non-empty run of non-space bytes in x. +// It returns the first non-nil error returned by fn. +func foreachField(x []byte, fn func(field []byte) error) error { + x = trimSpace(x) + for len(x) > 0 { + sp := bytesIndexByte(x, ' ') + if sp == -1 { + return fn(x) + } + if field := trimSpace(x[:sp]); len(field) > 0 { + if err := fn(field); err != nil { + return err + } + } + x = trimSpace(x[sp+1:]) + } + return nil +} + +// bytesIndexByte is bytes.IndexByte. It returns the index of the +// first instance of c in s, or -1 if c is not present in s. +func bytesIndexByte(s []byte, c byte) int { + for i, b := range s { + if b == c { + return i + } + } + return -1 +} + +// stringsHasSuffix is strings.HasSuffix. It reports whether s ends in +// suffix. +func stringsHasSuffix(s, suffix string) bool { + return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix +} + +// stringsHasSuffixFold reports whether s ends in suffix, +// ASCII-case-insensitively. +func stringsHasSuffixFold(s, suffix string) bool { + if len(suffix) > len(s) { + return false + } + for i := 0; i < len(suffix); i++ { + if lowerASCII(suffix[i]) != lowerASCII(s[len(s)-len(suffix)+i]) { + return false + } + } + return true +} + +// stringsHasPrefix is strings.HasPrefix. It reports whether s begins with prefix. +func stringsHasPrefix(s, prefix string) bool { + return len(s) >= len(prefix) && s[:len(prefix)] == prefix +} + +func readFull(r io.Reader) (all []byte, err error) { + buf := make([]byte, 1024) + for { + n, err := r.Read(buf) + all = append(all, buf[:n]...) + if err == io.EOF { + return all, nil + } + if err != nil { + return nil, err + } + } +} + +// goDebugString returns the value of the named GODEBUG key. +// GODEBUG is of the form "key=val,key2=val2" +func goDebugString(key string) string { + s := os.Getenv("GODEBUG") + for i := 0; i < len(s)-len(key)-1; i++ { + if i > 0 && s[i-1] != ',' { + continue + } + afterKey := s[i+len(key):] + if afterKey[0] != '=' || s[i:i+len(key)] != key { + continue + } + val := afterKey[1:] + for i, b := range val { + if b == ',' { + return val[:i] + } + } + return val + } + return "" +} diff --git a/libgo/go/net/parse_test.go b/libgo/go/net/parse_test.go index 7b213b75bde..0f048fcea0b 100644 --- a/libgo/go/net/parse_test.go +++ b/libgo/go/net/parse_test.go @@ -15,20 +15,20 @@ func TestReadLine(t *testing.T) { // /etc/services file does not exist on android, plan9, windows. switch runtime.GOOS { case "android", "plan9", "windows": - t.Skipf("skipping test on %q", runtime.GOOS) + t.Skipf("not supported on %s", runtime.GOOS) } filename := "/etc/services" // a nice big file fd, err := os.Open(filename) if err != nil { - t.Fatalf("open %s: %v", filename, err) + t.Fatal(err) } defer fd.Close() br := bufio.NewReader(fd) file, err := open(filename) if file == nil { - t.Fatalf("net.open(%s) = nil", filename) + t.Fatal(err) } defer file.close() @@ -41,8 +41,7 @@ func TestReadLine(t *testing.T) { } line, ok := file.readLine() if (berr != nil) != !ok || bline != line { - t.Fatalf("%s:%d (#%d)\nbufio => %q, %v\nnet => %q, %v", - filename, lineno, byteno, bline, berr, line, ok) + t.Fatalf("%s:%d (#%d)\nbufio => %q, %v\nnet => %q, %v", filename, lineno, byteno, bline, berr, line, ok) } if !ok { break @@ -51,3 +50,30 @@ func TestReadLine(t *testing.T) { byteno += len(line) + 1 } } + +func TestGoDebugString(t *testing.T) { + defer os.Setenv("GODEBUG", os.Getenv("GODEBUG")) + tests := []struct { + godebug string + key string + want string + }{ + {"", "foo", ""}, + {"foo=", "foo", ""}, + {"foo=bar", "foo", "bar"}, + {"foo=bar,", "foo", "bar"}, + {"foo,foo=bar,", "foo", "bar"}, + {"foo1=bar,foo=bar,", "foo", "bar"}, + {"foo=bar,foo=bar,", "foo", "bar"}, + {"foo=", "foo", ""}, + {"foo", "foo", ""}, + {",foo", "foo", ""}, + {"foo=bar,baz", "loooooooong", ""}, + } + for _, tt := range tests { + os.Setenv("GODEBUG", tt.godebug) + if got := goDebugString(tt.key); got != tt.want { + t.Errorf("for %q, goDebugString(%q) = %q; want %q", tt.godebug, tt.key, got, tt.want) + } + } +} diff --git a/libgo/go/net/pipe.go b/libgo/go/net/pipe.go index f1a2eca4e88..5fc830b7408 100644 --- a/libgo/go/net/pipe.go +++ b/libgo/go/net/pipe.go @@ -55,13 +55,13 @@ func (p *pipe) RemoteAddr() Addr { } func (p *pipe) SetDeadline(t time.Time) error { - return errors.New("net.Pipe does not support deadlines") + return &OpError{Op: "set", Net: "pipe", Source: nil, Addr: nil, Err: errors.New("deadline not supported")} } func (p *pipe) SetReadDeadline(t time.Time) error { - return errors.New("net.Pipe does not support deadlines") + return &OpError{Op: "set", Net: "pipe", Source: nil, Addr: nil, Err: errors.New("deadline not supported")} } func (p *pipe) SetWriteDeadline(t time.Time) error { - return errors.New("net.Pipe does not support deadlines") + return &OpError{Op: "set", Net: "pipe", Source: nil, Addr: nil, Err: errors.New("deadline not supported")} } diff --git a/libgo/go/net/pipe_test.go b/libgo/go/net/pipe_test.go index afe4f2408fa..60c39205932 100644 --- a/libgo/go/net/pipe_test.go +++ b/libgo/go/net/pipe_test.go @@ -10,10 +10,10 @@ import ( "testing" ) -func checkWrite(t *testing.T, w io.Writer, data []byte, c chan int) { +func checkPipeWrite(t *testing.T, w io.Writer, data []byte, c chan int) { n, err := w.Write(data) if err != nil { - t.Errorf("write: %v", err) + t.Error(err) } if n != len(data) { t.Errorf("short write: %d != %d", n, len(data)) @@ -21,11 +21,11 @@ func checkWrite(t *testing.T, w io.Writer, data []byte, c chan int) { c <- 0 } -func checkRead(t *testing.T, r io.Reader, data []byte, wantErr error) { +func checkPipeRead(t *testing.T, r io.Reader, data []byte, wantErr error) { buf := make([]byte, len(data)+10) n, err := r.Read(buf) if err != wantErr { - t.Errorf("read: %v", err) + t.Error(err) return } if n != len(data) || !bytes.Equal(buf[0:n], data) { @@ -34,23 +34,22 @@ func checkRead(t *testing.T, r io.Reader, data []byte, wantErr error) { } } -// Test a simple read/write/close sequence. +// TestPipe tests a simple read/write/close sequence. // Assumes that the underlying io.Pipe implementation // is solid and we're just testing the net wrapping. - func TestPipe(t *testing.T) { c := make(chan int) cli, srv := Pipe() - go checkWrite(t, cli, []byte("hello, world"), c) - checkRead(t, srv, []byte("hello, world"), nil) + go checkPipeWrite(t, cli, []byte("hello, world"), c) + checkPipeRead(t, srv, []byte("hello, world"), nil) <-c - go checkWrite(t, srv, []byte("line 2"), c) - checkRead(t, cli, []byte("line 2"), nil) + go checkPipeWrite(t, srv, []byte("line 2"), c) + checkPipeRead(t, cli, []byte("line 2"), nil) <-c - go checkWrite(t, cli, []byte("a third line"), c) - checkRead(t, srv, []byte("a third line"), nil) + go checkPipeWrite(t, cli, []byte("a third line"), c) + checkPipeRead(t, srv, []byte("a third line"), nil) <-c go srv.Close() - checkRead(t, cli, nil, io.EOF) + checkPipeRead(t, cli, nil, io.EOF) cli.Close() } diff --git a/libgo/go/net/platform_test.go b/libgo/go/net/platform_test.go new file mode 100644 index 00000000000..d6248520f33 --- /dev/null +++ b/libgo/go/net/platform_test.go @@ -0,0 +1,159 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package net + +import ( + "os" + "runtime" + "strings" + "testing" +) + +// testableNetwork reports whether network is testable on the current +// platform configuration. +func testableNetwork(network string) bool { + ss := strings.Split(network, ":") + switch ss[0] { + case "ip+nopriv": + switch runtime.GOOS { + case "nacl": + return false + } + case "ip", "ip4", "ip6": + switch runtime.GOOS { + case "nacl", "plan9": + return false + default: + if os.Getuid() != 0 { + return false + } + } + case "unix", "unixgram": + switch runtime.GOOS { + case "nacl", "plan9", "windows": + return false + } + // iOS does not support unix, unixgram. + if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") { + return false + } + case "unixpacket": + switch runtime.GOOS { + case "android", "darwin", "nacl", "plan9", "windows": + fallthrough + case "freebsd": // FreeBSD 8 and below don't support unixpacket + return false + } + } + switch ss[0] { + case "tcp4", "udp4", "ip4": + if !supportsIPv4 { + return false + } + case "tcp6", "udp6", "ip6": + if !supportsIPv6 { + return false + } + } + return true +} + +// testableAddress reports whether address of network is testable on +// the current platform configuration. +func testableAddress(network, address string) bool { + switch ss := strings.Split(network, ":"); ss[0] { + case "unix", "unixgram", "unixpacket": + // Abstract unix domain sockets, a Linux-ism. + if address[0] == '@' && runtime.GOOS != "linux" { + return false + } + } + return true +} + +// testableListenArgs reports whether arguments are testable on the +// current platform configuration. +func testableListenArgs(network, address, client string) bool { + if !testableNetwork(network) || !testableAddress(network, address) { + return false + } + + var err error + var addr Addr + switch ss := strings.Split(network, ":"); ss[0] { + case "tcp", "tcp4", "tcp6": + addr, err = ResolveTCPAddr("tcp", address) + case "udp", "udp4", "udp6": + addr, err = ResolveUDPAddr("udp", address) + case "ip", "ip4", "ip6": + addr, err = ResolveIPAddr("ip", address) + default: + return true + } + if err != nil { + return false + } + var ip IP + var wildcard bool + switch addr := addr.(type) { + case *TCPAddr: + ip = addr.IP + wildcard = addr.isWildcard() + case *UDPAddr: + ip = addr.IP + wildcard = addr.isWildcard() + case *IPAddr: + ip = addr.IP + wildcard = addr.isWildcard() + } + + // Test wildcard IP addresses. + if wildcard && (testing.Short() || !*testExternal) { + return false + } + + // Test functionality of IPv4 communication using AF_INET and + // IPv6 communication using AF_INET6 sockets. + if !supportsIPv4 && ip.To4() != nil { + return false + } + if !supportsIPv6 && ip.To16() != nil && ip.To4() == nil { + return false + } + cip := ParseIP(client) + if cip != nil { + if !supportsIPv4 && cip.To4() != nil { + return false + } + if !supportsIPv6 && cip.To16() != nil && cip.To4() == nil { + return false + } + } + + // Test functionality of IPv4 communication using AF_INET6 + // sockets. + if !supportsIPv4map && (network == "tcp" || network == "udp" || network == "ip") && wildcard { + // At this point, we prefer IPv4 when ip is nil. + // See favoriteAddrFamily for further information. + if ip.To16() != nil && ip.To4() == nil && cip.To4() != nil { // a pair of IPv6 server and IPv4 client + return false + } + if (ip.To4() != nil || ip == nil) && cip.To16() != nil && cip.To4() == nil { // a pair of IPv4 server and IPv6 client + return false + } + } + + return true +} + +var condFatalf = func() func(*testing.T, string, ...interface{}) { + // A few APIs, File, Read/WriteMsg{UDP,IP}, are not + // implemented yet on both Plan 9 and Windows. + switch runtime.GOOS { + case "plan9", "windows": + return (*testing.T).Logf + } + return (*testing.T).Fatalf +}() diff --git a/libgo/go/net/port.go b/libgo/go/net/port.go index c24f4ed5b17..a2a538789e1 100644 --- a/libgo/go/net/port.go +++ b/libgo/go/net/port.go @@ -18,7 +18,7 @@ func parsePort(net, port string) (int, error) { } } if p < 0 || p > 0xFFFF { - return 0, &AddrError{"invalid port", port} + return 0, &AddrError{Err: "invalid port", Addr: port} } return p, nil } diff --git a/libgo/go/net/port_test.go b/libgo/go/net/port_test.go index 4811ade69e0..2dacd975e7a 100644 --- a/libgo/go/net/port_test.go +++ b/libgo/go/net/port_test.go @@ -9,14 +9,12 @@ import ( "testing" ) -type portTest struct { - netw string - name string - port int - ok bool -} - -var porttests = []portTest{ +var portTests = []struct { + network string + name string + port int + ok bool +}{ {"tcp", "echo", 7, true}, {"tcp", "discard", 9, true}, {"tcp", "systat", 11, true}, @@ -46,14 +44,12 @@ var porttests = []portTest{ func TestLookupPort(t *testing.T) { switch runtime.GOOS { case "nacl": - t.Skipf("skipping test on %q", runtime.GOOS) + t.Skipf("not supported on %s", runtime.GOOS) } - for i := 0; i < len(porttests); i++ { - tt := porttests[i] - if port, err := LookupPort(tt.netw, tt.name); port != tt.port || (err == nil) != tt.ok { - t.Errorf("LookupPort(%q, %q) = %v, %v; want %v", - tt.netw, tt.name, port, err, tt.port) + for _, tt := range portTests { + if port, err := LookupPort(tt.network, tt.name); port != tt.port || (err == nil) != tt.ok { + t.Errorf("LookupPort(%q, %q) = %v, %v; want %v", tt.network, tt.name, port, err, tt.port) } } } diff --git a/libgo/go/net/port_unix.go b/libgo/go/net/port_unix.go index 348c771c351..badf8abc79b 100644 --- a/libgo/go/net/port_unix.go +++ b/libgo/go/net/port_unix.go @@ -69,5 +69,5 @@ func goLookupPort(network, service string) (port int, err error) { return } } - return 0, &AddrError{"unknown port", network + "/" + service} + return 0, &AddrError{Err: "unknown port", Addr: network + "/" + service} } diff --git a/libgo/go/net/protoconn_test.go b/libgo/go/net/protoconn_test.go index 12856b6c311..c6ef23b0e18 100644 --- a/libgo/go/net/protoconn_test.go +++ b/libgo/go/net/protoconn_test.go @@ -8,49 +8,31 @@ package net import ( - "io/ioutil" "os" "runtime" "testing" "time" ) -// testUnixAddr uses ioutil.TempFile to get a name that is unique. It -// also uses /tmp directory in case it is prohibited to create UNIX -// sockets in TMPDIR. -func testUnixAddr() string { - f, err := ioutil.TempFile("", "nettest") - if err != nil { - panic(err) - } - addr := f.Name() - f.Close() - os.Remove(addr) - return addr -} - -var condFatalf = func() func(*testing.T, string, ...interface{}) { - // A few APIs are not implemented yet on both Plan 9 and Windows. - switch runtime.GOOS { - case "plan9", "windows": - return (*testing.T).Logf - } - return (*testing.T).Fatalf -}() +// The full stack test cases for IPConn have been moved to the +// following: +// golang.org/x/net/ipv4 +// golang.org/x/net/ipv6 +// golang.org/x/net/icmp func TestTCPListenerSpecificMethods(t *testing.T) { switch runtime.GOOS { case "plan9": - t.Skipf("skipping test on %q", runtime.GOOS) + t.Skipf("not supported on %s", runtime.GOOS) } la, err := ResolveTCPAddr("tcp4", "127.0.0.1:0") if err != nil { - t.Fatalf("ResolveTCPAddr failed: %v", err) + t.Fatal(err) } ln, err := ListenTCP("tcp4", la) if err != nil { - t.Fatalf("ListenTCP failed: %v", err) + t.Fatal(err) } defer ln.Close() ln.Addr() @@ -58,21 +40,21 @@ func TestTCPListenerSpecificMethods(t *testing.T) { if c, err := ln.Accept(); err != nil { if !err.(Error).Timeout() { - t.Fatalf("TCPListener.Accept failed: %v", err) + t.Fatal(err) } } else { c.Close() } if c, err := ln.AcceptTCP(); err != nil { if !err.(Error).Timeout() { - t.Fatalf("TCPListener.AcceptTCP failed: %v", err) + t.Fatal(err) } } else { c.Close() } if f, err := ln.File(); err != nil { - condFatalf(t, "TCPListener.File failed: %v", err) + condFatalf(t, "%v", err) } else { f.Close() } @@ -81,25 +63,30 @@ func TestTCPListenerSpecificMethods(t *testing.T) { func TestTCPConnSpecificMethods(t *testing.T) { la, err := ResolveTCPAddr("tcp4", "127.0.0.1:0") if err != nil { - t.Fatalf("ResolveTCPAddr failed: %v", err) + t.Fatal(err) } ln, err := ListenTCP("tcp4", la) if err != nil { - t.Fatalf("ListenTCP failed: %v", err) + t.Fatal(err) + } + ch := make(chan error, 1) + handler := func(ls *localServer, ln Listener) { transponder(ls.Listener, ch) } + ls, err := (&streamListener{Listener: ln}).newLocalServer() + if err != nil { + t.Fatal(err) + } + defer ls.teardown() + if err := ls.buildup(handler); err != nil { + t.Fatal(err) } - defer ln.Close() - ln.Addr() - - done := make(chan int) - go transponder(t, ln, done) - ra, err := ResolveTCPAddr("tcp4", ln.Addr().String()) + ra, err := ResolveTCPAddr("tcp4", ls.Listener.Addr().String()) if err != nil { - t.Fatalf("ResolveTCPAddr failed: %v", err) + t.Fatal(err) } c, err := DialTCP("tcp4", nil, ra) if err != nil { - t.Fatalf("DialTCP failed: %v", err) + t.Fatal(err) } defer c.Close() c.SetKeepAlive(false) @@ -113,24 +100,26 @@ func TestTCPConnSpecificMethods(t *testing.T) { c.SetWriteDeadline(time.Now().Add(someTimeout)) if _, err := c.Write([]byte("TCPCONN TEST")); err != nil { - t.Fatalf("TCPConn.Write failed: %v", err) + t.Fatal(err) } rb := make([]byte, 128) if _, err := c.Read(rb); err != nil { - t.Fatalf("TCPConn.Read failed: %v", err) + t.Fatal(err) } - <-done + for err := range ch { + t.Error(err) + } } func TestUDPConnSpecificMethods(t *testing.T) { la, err := ResolveUDPAddr("udp4", "127.0.0.1:0") if err != nil { - t.Fatalf("ResolveUDPAddr failed: %v", err) + t.Fatal(err) } c, err := ListenUDP("udp4", la) if err != nil { - t.Fatalf("ListenUDP failed: %v", err) + t.Fatal(err) } defer c.Close() c.LocalAddr() @@ -144,27 +133,27 @@ func TestUDPConnSpecificMethods(t *testing.T) { wb := []byte("UDPCONN TEST") rb := make([]byte, 128) if _, err := c.WriteToUDP(wb, c.LocalAddr().(*UDPAddr)); err != nil { - t.Fatalf("UDPConn.WriteToUDP failed: %v", err) + t.Fatal(err) } if _, _, err := c.ReadFromUDP(rb); err != nil { - t.Fatalf("UDPConn.ReadFromUDP failed: %v", err) + t.Fatal(err) } if _, _, err := c.WriteMsgUDP(wb, nil, c.LocalAddr().(*UDPAddr)); err != nil { - condFatalf(t, "UDPConn.WriteMsgUDP failed: %v", err) + condFatalf(t, "%v", err) } if _, _, _, _, err := c.ReadMsgUDP(rb, nil); err != nil { - condFatalf(t, "UDPConn.ReadMsgUDP failed: %v", err) + condFatalf(t, "%v", err) } if f, err := c.File(); err != nil { - condFatalf(t, "UDPConn.File failed: %v", err) + condFatalf(t, "%v", err) } else { f.Close() } defer func() { if p := recover(); p != nil { - t.Fatalf("UDPConn.WriteToUDP or WriteMsgUDP panicked: %v", p) + t.Fatalf("panicked: %v", p) } }() @@ -173,17 +162,17 @@ func TestUDPConnSpecificMethods(t *testing.T) { } func TestIPConnSpecificMethods(t *testing.T) { - if skip, skipmsg := skipRawSocketTest(t); skip { - t.Skip(skipmsg) + if os.Getuid() != 0 { + t.Skip("must be root") } la, err := ResolveIPAddr("ip4", "127.0.0.1") if err != nil { - t.Fatalf("ResolveIPAddr failed: %v", err) + t.Fatal(err) } c, err := ListenIP("ip4:icmp", la) if err != nil { - t.Fatalf("ListenIP failed: %v", err) + t.Fatal(err) } defer c.Close() c.LocalAddr() @@ -194,60 +183,36 @@ func TestIPConnSpecificMethods(t *testing.T) { c.SetReadBuffer(2048) c.SetWriteBuffer(2048) - wb, err := (&icmpMessage{ - Type: icmpv4EchoRequest, Code: 0, - Body: &icmpEcho{ - ID: os.Getpid() & 0xffff, Seq: 1, - Data: []byte("IPCONN TEST "), - }, - }).Marshal() - if err != nil { - t.Fatalf("icmpMessage.Marshal failed: %v", err) - } - rb := make([]byte, 20+len(wb)) - if _, err := c.WriteToIP(wb, c.LocalAddr().(*IPAddr)); err != nil { - t.Fatalf("IPConn.WriteToIP failed: %v", err) - } - if _, _, err := c.ReadFromIP(rb); err != nil { - t.Fatalf("IPConn.ReadFromIP failed: %v", err) - } - if _, _, err := c.WriteMsgIP(wb, nil, c.LocalAddr().(*IPAddr)); err != nil { - condFatalf(t, "IPConn.WriteMsgIP failed: %v", err) - } - if _, _, _, _, err := c.ReadMsgIP(rb, nil); err != nil { - condFatalf(t, "IPConn.ReadMsgIP failed: %v", err) - } - if f, err := c.File(); err != nil { - condFatalf(t, "IPConn.File failed: %v", err) + condFatalf(t, "%v", err) } else { f.Close() } defer func() { if p := recover(); p != nil { - t.Fatalf("IPConn.WriteToIP or WriteMsgIP panicked: %v", p) + t.Fatalf("panicked: %v", p) } }() + wb := []byte("IPCONN TEST") c.WriteToIP(wb, nil) c.WriteMsgIP(wb, nil, nil) } func TestUnixListenerSpecificMethods(t *testing.T) { - switch runtime.GOOS { - case "nacl", "plan9", "windows": - t.Skipf("skipping test on %q", runtime.GOOS) + if !testableNetwork("unix") { + t.Skip("unix test") } addr := testUnixAddr() la, err := ResolveUnixAddr("unix", addr) if err != nil { - t.Fatalf("ResolveUnixAddr failed: %v", err) + t.Fatal(err) } ln, err := ListenUnix("unix", la) if err != nil { - t.Fatalf("ListenUnix failed: %v", err) + t.Fatal(err) } defer ln.Close() defer os.Remove(addr) @@ -256,41 +221,40 @@ func TestUnixListenerSpecificMethods(t *testing.T) { if c, err := ln.Accept(); err != nil { if !err.(Error).Timeout() { - t.Fatalf("UnixListener.Accept failed: %v", err) + t.Fatal(err) } } else { c.Close() } if c, err := ln.AcceptUnix(); err != nil { if !err.(Error).Timeout() { - t.Fatalf("UnixListener.AcceptUnix failed: %v", err) + t.Fatal(err) } } else { c.Close() } if f, err := ln.File(); err != nil { - t.Fatalf("UnixListener.File failed: %v", err) + t.Fatal(err) } else { f.Close() } } func TestUnixConnSpecificMethods(t *testing.T) { - switch runtime.GOOS { - case "nacl", "plan9", "windows": - t.Skipf("skipping test on %q", runtime.GOOS) + if !testableNetwork("unixgram") { + t.Skip("unixgram test") } addr1, addr2, addr3 := testUnixAddr(), testUnixAddr(), testUnixAddr() a1, err := ResolveUnixAddr("unixgram", addr1) if err != nil { - t.Fatalf("ResolveUnixAddr failed: %v", err) + t.Fatal(err) } c1, err := DialUnix("unixgram", a1, nil) if err != nil { - t.Fatalf("DialUnix failed: %v", err) + t.Fatal(err) } defer c1.Close() defer os.Remove(addr1) @@ -304,11 +268,11 @@ func TestUnixConnSpecificMethods(t *testing.T) { a2, err := ResolveUnixAddr("unixgram", addr2) if err != nil { - t.Fatalf("ResolveUnixAddr failed: %v", err) + t.Fatal(err) } c2, err := DialUnix("unixgram", a2, nil) if err != nil { - t.Fatalf("DialUnix failed: %v", err) + t.Fatal(err) } defer c2.Close() defer os.Remove(addr2) @@ -322,11 +286,11 @@ func TestUnixConnSpecificMethods(t *testing.T) { a3, err := ResolveUnixAddr("unixgram", addr3) if err != nil { - t.Fatalf("ResolveUnixAddr failed: %v", err) + t.Fatal(err) } c3, err := ListenUnixgram("unixgram", a3) if err != nil { - t.Fatalf("ListenUnixgram failed: %v", err) + t.Fatal(err) } defer c3.Close() defer os.Remove(addr3) @@ -343,39 +307,39 @@ func TestUnixConnSpecificMethods(t *testing.T) { rb2 := make([]byte, 128) rb3 := make([]byte, 128) if _, _, err := c1.WriteMsgUnix(wb, nil, a2); err != nil { - t.Fatalf("UnixConn.WriteMsgUnix failed: %v", err) + t.Fatal(err) } if _, _, _, _, err := c2.ReadMsgUnix(rb2, nil); err != nil { - t.Fatalf("UnixConn.ReadMsgUnix failed: %v", err) + t.Fatal(err) } if _, err := c2.WriteToUnix(wb, a1); err != nil { - t.Fatalf("UnixConn.WriteToUnix failed: %v", err) + t.Fatal(err) } if _, _, err := c1.ReadFromUnix(rb1); err != nil { - t.Fatalf("UnixConn.ReadFromUnix failed: %v", err) + t.Fatal(err) } if _, err := c3.WriteToUnix(wb, a1); err != nil { - t.Fatalf("UnixConn.WriteToUnix failed: %v", err) + t.Fatal(err) } if _, _, err := c1.ReadFromUnix(rb1); err != nil { - t.Fatalf("UnixConn.ReadFromUnix failed: %v", err) + t.Fatal(err) } if _, err := c2.WriteToUnix(wb, a3); err != nil { - t.Fatalf("UnixConn.WriteToUnix failed: %v", err) + t.Fatal(err) } if _, _, err := c3.ReadFromUnix(rb3); err != nil { - t.Fatalf("UnixConn.ReadFromUnix failed: %v", err) + t.Fatal(err) } if f, err := c1.File(); err != nil { - t.Fatalf("UnixConn.File failed: %v", err) + t.Fatal(err) } else { f.Close() } defer func() { if p := recover(); p != nil { - t.Fatalf("UnixConn.WriteToUnix or WriteMsgUnix panicked: %v", p) + t.Fatalf("panicked: %v", p) } }() diff --git a/libgo/go/net/rpc/client_test.go b/libgo/go/net/rpc/client_test.go index 5dd111b299f..ba11ff85869 100644 --- a/libgo/go/net/rpc/client_test.go +++ b/libgo/go/net/rpc/client_test.go @@ -54,7 +54,7 @@ func (s *S) Recv(nul *struct{}, reply *R) error { func TestGobError(t *testing.T) { if runtime.GOOS == "plan9" { - t.Skip("skipping test; see http://golang.org/issue/8908") + t.Skip("skipping test; see https://golang.org/issue/8908") } defer func() { err := recover() diff --git a/libgo/go/net/rpc/server.go b/libgo/go/net/rpc/server.go index 83728d55a18..6e6e8819174 100644 --- a/libgo/go/net/rpc/server.go +++ b/libgo/go/net/rpc/server.go @@ -13,6 +13,7 @@ Only methods that satisfy these criteria will be made available for remote access; other methods will be ignored: + - the method's type is exported. - the method is exported. - the method has two arguments, both exported (or builtin) types. - the method's second argument is a pointer. @@ -216,7 +217,7 @@ func isExportedOrBuiltinType(t reflect.Type) bool { // Register publishes in the server the set of methods of the // receiver value that satisfy the following conditions: -// - exported method +// - exported method of exported type // - two arguments, both of exported type // - the second argument is a pointer // - one return value, of type error diff --git a/libgo/go/net/sendfile_dragonfly.go b/libgo/go/net/sendfile_dragonfly.go index bc88fd3b907..a9cf3fe9517 100644 --- a/libgo/go/net/sendfile_dragonfly.go +++ b/libgo/go/net/sendfile_dragonfly.go @@ -91,13 +91,16 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) { if err1 != nil { // This includes syscall.ENOSYS (no kernel // support) and syscall.EINVAL (fd types which - // don't implement sendfile together) - err = &OpError{"sendfile", c.net, c.raddr, err1} + // don't implement sendfile) + err = err1 break } } if lr != nil { lr.N = remain } + if err != nil { + err = os.NewSyscallError("sendfile", err) + } return written, err, written > 0 } diff --git a/libgo/go/net/sendfile_freebsd.go b/libgo/go/net/sendfile_freebsd.go index ffc147262a8..d0bf6034c18 100644 --- a/libgo/go/net/sendfile_freebsd.go +++ b/libgo/go/net/sendfile_freebsd.go @@ -91,13 +91,16 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) { if err1 != nil { // This includes syscall.ENOSYS (no kernel // support) and syscall.EINVAL (fd types which - // don't implement sendfile together) - err = &OpError{"sendfile", c.net, c.raddr, err1} + // don't implement sendfile) + err = err1 break } } if lr != nil { lr.N = remain } + if err != nil { + err = os.NewSyscallError("sendfile", err) + } return written, err, written > 0 } diff --git a/libgo/go/net/sendfile_linux.go b/libgo/go/net/sendfile_linux.go index 5e117636a80..5ca41c39eb5 100644 --- a/libgo/go/net/sendfile_linux.go +++ b/libgo/go/net/sendfile_linux.go @@ -64,13 +64,16 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) { if err1 != nil { // This includes syscall.ENOSYS (no kernel // support) and syscall.EINVAL (fd types which - // don't implement sendfile together) - err = &OpError{"sendfile", c.net, c.raddr, err1} + // don't implement sendfile) + err = err1 break } } if lr != nil { lr.N = remain } + if err != nil { + err = os.NewSyscallError("sendfile", err) + } return written, err, written > 0 } diff --git a/libgo/go/net/sendfile_solaris.go b/libgo/go/net/sendfile_solaris.go new file mode 100644 index 00000000000..0966575696b --- /dev/null +++ b/libgo/go/net/sendfile_solaris.go @@ -0,0 +1,110 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package net + +import ( + "io" + "os" + "syscall" +) + +// Not strictly needed, but very helpful for debugging, see issue #10221. +//go:cgo_import_dynamic _ _ "libsendfile.so" +//go:cgo_import_dynamic _ _ "libsocket.so" + +// maxSendfileSize is the largest chunk size we ask the kernel to copy +// at a time. +const maxSendfileSize int = 4 << 20 + +// sendFile copies the contents of r to c using the sendfile +// system call to minimize copies. +// +// if handled == true, sendFile returns the number of bytes copied and any +// non-EOF error. +// +// if handled == false, sendFile performed no work. +func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) { + // Solaris uses 0 as the "until EOF" value. If you pass in more bytes than the + // file contains, it will loop back to the beginning ad nauseam until it's sent + // exactly the number of bytes told to. As such, we need to know exactly how many + // bytes to send. + var remain int64 = 0 + + lr, ok := r.(*io.LimitedReader) + if ok { + remain, r = lr.N, lr.R + if remain <= 0 { + return 0, nil, true + } + } + f, ok := r.(*os.File) + if !ok { + return 0, nil, false + } + + if remain == 0 { + fi, err := f.Stat() + if err != nil { + return 0, err, false + } + + remain = fi.Size() + } + + // The other quirk with Solaris's sendfile implementation is that it doesn't + // use the current position of the file -- if you pass it offset 0, it starts + // from offset 0. There's no way to tell it "start from current position", so + // we have to manage that explicitly. + pos, err := f.Seek(0, os.SEEK_CUR) + if err != nil { + return 0, err, false + } + + if err := c.writeLock(); err != nil { + return 0, err, true + } + defer c.writeUnlock() + + dst := c.sysfd + src := int(f.Fd()) + for remain > 0 { + n := maxSendfileSize + if int64(n) > remain { + n = int(remain) + } + pos1 := pos + n, err1 := syscall.Sendfile(dst, src, &pos1, n) + if n > 0 { + pos += int64(n) + written += int64(n) + remain -= int64(n) + } + if n == 0 && err1 == nil { + break + } + if err1 == syscall.EAGAIN { + if err1 = c.pd.WaitWrite(); err1 == nil { + continue + } + } + if err1 == syscall.EINTR { + continue + } + if err1 != nil { + // This includes syscall.ENOSYS (no kernel + // support) and syscall.EINVAL (fd types which + // don't implement sendfile) + err = err1 + break + } + } + if lr != nil { + lr.N = remain + } + if err != nil { + err = os.NewSyscallError("sendfile", err) + } + return written, err, written > 0 +} diff --git a/libgo/go/net/sendfile_stub.go b/libgo/go/net/sendfile_stub.go index 03426ef0df1..a0760b4e526 100644 --- a/libgo/go/net/sendfile_stub.go +++ b/libgo/go/net/sendfile_stub.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build darwin nacl netbsd openbsd solaris +// +build darwin nacl netbsd openbsd package net diff --git a/libgo/go/net/sendfile_windows.go b/libgo/go/net/sendfile_windows.go index b128ba27b00..f3f3b54b886 100644 --- a/libgo/go/net/sendfile_windows.go +++ b/libgo/go/net/sendfile_windows.go @@ -46,7 +46,7 @@ func sendFile(fd *netFD, r io.Reader) (written int64, err error, handled bool) { return syscall.TransmitFile(o.fd.sysfd, o.handle, o.qty, 0, &o.o, nil, syscall.TF_WRITE_BEHIND) }) if err != nil { - return 0, err, false + return 0, os.NewSyscallError("transmitfile", err), false } if lr != nil { lr.N -= int64(done) diff --git a/libgo/go/net/server_test.go b/libgo/go/net/server_test.go index 6a2bb924329..fe0006b11fb 100644 --- a/libgo/go/net/server_test.go +++ b/libgo/go/net/server_test.go @@ -5,457 +5,384 @@ package net import ( - "flag" - "io" "os" - "runtime" "testing" - "time" ) -func skipServerTest(net, unixsotype, addr string, ipv6, ipv4map, linuxOnly bool) bool { - switch runtime.GOOS { - case "linux": - case "nacl", "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 -} - -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 - linuxOnly bool // test with abstract unix domain socket, a Linux-ism +var tcpServerTests = []struct { + snet, saddr string // server endpoint + tnet, taddr string // target endpoint for client }{ - {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}, + {snet: "tcp", saddr: ":0", tnet: "tcp", taddr: "127.0.0.1"}, + {snet: "tcp", saddr: "0.0.0.0:0", tnet: "tcp", taddr: "127.0.0.1"}, + {snet: "tcp", saddr: "[::ffff:0.0.0.0]:0", tnet: "tcp", taddr: "127.0.0.1"}, + {snet: "tcp", saddr: "[::]:0", tnet: "tcp", taddr: "::1"}, - {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: ":0", tnet: "tcp", taddr: "::1"}, + {snet: "tcp", saddr: "0.0.0.0:0", tnet: "tcp", taddr: "::1"}, + {snet: "tcp", saddr: "[::ffff:0.0.0.0]:0", tnet: "tcp", taddr: "::1"}, + {snet: "tcp", saddr: "[::]:0", tnet: "tcp", taddr: "127.0.0.1"}, - {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: ":0", tnet: "tcp4", taddr: "127.0.0.1"}, + {snet: "tcp", saddr: "0.0.0.0:0", tnet: "tcp4", taddr: "127.0.0.1"}, + {snet: "tcp", saddr: "[::ffff:0.0.0.0]:0", tnet: "tcp4", taddr: "127.0.0.1"}, + {snet: "tcp", saddr: "[::]:0", tnet: "tcp6", taddr: "::1"}, - {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: ":0", tnet: "tcp6", taddr: "::1"}, + {snet: "tcp", saddr: "0.0.0.0:0", tnet: "tcp6", taddr: "::1"}, + {snet: "tcp", saddr: "[::ffff:0.0.0.0]:0", tnet: "tcp6", taddr: "::1"}, + {snet: "tcp", saddr: "[::]:0", tnet: "tcp4", taddr: "127.0.0.1"}, - {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: "tcp", saddr: "127.0.0.1:0", tnet: "tcp", taddr: "127.0.0.1"}, + {snet: "tcp", saddr: "[::ffff:127.0.0.1]:0", tnet: "tcp", taddr: "127.0.0.1"}, + {snet: "tcp", saddr: "[::1]:0", tnet: "tcp", taddr: "::1"}, - {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: ":0", tnet: "tcp4", taddr: "127.0.0.1"}, + {snet: "tcp4", saddr: "0.0.0.0:0", tnet: "tcp4", taddr: "127.0.0.1"}, + {snet: "tcp4", saddr: "[::ffff:0.0.0.0]:0", tnet: "tcp4", taddr: "127.0.0.1"}, - {snet: "tcp4", saddr: "127.0.0.1", cnet: "tcp4", caddr: "127.0.0.1"}, + {snet: "tcp4", saddr: "127.0.0.1:0", tnet: "tcp4", taddr: "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: ":0", tnet: "tcp6", taddr: "::1"}, + {snet: "tcp6", saddr: "[::]:0", tnet: "tcp6", taddr: "::1"}, - {snet: "tcp6", saddr: "[::1]", cnet: "tcp6", caddr: "[::1]", ipv6: true}, - - {snet: "unix", saddr: testUnixAddr(), cnet: "unix", caddr: testUnixAddr()}, - {snet: "unix", saddr: "@gotest2/net", cnet: "unix", caddr: "@gotest2/net.local", linuxOnly: true}, + {snet: "tcp6", saddr: "[::1]:0", tnet: "tcp6", taddr: "::1"}, } -func TestStreamConnServer(t *testing.T) { - for _, tt := range streamConnServerTests { - if skipServerTest(tt.snet, "unix", tt.saddr, tt.ipv6, tt.ipv4map, tt.linuxOnly) { +// TestTCPServer tests concurrent accept-read-write servers. +func TestTCPServer(t *testing.T) { + const N = 3 + + for i, tt := range tcpServerTests { + if !testableListenArgs(tt.snet, tt.saddr, tt.taddr) { + t.Logf("skipping %s test", tt.snet+" "+tt.saddr+"->"+tt.taddr) 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) + ln, err := Listen(tt.snet, tt.saddr) + if err != nil { + if perr := parseDialError(err); perr != nil { + t.Error(perr) + } + t.Fatal(err) } - 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) + var lss []*localServer + var tpchs []chan error + defer func() { + for _, ls := range lss { + ls.teardown() + } + }() + for i := 0; i < N; i++ { + ls, err := (&streamListener{Listener: ln}).newLocalServer() if err != nil { - t.Fatalf("SplitHostPort(%q) failed: %v", taddr, err) + t.Fatal(err) + } + lss = append(lss, ls) + tpchs = append(tpchs, make(chan error, 1)) + } + for i := 0; i < N; i++ { + ch := tpchs[i] + handler := func(ls *localServer, ln Listener) { transponder(ln, ch) } + if err := lss[i].buildup(handler); err != nil { + t.Fatal(err) } - taddr = tt.caddr + ":" + port } - runStreamConnClient(t, tt.cnet, taddr, tt.empty) - <-done // make sure server stopped + var trchs []chan error + for i := 0; i < N; i++ { + _, port, err := SplitHostPort(lss[i].Listener.Addr().String()) + if err != nil { + t.Fatal(err) + } + d := Dialer{Timeout: someTimeout} + c, err := d.Dial(tt.tnet, JoinHostPort(tt.taddr, port)) + if err != nil { + if perr := parseDialError(err); perr != nil { + t.Error(perr) + } + t.Fatal(err) + } + defer c.Close() + trchs = append(trchs, make(chan error, 1)) + go transceiver(c, []byte("TCP SERVER TEST"), trchs[i]) + } - switch tt.snet { - case "unix": - os.Remove(tt.saddr) - os.Remove(tt.caddr) + for _, ch := range trchs { + for err := range ch { + t.Errorf("#%d: %v", i, err) + } + } + for _, ch := range tpchs { + for err := range ch { + t.Errorf("#%d: %v", i, err) + } } } } -var seqpacketConnServerTests = []struct { - net string - saddr string // server address - caddr string // client address - empty bool // test with empty data - linuxOnly bool // test with abstract unix domain socket, a Linux-ism +var unixAndUnixpacketServerTests = []struct { + network, address string }{ - {net: "unixpacket", saddr: testUnixAddr(), caddr: testUnixAddr()}, - {net: "unixpacket", saddr: "@gotest4/net", caddr: "@gotest4/net.local", linuxOnly: true}, + {"unix", testUnixAddr()}, + {"unix", "@nettest/go/unix"}, + + {"unixpacket", testUnixAddr()}, + {"unixpacket", "@nettest/go/unixpacket"}, } -func TestSeqpacketConnServer(t *testing.T) { - switch runtime.GOOS { - case "darwin", "nacl", "openbsd", "plan9", "windows": - fallthrough - case "freebsd": // FreeBSD 8 doesn't support unixpacket - t.Skipf("skipping test on %q", runtime.GOOS) - } +// TestUnixAndUnixpacketServer tests concurrent accept-read-write +// servers +func TestUnixAndUnixpacketServer(t *testing.T) { + const N = 3 - for _, tt := range seqpacketConnServerTests { - if runtime.GOOS != "linux" && tt.linuxOnly { + for i, tt := range unixAndUnixpacketServerTests { + if !testableListenArgs(tt.network, tt.address, "") { + t.Logf("skipping %s test", tt.network+" "+tt.address) continue } - 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) + ln, err := Listen(tt.network, tt.address) + if err != nil { + if perr := parseDialError(err); perr != nil { + t.Error(perr) + } + t.Fatal(err) } - } -} -func runStreamConnServer(t *testing.T, net, laddr string, listening chan<- string, done chan<- int) { - defer close(done) - l, err := Listen(net, laddr) - if err != nil { - t.Errorf("Listen(%q, %q) failed: %v", net, laddr, err) - listening <- "" - 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 + var lss []*localServer + var tpchs []chan error + defer func() { + for _, ls := range lss { + ls.teardown() } - rw.Write(buf[0:n]) + }() + for i := 0; i < N; i++ { + ls, err := (&streamListener{Listener: ln}).newLocalServer() + if err != nil { + t.Fatal(err) + } + lss = append(lss, ls) + tpchs = append(tpchs, make(chan error, 1)) } - close(done) - } - -run: - for { - c, err := l.Accept() - if err != nil { - t.Logf("Accept failed: %v", err) - continue run + for i := 0; i < N; i++ { + ch := tpchs[i] + handler := func(ls *localServer, ln Listener) { transponder(ln, ch) } + if err := lss[i].buildup(handler); err != nil { + t.Fatal(err) + } } - echodone := make(chan int) - go echo(c, echodone) - <-echodone // make sure echo stopped - c.Close() - break run - } -} - -func runStreamConnClient(t *testing.T, net, taddr string, isEmpty bool) { - c, err := Dial(net, taddr) - if err != nil { - t.Fatalf("Dial(%q, %q) failed: %v", net, taddr, err) - } - defer c.Close() - c.SetReadDeadline(time.Now().Add(1 * time.Second)) - var wb []byte - if !isEmpty { - wb = []byte("StreamConnClient by Dial\n") - } - if n, err := c.Write(wb); err != nil || n != len(wb) { - t.Fatalf("Write failed: %v, %v; want %v, ", n, err, len(wb)) - } - - rb := make([]byte, 1024) - if n, err := c.Read(rb[0:]); err != nil || n != len(wb) { - t.Fatalf("Read failed: %v, %v; want %v, ", n, err, len(wb)) - } + var trchs []chan error + for i := 0; i < N; i++ { + d := Dialer{Timeout: someTimeout} + c, err := d.Dial(lss[i].Listener.Addr().Network(), lss[i].Listener.Addr().String()) + if err != nil { + if perr := parseDialError(err); perr != nil { + t.Error(perr) + } + t.Fatal(err) + } + defer os.Remove(c.LocalAddr().String()) + defer c.Close() + trchs = append(trchs, make(chan error, 1)) + go transceiver(c, []byte("UNIX AND UNIXPACKET SERVER TEST"), trchs[i]) + } - // Send explicit ending for unixpacket. - // Older Linux kernels do not stop reads on close. - switch net { - case "unixpacket": - c.Write([]byte("END")) + for _, ch := range trchs { + for err := range ch { + t.Errorf("#%d: %v", i, err) + } + } + for _, ch := range tpchs { + for err := range ch { + t.Errorf("#%d: %v", i, err) + } + } } } -// 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") - -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 - linuxOnly bool // test with abstract unix domain socket, a Linux-ism +var udpServerTests = []struct { + snet, saddr string // server endpoint + tnet, taddr string // target endpoint for client + dial bool // test with Dial }{ - {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: ":0", tnet: "udp", taddr: "127.0.0.1"}, + {snet: "udp", saddr: "0.0.0.0:0", tnet: "udp", taddr: "127.0.0.1"}, + {snet: "udp", saddr: "[::ffff:0.0.0.0]:0", tnet: "udp", taddr: "127.0.0.1"}, + {snet: "udp", saddr: "[::]:0", tnet: "udp", taddr: "::1"}, - {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: ":0", tnet: "udp", taddr: "::1"}, + {snet: "udp", saddr: "0.0.0.0:0", tnet: "udp", taddr: "::1"}, + {snet: "udp", saddr: "[::ffff:0.0.0.0]:0", tnet: "udp", taddr: "::1"}, + {snet: "udp", saddr: "[::]:0", tnet: "udp", taddr: "127.0.0.1"}, - {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: ":0", tnet: "udp4", taddr: "127.0.0.1"}, + {snet: "udp", saddr: "0.0.0.0:0", tnet: "udp4", taddr: "127.0.0.1"}, + {snet: "udp", saddr: "[::ffff:0.0.0.0]:0", tnet: "udp4", taddr: "127.0.0.1"}, + {snet: "udp", saddr: "[::]:0", tnet: "udp6", taddr: "::1"}, - {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: "udp", saddr: ":0", tnet: "udp6", taddr: "::1"}, + {snet: "udp", saddr: "0.0.0.0:0", tnet: "udp6", taddr: "::1"}, + {snet: "udp", saddr: "[::ffff:0.0.0.0]:0", tnet: "udp6", taddr: "::1"}, + {snet: "udp", saddr: "[::]:0", tnet: "udp4", taddr: "127.0.0.1"}, - {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: "udp", saddr: "127.0.0.1:0", tnet: "udp", taddr: "127.0.0.1"}, + {snet: "udp", saddr: "[::ffff:127.0.0.1]:0", tnet: "udp", taddr: "127.0.0.1"}, + {snet: "udp", saddr: "[::1]:0", tnet: "udp", taddr: "::1"}, - {snet: "udp4", saddr: "127.0.0.1", cnet: "udp4", caddr: "127.0.0.1"}, + {snet: "udp4", saddr: ":0", tnet: "udp4", taddr: "127.0.0.1"}, + {snet: "udp4", saddr: "0.0.0.0:0", tnet: "udp4", taddr: "127.0.0.1"}, + {snet: "udp4", saddr: "[::ffff:0.0.0.0]:0", tnet: "udp4", taddr: "127.0.0.1"}, - {snet: "udp6", saddr: "", cnet: "udp6", caddr: "[::1]", ipv6: true}, - {snet: "udp6", saddr: "[::]", cnet: "udp6", caddr: "[::1]", ipv6: true}, + {snet: "udp4", saddr: "127.0.0.1:0", tnet: "udp4", taddr: "127.0.0.1"}, - {snet: "udp6", saddr: "[::1]", cnet: "udp6", caddr: "[::1]", ipv6: true}, + {snet: "udp6", saddr: ":0", tnet: "udp6", taddr: "::1"}, + {snet: "udp6", saddr: "[::]:0", tnet: "udp6", taddr: "::1"}, - {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: "udp6", saddr: "[::1]:0", tnet: "udp6", taddr: "::1"}, - {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: "udp", saddr: "127.0.0.1:0", tnet: "udp", taddr: "127.0.0.1", dial: true}, - {snet: "unixgram", saddr: testUnixAddr(), cnet: "unixgram", caddr: testUnixAddr()}, - {snet: "unixgram", saddr: testUnixAddr(), cnet: "unixgram", caddr: testUnixAddr(), dial: true}, - {snet: "unixgram", saddr: testUnixAddr(), cnet: "unixgram", caddr: testUnixAddr(), empty: true}, - {snet: "unixgram", saddr: testUnixAddr(), cnet: "unixgram", caddr: testUnixAddr(), dial: true, empty: true}, - - {snet: "unixgram", saddr: "@gotest6/net", cnet: "unixgram", caddr: "@gotest6/net.local", linuxOnly: true}, + {snet: "udp", saddr: "[::1]:0", tnet: "udp", taddr: "::1", dial: true}, } -func TestDatagramPacketConnServer(t *testing.T) { - if !*testDatagram { - return - } - - for _, tt := range datagramPacketConnServerTests { - if skipServerTest(tt.snet, "unixgram", tt.saddr, tt.ipv6, tt.ipv4map, tt.linuxOnly) { +func TestUDPServer(t *testing.T) { + for i, tt := range udpServerTests { + if !testableListenArgs(tt.snet, tt.saddr, tt.taddr) { + t.Logf("skipping %s test", tt.snet+" "+tt.saddr+"->"+tt.taddr) 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) + c1, err := ListenPacket(tt.snet, tt.saddr) + if err != nil { + if perr := parseDialError(err); perr != nil { + t.Error(perr) + } + t.Fatal(err) } - go runDatagramPacketConnServer(t, tt.snet, tt.saddr, listening, done) - taddr := <-listening // wait for server to start + ls, err := (&packetListener{PacketConn: c1}).newLocalServer() + if err != nil { + t.Fatal(err) + } + defer ls.teardown() + tpch := make(chan error, 1) + handler := func(ls *localPacketServer, c PacketConn) { packetTransponder(c, tpch) } + if err := ls.buildup(handler); err != nil { + t.Fatal(err) + } - switch tt.cnet { - case "udp", "udp4", "udp6": - _, port, err := SplitHostPort(taddr) - if err != nil { - t.Fatalf("SplitHostPort(%q) failed: %v", taddr, err) - } - taddr = tt.caddr + ":" + port - tt.caddr += ":0" + trch := make(chan error, 1) + _, port, err := SplitHostPort(ls.PacketConn.LocalAddr().String()) + if err != nil { + t.Fatal(err) } if tt.dial { - runDatagramConnClient(t, tt.cnet, tt.caddr, taddr, tt.empty) + d := Dialer{Timeout: someTimeout} + c2, err := d.Dial(tt.tnet, JoinHostPort(tt.taddr, port)) + if err != nil { + if perr := parseDialError(err); perr != nil { + t.Error(perr) + } + t.Fatal(err) + } + defer c2.Close() + go transceiver(c2, []byte("UDP SERVER TEST"), trch) } else { - runDatagramPacketConnClient(t, tt.cnet, tt.caddr, taddr, tt.empty) + c2, err := ListenPacket(tt.tnet, JoinHostPort(tt.taddr, "0")) + if err != nil { + if perr := parseDialError(err); perr != nil { + t.Error(perr) + } + t.Fatal(err) + } + defer c2.Close() + dst, err := ResolveUDPAddr(tt.tnet, JoinHostPort(tt.taddr, port)) + if err != nil { + t.Fatal(err) + } + go packetTransceiver(c2, []byte("UDP SERVER TEST"), dst, trch) } - <-done // tell server to stop - <-done // make sure server stopped - switch tt.snet { - case "unixgram": - os.Remove(tt.saddr) - os.Remove(tt.caddr) + for err := range trch { + t.Errorf("#%d: %v", i, err) + } + for err := range tpch { + t.Errorf("#%d: %v", i, err) } } } -func runDatagramPacketConnServer(t *testing.T, net, laddr string, listening chan<- string, done chan<- int) { - c, err := ListenPacket(net, laddr) - if err != nil { - t.Errorf("ListenPacket(%q, %q) failed: %v", net, laddr, err) - listening <- "" - done <- 1 - return - } - defer c.Close() - listening <- c.LocalAddr().String() - - buf := make([]byte, 1024) -run: - for { - c.SetReadDeadline(time.Now().Add(10 * time.Millisecond)) - n, ra, err := c.ReadFrom(buf[0:]) - if nerr, ok := err.(Error); ok && nerr.Timeout() { - select { - case done <- 1: - break run - default: - continue run - } - } - if err != nil { - break run - } - if _, err = c.WriteTo(buf[0:n], ra); err != nil { - t.Errorf("WriteTo(%v) failed: %v", ra, err) - break run - } - } - done <- 1 +var unixgramServerTests = []struct { + saddr string // server endpoint + caddr string // client endpoint + dial bool // test with Dial +}{ + {saddr: testUnixAddr(), caddr: testUnixAddr()}, + {saddr: testUnixAddr(), caddr: testUnixAddr(), dial: true}, + + {saddr: "@nettest/go/unixgram/server", caddr: "@nettest/go/unixgram/client"}, } -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.Fatalf("Dial(%q, %q) failed: %v", net, taddr, err) +func TestUnixgramServer(t *testing.T) { + for i, tt := range unixgramServerTests { + if !testableListenArgs("unixgram", tt.saddr, "") { + t.Logf("skipping %s test", "unixgram "+tt.saddr+"->"+tt.caddr) + continue } - case "unixgram": - c, err = DialUnix(net, &UnixAddr{Name: laddr, Net: net}, &UnixAddr{Name: taddr, Net: net}) + + c1, err := ListenPacket("unixgram", tt.saddr) if err != nil { - t.Fatalf("DialUnix(%q, {%q, %q}) failed: %v", net, laddr, taddr, err) + if perr := parseDialError(err); perr != nil { + t.Error(perr) + } + t.Fatal(err) } - } - defer c.Close() - c.SetReadDeadline(time.Now().Add(1 * time.Second)) - var wb []byte - if !isEmpty { - wb = []byte("DatagramConnClient by Dial\n") - } - if n, err := c.Write(wb[0:]); err != nil || n != len(wb) { - t.Fatalf("Write failed: %v, %v; want %v, ", n, err, len(wb)) - } - - rb := make([]byte, 1024) - if n, err := c.Read(rb[0:]); err != nil || n != len(wb) { - t.Fatalf("Read failed: %v, %v; want %v, ", n, err, len(wb)) - } -} - -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) + ls, err := (&packetListener{PacketConn: c1}).newLocalServer() if err != nil { - t.Fatalf("ResolveUDPAddr(%q, %q) failed: %v", net, taddr, err) + t.Fatal(err) } - case "unixgram": - ra, err = ResolveUnixAddr(net, taddr) - if err != nil { - t.Fatalf("ResolveUxixAddr(%q, %q) failed: %v", net, taddr, err) + defer ls.teardown() + tpch := make(chan error, 1) + handler := func(ls *localPacketServer, c PacketConn) { packetTransponder(c, tpch) } + if err := ls.buildup(handler); err != nil { + t.Fatal(err) } - } - c, err := ListenPacket(net, laddr) - if err != nil { - t.Fatalf("ListenPacket(%q, %q) faild: %v", net, laddr, err) - } - 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.Fatalf("WriteTo(%v) failed: %v, %v; want %v, ", ra, n, err, len(wb)) - } + trch := make(chan error, 1) + if tt.dial { + d := Dialer{Timeout: someTimeout, LocalAddr: &UnixAddr{Net: "unixgram", Name: tt.caddr}} + c2, err := d.Dial("unixgram", ls.PacketConn.LocalAddr().String()) + if err != nil { + if perr := parseDialError(err); perr != nil { + t.Error(perr) + } + t.Fatal(err) + } + defer os.Remove(c2.LocalAddr().String()) + defer c2.Close() + go transceiver(c2, []byte(c2.LocalAddr().String()), trch) + } else { + c2, err := ListenPacket("unixgram", tt.caddr) + if err != nil { + if perr := parseDialError(err); perr != nil { + t.Error(perr) + } + t.Fatal(err) + } + defer os.Remove(c2.LocalAddr().String()) + defer c2.Close() + go packetTransceiver(c2, []byte("UNIXGRAM SERVER TEST"), ls.PacketConn.LocalAddr(), trch) + } - rb := make([]byte, 1024) - if n, _, err := c.ReadFrom(rb[0:]); err != nil || n != len(wb) { - t.Fatalf("ReadFrom failed: %v, %v; want %v, ", n, err, len(wb)) + for err := range trch { + t.Errorf("#%d: %v", i, err) + } + for err := range tpch { + t.Errorf("#%d: %v", i, err) + } } } diff --git a/libgo/go/net/singleflight.go b/libgo/go/net/singleflight.go deleted file mode 100644 index bf599f0cc94..00000000000 --- a/libgo/go/net/singleflight.go +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package net - -import "sync" - -// call is an in-flight or completed singleflight.Do call -type call struct { - wg sync.WaitGroup - - // These fields are written once before the WaitGroup is done - // and are only read after the WaitGroup is done. - val interface{} - err error - - // These fields are read and written with the singleflight - // mutex held before the WaitGroup is done, and are read but - // not written after the WaitGroup is done. - dups int - chans []chan<- singleflightResult -} - -// singleflight represents a class of work and forms a namespace in -// which units of work can be executed with duplicate suppression. -type singleflight struct { - mu sync.Mutex // protects m - m map[string]*call // lazily initialized -} - -// singleflightResult holds the results of Do, so they can be passed -// on a channel. -type singleflightResult struct { - v interface{} - err error - shared bool -} - -// Do executes and returns the results of the given function, making -// sure that only one execution is in-flight for a given key at a -// time. If a duplicate comes in, the duplicate caller waits for the -// original to complete and receives the same results. -// The return value shared indicates whether v was given to multiple callers. -func (g *singleflight) Do(key string, fn func() (interface{}, error)) (v interface{}, err error, shared bool) { - g.mu.Lock() - if g.m == nil { - g.m = make(map[string]*call) - } - if c, ok := g.m[key]; ok { - c.dups++ - g.mu.Unlock() - c.wg.Wait() - return c.val, c.err, true - } - c := new(call) - c.wg.Add(1) - g.m[key] = c - g.mu.Unlock() - - g.doCall(c, key, fn) - return c.val, c.err, c.dups > 0 -} - -// DoChan is like Do but returns a channel that will receive the -// results when they are ready. -func (g *singleflight) DoChan(key string, fn func() (interface{}, error)) <-chan singleflightResult { - ch := make(chan singleflightResult, 1) - g.mu.Lock() - if g.m == nil { - g.m = make(map[string]*call) - } - if c, ok := g.m[key]; ok { - c.dups++ - c.chans = append(c.chans, ch) - g.mu.Unlock() - return ch - } - c := &call{chans: []chan<- singleflightResult{ch}} - c.wg.Add(1) - g.m[key] = c - g.mu.Unlock() - - go g.doCall(c, key, fn) - - return ch -} - -// doCall handles the single call for a key. -func (g *singleflight) doCall(c *call, key string, fn func() (interface{}, error)) { - c.val, c.err = fn() - c.wg.Done() - - g.mu.Lock() - delete(g.m, key) - for _, ch := range c.chans { - ch <- singleflightResult{c.val, c.err, c.dups > 0} - } - g.mu.Unlock() -} - -// Forget tells the singleflight to forget about a key. Future calls -// to Do for this key will call the function rather than waiting for -// an earlier call to complete. -func (g *singleflight) Forget(key string) { - g.mu.Lock() - delete(g.m, key) - g.mu.Unlock() -} diff --git a/libgo/go/net/smtp/smtp.go b/libgo/go/net/smtp/smtp.go index 87dea442c46..09883503222 100644 --- a/libgo/go/net/smtp/smtp.go +++ b/libgo/go/net/smtp/smtp.go @@ -41,7 +41,7 @@ type Client struct { } // Dial returns a new Client connected to an SMTP server at addr. -// The addr must include a port number. +// The addr must include a port, as in "mail.example.com:smtp". func Dial(addr string) (*Client, error) { conn, err := net.Dial("tcp", addr) if err != nil { @@ -157,6 +157,17 @@ func (c *Client) StartTLS(config *tls.Config) error { return c.ehlo() } +// TLSConnectionState returns the client's TLS connection state. +// The return values are their zero values if StartTLS did +// not succeed. +func (c *Client) TLSConnectionState() (state tls.ConnectionState, ok bool) { + tc, ok := c.conn.(*tls.Conn) + if !ok { + return + } + return tc.ConnectionState(), true +} + // Verify checks the validity of an email address on the server. // If Verify returns nil, the address is valid. A non-nil return // does not necessarily indicate an invalid address. Many servers @@ -253,9 +264,9 @@ func (d *dataCloser) Close() error { } // Data issues a DATA command to the server and returns a writer that -// can be used to write the data. The caller should close the writer -// before calling any more methods on c. -// A call to Data must be preceded by one or more calls to Rcpt. +// can be used to write the mail headers and body. The caller should +// close the writer before calling any more methods on c. A call to +// Data must be preceded by one or more calls to Rcpt. func (c *Client) Data() (io.WriteCloser, error) { _, _, err := c.cmd(354, "DATA") if err != nil { @@ -270,6 +281,22 @@ var testHookStartTLS func(*tls.Config) // nil, except for tests // possible, authenticates with the optional mechanism a if possible, // and then sends an email from address from, to addresses to, with // message msg. +// The addr must include a port, as in "mail.example.com:smtp". +// +// The addresses in the to parameter are the SMTP RCPT addresses. +// +// The msg parameter should be an RFC 822-style email with headers +// first, a blank line, and then the message body. The lines of msg +// should be CRLF terminated. The msg headers should usually include +// fields such as "From", "To", "Subject", and "Cc". Sending "Bcc" +// messages is accomplished by including an email address in the to +// parameter but not including it in the msg headers. +// +// The SendMail function and the the net/smtp package are low-level +// mechanisms and provide no support for DKIM signing, MIME +// attachments (see the mime/multipart package), or other mail +// functionality. Higher-level packages exist outside of the standard +// library. func SendMail(addr string, a Auth, from string, to []string, msg []byte) error { c, err := Dial(addr) if err != nil { diff --git a/libgo/go/net/smtp/smtp_test.go b/libgo/go/net/smtp/smtp_test.go index 5c659e8a095..3ae0d5bf1dd 100644 --- a/libgo/go/net/smtp/smtp_test.go +++ b/libgo/go/net/smtp/smtp_test.go @@ -571,6 +571,50 @@ func TestTLSClient(t *testing.T) { } } +func TestTLSConnState(t *testing.T) { + ln := newLocalListener(t) + defer ln.Close() + clientDone := make(chan bool) + serverDone := make(chan bool) + go func() { + defer close(serverDone) + c, err := ln.Accept() + if err != nil { + t.Errorf("Server accept: %v", err) + return + } + defer c.Close() + if err := serverHandle(c, t); err != nil { + t.Errorf("server error: %v", err) + } + }() + go func() { + defer close(clientDone) + c, err := Dial(ln.Addr().String()) + if err != nil { + t.Errorf("Client dial: %v", err) + return + } + defer c.Quit() + cfg := &tls.Config{ServerName: "example.com"} + testHookStartTLS(cfg) // set the RootCAs + if err := c.StartTLS(cfg); err != nil { + t.Errorf("StartTLS: %v", err) + return + } + cs, ok := c.TLSConnectionState() + if !ok { + t.Errorf("TLSConnectionState returned ok == false; want true") + return + } + if cs.Version == 0 || !cs.HandshakeComplete { + t.Errorf("ConnectionState = %#v; expect non-zero Version and HandshakeComplete", cs) + } + }() + <-clientDone + <-serverDone +} + func newLocalListener(t *testing.T) net.Listener { ln, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { diff --git a/libgo/go/net/sock_cloexec.go b/libgo/go/net/sock_cloexec.go index dec81855b68..616a101eacb 100644 --- a/libgo/go/net/sock_cloexec.go +++ b/libgo/go/net/sock_cloexec.go @@ -9,34 +9,41 @@ package net -import "syscall" +import ( + "os" + "syscall" +) // Wrapper around the socket system call that marks the returned file // descriptor as nonblocking and close-on-exec. func sysSocket(family, sotype, proto int) (int, error) { - s, err := syscall.Socket(family, sotype|syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC, proto) + s, err := socketFunc(family, sotype|syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC, proto) // On Linux the SOCK_NONBLOCK and SOCK_CLOEXEC flags were // introduced in 2.6.27 kernel and on FreeBSD both flags were // introduced in 10 kernel. If we get an EINVAL error on Linux // or EPROTONOSUPPORT error on FreeBSD, fall back to using // socket without them. - if err == nil || (err != syscall.EPROTONOSUPPORT && err != syscall.EINVAL) { - return s, err + switch err { + case nil: + return s, nil + default: + return -1, os.NewSyscallError("socket", err) + case syscall.EPROTONOSUPPORT, syscall.EINVAL: } // See ../syscall/exec_unix.go for description of ForkLock. syscall.ForkLock.RLock() - s, err = syscall.Socket(family, sotype, proto) + s, err = socketFunc(family, sotype, proto) if err == nil { syscall.CloseOnExec(s) } syscall.ForkLock.RUnlock() if err != nil { - return -1, err + return -1, os.NewSyscallError("socket", err) } if err = syscall.SetNonblock(s, true); err != nil { - syscall.Close(s) - return -1, err + closeFunc(s) + return -1, os.NewSyscallError("setnonblock", err) } return s, nil } @@ -44,14 +51,16 @@ func sysSocket(family, sotype, proto int) (int, error) { // Wrapper around the accept system call that marks the returned file // descriptor as nonblocking and close-on-exec. func accept(s int) (int, syscall.Sockaddr, error) { - ns, sa, err := syscall.Accept4(s, syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC) + ns, sa, err := accept4Func(s, syscall.SOCK_NONBLOCK|syscall.SOCK_CLOEXEC) // On Linux the accept4 system call was introduced in 2.6.28 // kernel and on FreeBSD it was introduced in 10 kernel. If we // get an ENOSYS error on both Linux and FreeBSD, or EINVAL // error on Linux, fall back to using accept. switch err { - default: // nil and errors other than the ones listed - return ns, sa, err + case nil: + return ns, sa, nil + default: // errors other than the ones listed + return -1, sa, os.NewSyscallError("accept4", err) case syscall.ENOSYS: // syscall missing case syscall.EINVAL: // some Linux use this instead of ENOSYS case syscall.EACCES: // some Linux use this instead of ENOSYS @@ -63,16 +72,16 @@ func accept(s int) (int, syscall.Sockaddr, error) { // because we have put fd.sysfd into non-blocking mode. // However, a call to the File method will put it back into // blocking mode. We can't take that risk, so no use of ForkLock here. - ns, sa, err = syscall.Accept(s) + ns, sa, err = acceptFunc(s) if err == nil { syscall.CloseOnExec(ns) } if err != nil { - return -1, nil, err + return -1, nil, os.NewSyscallError("accept", err) } if err = syscall.SetNonblock(ns, true); err != nil { - syscall.Close(ns) - return -1, nil, err + closeFunc(ns) + return -1, nil, os.NewSyscallError("setnonblock", err) } return ns, sa, nil } diff --git a/libgo/go/net/sock_posix.go b/libgo/go/net/sock_posix.go index 3f956df65a6..4d2cfde3f1c 100644 --- a/libgo/go/net/sock_posix.go +++ b/libgo/go/net/sock_posix.go @@ -17,8 +17,6 @@ import ( type sockaddr interface { Addr - netaddr - // family returns the platform-dependent address family // identifier. family() int @@ -42,11 +40,11 @@ func socket(net string, family, sotype, proto int, ipv6only bool, laddr, raddr s return nil, err } if err = setDefaultSockopts(s, family, sotype, ipv6only); err != nil { - closesocket(s) + closeFunc(s) return nil, err } if fd, err = newFD(s, family, sotype, net); err != nil { - closesocket(s) + closeFunc(s) return nil, err } @@ -54,7 +52,7 @@ func socket(net string, family, sotype, proto int, ipv6only bool, laddr, raddr s // following applications: // // - An endpoint holder that opens a passive stream - // connenction, known as a stream listener + // connection, known as a stream listener // // - An endpoint holder that opens a destination-unspecific // datagram connection, known as a datagram listener @@ -165,7 +163,7 @@ func (fd *netFD) listenStream(laddr sockaddr, backlog int) error { return os.NewSyscallError("bind", err) } } - if err := syscall.Listen(fd.sysfd, backlog); err != nil { + if err := listenFunc(fd.sysfd, backlog); err != nil { return os.NewSyscallError("listen", err) } if err := fd.init(); err != nil { diff --git a/libgo/go/net/sock_windows.go b/libgo/go/net/sock_windows.go index 6ccde3a24b9..888e70bb8e9 100644 --- a/libgo/go/net/sock_windows.go +++ b/libgo/go/net/sock_windows.go @@ -4,7 +4,10 @@ package net -import "syscall" +import ( + "os" + "syscall" +) func maxListenerBacklog() int { // TODO: Implement this @@ -12,13 +15,16 @@ func maxListenerBacklog() int { return syscall.SOMAXCONN } -func sysSocket(f, t, p int) (syscall.Handle, error) { +func sysSocket(family, sotype, proto int) (syscall.Handle, error) { // See ../syscall/exec_unix.go for description of ForkLock. syscall.ForkLock.RLock() - s, err := syscall.Socket(f, t, p) + s, err := socketFunc(family, sotype, proto) if err == nil { syscall.CloseOnExec(s) } syscall.ForkLock.RUnlock() - return s, err + if err != nil { + return syscall.InvalidHandle, os.NewSyscallError("socket", err) + } + return s, nil } diff --git a/libgo/go/net/sockopt_bsd.go b/libgo/go/net/sockopt_bsd.go index d5b3621c526..52b2a5debc5 100644 --- a/libgo/go/net/sockopt_bsd.go +++ b/libgo/go/net/sockopt_bsd.go @@ -25,7 +25,7 @@ func setDefaultSockopts(s, family, sotype int, ipv6only bool) error { syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_PORTRANGE, syscall.IPV6_PORTRANGE_HIGH) } } - if family == syscall.AF_INET6 && sotype != syscall.SOCK_RAW { + if supportsIPv4map && family == syscall.AF_INET6 && sotype != syscall.SOCK_RAW { // Allow both IP versions even if the OS default // is otherwise. Note that some operating systems // never admit this option. diff --git a/libgo/go/net/sys_cloexec.go b/libgo/go/net/sys_cloexec.go index 898fb7c0c2c..ba266e6534c 100644 --- a/libgo/go/net/sys_cloexec.go +++ b/libgo/go/net/sys_cloexec.go @@ -9,24 +9,27 @@ package net -import "syscall" +import ( + "os" + "syscall" +) // Wrapper around the socket system call that marks the returned file // descriptor as nonblocking and close-on-exec. func sysSocket(family, sotype, proto int) (int, error) { // See ../syscall/exec_unix.go for description of ForkLock. syscall.ForkLock.RLock() - s, err := syscall.Socket(family, sotype, proto) + s, err := socketFunc(family, sotype, proto) if err == nil { syscall.CloseOnExec(s) } syscall.ForkLock.RUnlock() if err != nil { - return -1, err + return -1, os.NewSyscallError("socket", err) } if err = syscall.SetNonblock(s, true); err != nil { - syscall.Close(s) - return -1, err + closeFunc(s) + return -1, os.NewSyscallError("setnonblock", err) } return s, nil } @@ -39,16 +42,16 @@ func accept(s int) (int, syscall.Sockaddr, error) { // because we have put fd.sysfd into non-blocking mode. // However, a call to the File method will put it back into // blocking mode. We can't take that risk, so no use of ForkLock here. - ns, sa, err := syscall.Accept(s) + ns, sa, err := acceptFunc(s) if err == nil { syscall.CloseOnExec(ns) } if err != nil { - return -1, nil, err + return -1, nil, os.NewSyscallError("accept", err) } if err = syscall.SetNonblock(ns, true); err != nil { - syscall.Close(ns) - return -1, nil, err + closeFunc(ns) + return -1, nil, os.NewSyscallError("setnonblock", err) } return ns, sa, nil } diff --git a/libgo/go/net/tcp_test.go b/libgo/go/net/tcp_test.go index c04198ea000..25ae9b9d771 100644 --- a/libgo/go/net/tcp_test.go +++ b/libgo/go/net/tcp_test.go @@ -5,7 +5,6 @@ package net import ( - "fmt" "io" "reflect" "runtime" @@ -59,6 +58,8 @@ func BenchmarkTCP6PersistentTimeout(b *testing.B) { } func benchmarkTCP(b *testing.B, persistent, timeout bool, laddr string) { + testHookUninstaller.Do(uninstallTestHooks) + const msgLen = 512 conns := b.N numConcurrent := runtime.GOMAXPROCS(-1) * 2 @@ -76,7 +77,7 @@ func benchmarkTCP(b *testing.B, persistent, timeout bool, laddr string) { sendMsg := func(c Conn, buf []byte) bool { n, err := c.Write(buf) if n != len(buf) || err != nil { - b.Logf("Write failed: %v", err) + b.Log(err) return false } return true @@ -86,7 +87,7 @@ func benchmarkTCP(b *testing.B, persistent, timeout bool, laddr string) { n, err := c.Read(buf) read += n if err != nil { - b.Logf("Read failed: %v", err) + b.Log(err) return false } } @@ -94,7 +95,7 @@ func benchmarkTCP(b *testing.B, persistent, timeout bool, laddr string) { } ln, err := Listen("tcp", laddr) if err != nil { - b.Fatalf("Listen failed: %v", err) + b.Fatal(err) } defer ln.Close() serverSem := make(chan bool, numConcurrent) @@ -134,7 +135,7 @@ func benchmarkTCP(b *testing.B, persistent, timeout bool, laddr string) { }() c, err := Dial("tcp", ln.Addr().String()) if err != nil { - b.Logf("Dial failed: %v", err) + b.Log(err) return } defer c.Close() @@ -167,6 +168,8 @@ func BenchmarkTCP6ConcurrentReadWrite(b *testing.B) { } func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) { + testHookUninstaller.Do(uninstallTestHooks) + // The benchmark creates GOMAXPROCS client/server pairs. // Each pair creates 4 goroutines: client reader/writer and server reader/writer. // The benchmark stresses concurrent reading and writing to the same connection. @@ -183,7 +186,7 @@ func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) { servers := make([]Conn, P) ln, err := Listen("tcp", laddr) if err != nil { - b.Fatalf("Listen failed: %v", err) + b.Fatal(err) } defer ln.Close() done := make(chan bool) @@ -191,7 +194,7 @@ func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) { for p := 0; p < P; p++ { s, err := ln.Accept() if err != nil { - b.Errorf("Accept failed: %v", err) + b.Error(err) return } servers[p] = s @@ -201,7 +204,7 @@ func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) { for p := 0; p < P; p++ { c, err := Dial("tcp", ln.Addr().String()) if err != nil { - b.Fatalf("Dial failed: %v", err) + b.Fatal(err) } clients[p] = c } @@ -224,7 +227,7 @@ func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) { buf[0] = v _, err := c.Write(buf[:]) if err != nil { - b.Errorf("Write failed: %v", err) + b.Error(err) return } } @@ -240,7 +243,7 @@ func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) { for i := 0; i < N; i++ { _, err := s.Read(buf[:]) if err != nil { - b.Errorf("Read failed: %v", err) + b.Error(err) return } pipe <- buf[0] @@ -259,7 +262,7 @@ func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) { buf[0] = v _, err := s.Write(buf[:]) if err != nil { - b.Errorf("Write failed: %v", err) + b.Error(err) return } } @@ -273,7 +276,7 @@ func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) { for i := 0; i < N; i++ { _, err := c.Read(buf[:]) if err != nil { - b.Errorf("Read failed: %v", err) + b.Error(err) return } } @@ -284,7 +287,7 @@ func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) { } type resolveTCPAddrTest struct { - net string + network string litAddrOrName string addr *TCPAddr err error @@ -294,8 +297,8 @@ var resolveTCPAddrTests = []resolveTCPAddrTest{ {"tcp", "127.0.0.1:0", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 0}, nil}, {"tcp4", "127.0.0.1:65535", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 65535}, nil}, - {"tcp", "[::1]:1", &TCPAddr{IP: ParseIP("::1"), Port: 1}, nil}, - {"tcp6", "[::1]:65534", &TCPAddr{IP: ParseIP("::1"), Port: 65534}, nil}, + {"tcp", "[::1]:0", &TCPAddr{IP: ParseIP("::1"), Port: 0}, nil}, + {"tcp6", "[::1]:65535", &TCPAddr{IP: ParseIP("::1"), Port: 65535}, nil}, {"tcp", "[::1%en0]:1", &TCPAddr{IP: ParseIP("::1"), Port: 1, Zone: "en0"}, nil}, {"tcp6", "[::1%911]:2", &TCPAddr{IP: ParseIP("::1"), Port: 2, Zone: "911"}, nil}, @@ -308,41 +311,26 @@ var resolveTCPAddrTests = []resolveTCPAddrTest{ {"http", "127.0.0.1:0", nil, UnknownNetworkError("http")}, } -func init() { - if ifi := loopbackInterface(); ifi != nil { - index := fmt.Sprintf("%v", ifi.Index) - resolveTCPAddrTests = append(resolveTCPAddrTests, []resolveTCPAddrTest{ - {"tcp6", "[fe80::1%" + ifi.Name + "]:3", &TCPAddr{IP: ParseIP("fe80::1"), Port: 3, Zone: zoneToString(ifi.Index)}, nil}, - {"tcp6", "[fe80::1%" + index + "]:4", &TCPAddr{IP: ParseIP("fe80::1"), Port: 4, Zone: index}, nil}, - }...) - } - if ips, err := LookupIP("localhost"); err == nil && len(ips) > 1 && supportsIPv4 && supportsIPv6 { - resolveTCPAddrTests = append(resolveTCPAddrTests, []resolveTCPAddrTest{ - {"tcp", "localhost:5", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5}, nil}, - {"tcp4", "localhost:6", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 6}, nil}, - {"tcp6", "localhost:7", &TCPAddr{IP: IPv6loopback, Port: 7}, nil}, - }...) - } -} - func TestResolveTCPAddr(t *testing.T) { - for _, tt := range resolveTCPAddrTests { - addr, err := ResolveTCPAddr(tt.net, tt.litAddrOrName) + origTestHookLookupIP := testHookLookupIP + defer func() { testHookLookupIP = origTestHookLookupIP }() + testHookLookupIP = lookupLocalhost + + for i, tt := range resolveTCPAddrTests { + addr, err := ResolveTCPAddr(tt.network, tt.litAddrOrName) if err != tt.err { - t.Fatalf("ResolveTCPAddr(%q, %q) failed: %v", tt.net, tt.litAddrOrName, err) + t.Errorf("#%d: %v", i, err) + } else if !reflect.DeepEqual(addr, tt.addr) { + t.Errorf("#%d: got %#v; want %#v", i, addr, tt.addr) } - if !reflect.DeepEqual(addr, tt.addr) { - t.Fatalf("ResolveTCPAddr(%q, %q) = %#v, want %#v", tt.net, tt.litAddrOrName, addr, tt.addr) + if err != nil { + continue } - if err == nil { - str := addr.String() - addr1, err := ResolveTCPAddr(tt.net, str) - if err != nil { - t.Fatalf("ResolveTCPAddr(%q, %q) [from %q]: %v", tt.net, str, tt.litAddrOrName, err) - } - if !reflect.DeepEqual(addr1, addr) { - t.Fatalf("ResolveTCPAddr(%q, %q) [from %q] = %#v, want %#v", tt.net, str, tt.litAddrOrName, addr1, addr) - } + rtaddr, err := ResolveTCPAddr(addr.Network(), addr.String()) + if err != nil { + t.Errorf("#%d: %v", i, err) + } else if !reflect.DeepEqual(rtaddr, addr) { + t.Errorf("#%d: got %#v; want %#v", i, rtaddr, addr) } } } @@ -358,13 +346,13 @@ var tcpListenerNameTests = []struct { func TestTCPListenerName(t *testing.T) { if testing.Short() || !*testExternal { - t.Skip("skipping test to avoid external network") + t.Skip("avoid external network") } for _, tt := range tcpListenerNameTests { ln, err := ListenTCP(tt.net, tt.laddr) if err != nil { - t.Fatalf("ListenTCP failed: %v", err) + t.Fatal(err) } defer ln.Close() la := ln.Addr() @@ -376,59 +364,37 @@ func TestTCPListenerName(t *testing.T) { func TestIPv6LinkLocalUnicastTCP(t *testing.T) { if testing.Short() || !*testExternal { - t.Skip("skipping test to avoid external network") + t.Skip("avoid external network") } if !supportsIPv6 { - t.Skip("ipv6 is not supported") - } - ifi := loopbackInterface() - if ifi == nil { - t.Skip("loopback interface not found") - } - laddr := ipv6LinkLocalUnicastAddr(ifi) - if laddr == "" { - t.Skip("ipv6 unicast address on loopback not found") + t.Skip("IPv6 is not supported") } - type test struct { - net, addr string - nameLookup bool - } - var tests = []test{ - {"tcp", "[" + laddr + "%" + ifi.Name + "]:0", false}, - {"tcp6", "[" + laddr + "%" + ifi.Name + "]:0", false}, - } - switch runtime.GOOS { - case "darwin", "freebsd", "openbsd", "netbsd": - tests = append(tests, []test{ - {"tcp", "[localhost%" + ifi.Name + "]:0", true}, - {"tcp6", "[localhost%" + ifi.Name + "]:0", true}, - }...) - case "linux": - tests = append(tests, []test{ - {"tcp", "[ip6-localhost%" + ifi.Name + "]:0", true}, - {"tcp6", "[ip6-localhost%" + ifi.Name + "]:0", true}, - }...) - } - for _, tt := range tests { - ln, err := Listen(tt.net, tt.addr) + for i, tt := range ipv6LinkLocalUnicastTCPTests { + ln, err := Listen(tt.network, tt.address) if err != nil { // It might return "LookupHost returned no // suitable address" error on some platforms. - t.Logf("Listen failed: %v", err) + t.Log(err) continue } - defer ln.Close() + ls, err := (&streamListener{Listener: ln}).newLocalServer() + if err != nil { + t.Fatal(err) + } + defer ls.teardown() + ch := make(chan error, 1) + handler := func(ls *localServer, ln Listener) { transponder(ln, ch) } + if err := ls.buildup(handler); err != nil { + t.Fatal(err) + } if la, ok := ln.Addr().(*TCPAddr); !ok || !tt.nameLookup && la.Zone == "" { t.Fatalf("got %v; expected a proper address with zone identifier", la) } - done := make(chan int) - go transponder(t, ln, done) - - c, err := Dial(tt.net, ln.Addr().String()) + c, err := Dial(tt.network, ls.Listener.Addr().String()) if err != nil { - t.Fatalf("Dial failed: %v", err) + t.Fatal(err) } defer c.Close() if la, ok := c.LocalAddr().(*TCPAddr); !ok || !tt.nameLookup && la.Zone == "" { @@ -439,14 +405,16 @@ func TestIPv6LinkLocalUnicastTCP(t *testing.T) { } if _, err := c.Write([]byte("TCP OVER IPV6 LINKLOCAL TEST")); err != nil { - t.Fatalf("Conn.Write failed: %v", err) + t.Fatal(err) } b := make([]byte, 32) if _, err := c.Read(b); err != nil { - t.Fatalf("Conn.Read failed: %v", err) + t.Fatal(err) } - <-done + for err := range ch { + t.Errorf("#%d: %v", i, err) + } } } @@ -454,7 +422,7 @@ func TestTCPConcurrentAccept(t *testing.T) { defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4)) ln, err := Listen("tcp", "127.0.0.1:0") if err != nil { - t.Fatalf("Listen failed: %v", err) + t.Fatal(err) } const N = 10 var wg sync.WaitGroup @@ -492,13 +460,20 @@ func TestTCPConcurrentAccept(t *testing.T) { } } -func TestTCPReadWriteMallocs(t *testing.T) { - if testing.Short() { - t.Skip("skipping malloc count in short mode") +func TestTCPReadWriteAllocs(t *testing.T) { + t.Skip("skipping test on gccgo until escape analysis is turned on") + switch runtime.GOOS { + case "nacl", "windows": + // NaCl needs to allocate pseudo file descriptor + // stuff. See syscall/fd_nacl.go. + // Windows uses closures and channels for IO + // completion port-based netpoll. See fd_windows.go. + t.Skipf("not supported on %s", runtime.GOOS) } + ln, err := Listen("tcp", "127.0.0.1:0") if err != nil { - t.Fatalf("Listen failed: %v", err) + t.Fatal(err) } defer ln.Close() var server Conn @@ -510,25 +485,26 @@ func TestTCPReadWriteMallocs(t *testing.T) { }() client, err := Dial("tcp", ln.Addr().String()) if err != nil { - t.Fatalf("Dial failed: %v", err) + t.Fatal(err) } + defer client.Close() if err := <-errc; err != nil { - t.Fatalf("Accept failed: %v", err) + t.Fatal(err) } defer server.Close() var buf [128]byte - mallocs := testing.AllocsPerRun(1000, func() { + allocs := testing.AllocsPerRun(1000, func() { _, err := server.Write(buf[:]) if err != nil { - t.Fatalf("Write failed: %v", err) + t.Fatal(err) } _, err = io.ReadFull(client, buf[:]) if err != nil { - t.Fatalf("Read failed: %v", err) + t.Fatal(err) } }) - if mallocs > 0 { - t.Fatalf("Got %v allocs, want 0", mallocs) + if allocs > 0 { + t.Fatalf("got %v; want 0", allocs) } } @@ -543,7 +519,7 @@ func TestTCPStress(t *testing.T) { sendMsg := func(c Conn, buf []byte) bool { n, err := c.Write(buf) if n != len(buf) || err != nil { - t.Logf("Write failed: %v", err) + t.Log(err) return false } return true @@ -553,7 +529,7 @@ func TestTCPStress(t *testing.T) { n, err := c.Read(buf) read += n if err != nil { - t.Logf("Read failed: %v", err) + t.Log(err) return false } } @@ -562,7 +538,7 @@ func TestTCPStress(t *testing.T) { ln, err := Listen("tcp", "127.0.0.1:0") if err != nil { - t.Fatalf("Listen failed: %v", err) + t.Fatal(err) } defer ln.Close() // Acceptor. @@ -593,7 +569,7 @@ func TestTCPStress(t *testing.T) { }() c, err := Dial("tcp", ln.Addr().String()) if err != nil { - t.Logf("Dial failed: %v", err) + t.Log(err) return } defer c.Close() diff --git a/libgo/go/net/tcpsock.go b/libgo/go/net/tcpsock.go index f3dfbd23d34..8765affd462 100644 --- a/libgo/go/net/tcpsock.go +++ b/libgo/go/net/tcpsock.go @@ -25,7 +25,14 @@ func (a *TCPAddr) String() string { return JoinHostPort(ip, itoa(a.Port)) } -func (a *TCPAddr) toAddr() Addr { +func (a *TCPAddr) isWildcard() bool { + if a == nil || a.IP == nil { + return true + } + return a.IP.IsUnspecified() +} + +func (a *TCPAddr) opAddr() Addr { if a == nil { return nil } @@ -46,9 +53,9 @@ func ResolveTCPAddr(net, addr string) (*TCPAddr, error) { default: return nil, UnknownNetworkError(net) } - a, err := resolveInternetAddr(net, addr, noDeadline) + addrs, err := internetAddrList(net, addr, noDeadline) if err != nil { return nil, err } - return a.toAddr().(*TCPAddr), nil + return addrs.first(isIPv4).(*TCPAddr), nil } diff --git a/libgo/go/net/tcpsock_plan9.go b/libgo/go/net/tcpsock_plan9.go index 52019d7b4eb..9f23703abb4 100644 --- a/libgo/go/net/tcpsock_plan9.go +++ b/libgo/go/net/tcpsock_plan9.go @@ -23,7 +23,11 @@ func newTCPConn(fd *netFD) *TCPConn { // ReadFrom implements the io.ReaderFrom ReadFrom method. func (c *TCPConn) ReadFrom(r io.Reader) (int64, error) { - return genericReadFrom(c, r) + n, err := genericReadFrom(c, r) + if err != nil && err != io.EOF { + err = &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + return n, err } // CloseRead shuts down the reading side of the TCP connection. @@ -32,7 +36,11 @@ func (c *TCPConn) CloseRead() error { if !c.ok() { return syscall.EINVAL } - return c.fd.closeRead() + err := c.fd.closeRead() + if err != nil { + err = &OpError{Op: "close", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + return err } // CloseWrite shuts down the writing side of the TCP connection. @@ -41,7 +49,11 @@ func (c *TCPConn) CloseWrite() error { if !c.ok() { return syscall.EINVAL } - return c.fd.closeWrite() + err := c.fd.closeWrite() + if err != nil { + err = &OpError{Op: "close", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + return err } // SetLinger sets the behavior of Close on a connection which still @@ -57,7 +69,7 @@ func (c *TCPConn) CloseWrite() error { // some operating systems after sec seconds have elapsed any remaining // unsent data may be discarded. func (c *TCPConn) SetLinger(sec int) error { - return syscall.EPLAN9 + return &OpError{Op: "set", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9} } // SetKeepAlive sets whether the operating system should send @@ -66,7 +78,10 @@ func (c *TCPConn) SetKeepAlive(keepalive bool) error { if !c.ok() { return syscall.EPLAN9 } - return setKeepAlive(c.fd, keepalive) + if err := setKeepAlive(c.fd, keepalive); err != nil { + return &OpError{Op: "set", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + return nil } // SetKeepAlivePeriod sets period between keep alives. @@ -74,7 +89,10 @@ func (c *TCPConn) SetKeepAlivePeriod(d time.Duration) error { if !c.ok() { return syscall.EPLAN9 } - return setKeepAlivePeriod(c.fd, d) + if err := setKeepAlivePeriod(c.fd, d); err != nil { + return &OpError{Op: "set", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + return nil } // SetNoDelay controls whether the operating system should delay @@ -82,7 +100,7 @@ func (c *TCPConn) SetKeepAlivePeriod(d time.Duration) error { // algorithm). The default is true (no delay), meaning that data is // sent as soon as possible after a Write. func (c *TCPConn) SetNoDelay(noDelay bool) error { - return syscall.EPLAN9 + return &OpError{Op: "set", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9} } // DialTCP connects to the remote address raddr on the network net, @@ -99,10 +117,10 @@ func dialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time) (*TCPConn, e switch net { case "tcp", "tcp4", "tcp6": default: - return nil, &OpError{"dial", net, raddr, UnknownNetworkError(net)} + return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(net)} } if raddr == nil { - return nil, &OpError{"dial", net, nil, errMissingAddress} + return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: nil, Err: errMissingAddress} } fd, err := dialPlan9(net, laddr, raddr) if err != nil { @@ -151,12 +169,18 @@ func (l *TCPListener) Close() error { } if _, err := l.fd.ctl.WriteString("hangup"); err != nil { l.fd.ctl.Close() - return &OpError{"close", l.fd.ctl.Name(), l.fd.laddr, err} + return &OpError{Op: "close", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: err} } - return l.fd.ctl.Close() + err := l.fd.ctl.Close() + if err != nil { + err = &OpError{Op: "close", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: err} + } + return err } // Addr returns the listener's network address, a *TCPAddr. +// The Addr returned is shared by all invocations of Addr, so +// do not modify it. func (l *TCPListener) Addr() Addr { return l.fd.laddr } // SetDeadline sets the deadline associated with the listener. @@ -165,7 +189,10 @@ func (l *TCPListener) SetDeadline(t time.Time) error { if l == nil || l.fd == nil || l.fd.ctl == nil { return syscall.EINVAL } - return l.fd.setDeadline(t) + if err := l.fd.setDeadline(t); err != nil { + return &OpError{Op: "set", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: err} + } + return nil } // File returns a copy of the underlying os.File, set to blocking @@ -175,7 +202,13 @@ func (l *TCPListener) SetDeadline(t time.Time) error { // The returned os.File's file descriptor is different from the // connection's. Attempting to change properties of the original // using this duplicate may or may not have the desired effect. -func (l *TCPListener) File() (f *os.File, err error) { return l.dup() } +func (l *TCPListener) File() (f *os.File, err error) { + f, err = l.dup() + if err != nil { + err = &OpError{Op: "file", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: err} + } + return +} // ListenTCP announces on the TCP address laddr and returns a TCP // listener. Net must be "tcp", "tcp4", or "tcp6". If laddr has a @@ -185,7 +218,7 @@ func ListenTCP(net string, laddr *TCPAddr) (*TCPListener, error) { switch net { case "tcp", "tcp4", "tcp6": default: - return nil, &OpError{"listen", net, laddr, UnknownNetworkError(net)} + return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(net)} } if laddr == nil { laddr = &TCPAddr{} diff --git a/libgo/go/net/tcpsock_posix.go b/libgo/go/net/tcpsock_posix.go index dd78aefa773..7e49b769e1c 100644 --- a/libgo/go/net/tcpsock_posix.go +++ b/libgo/go/net/tcpsock_posix.go @@ -13,11 +13,6 @@ import ( "time" ) -// BUG(rsc): On OpenBSD, listening on the "tcp" network does not listen for -// both IPv4 and IPv6 connections. This is due to the fact that IPv4 traffic -// will not be routed to an IPv6 socket - two separate sockets are required -// if both AFs are to be supported. See inet6(4) on OpenBSD for details. - func sockaddrToTCP(sa syscall.Sockaddr) Addr { switch sa := sa.(type) { case *syscall.SockaddrInet4: @@ -38,13 +33,6 @@ 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) { if a == nil { return nil, nil @@ -60,16 +48,23 @@ type TCPConn struct { func newTCPConn(fd *netFD) *TCPConn { c := &TCPConn{conn{fd}} - c.SetNoDelay(true) + setNoDelay(c.fd, true) return c } // ReadFrom implements the io.ReaderFrom ReadFrom method. func (c *TCPConn) ReadFrom(r io.Reader) (int64, error) { if n, err, handled := sendFile(c.fd, r); handled { + if err != nil && err != io.EOF { + err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } return n, err } - return genericReadFrom(c, r) + n, err := genericReadFrom(c, r) + if err != nil && err != io.EOF { + err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + return n, err } // CloseRead shuts down the reading side of the TCP connection. @@ -78,7 +73,11 @@ func (c *TCPConn) CloseRead() error { if !c.ok() { return syscall.EINVAL } - return c.fd.closeRead() + err := c.fd.closeRead() + if err != nil { + err = &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + return err } // CloseWrite shuts down the writing side of the TCP connection. @@ -87,7 +86,11 @@ func (c *TCPConn) CloseWrite() error { if !c.ok() { return syscall.EINVAL } - return c.fd.closeWrite() + err := c.fd.closeWrite() + if err != nil { + err = &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + return err } // SetLinger sets the behavior of Close on a connection which still @@ -106,7 +109,10 @@ func (c *TCPConn) SetLinger(sec int) error { if !c.ok() { return syscall.EINVAL } - return setLinger(c.fd, sec) + if err := setLinger(c.fd, sec); err != nil { + return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + return nil } // SetKeepAlive sets whether the operating system should send @@ -115,7 +121,10 @@ func (c *TCPConn) SetKeepAlive(keepalive bool) error { if !c.ok() { return syscall.EINVAL } - return setKeepAlive(c.fd, keepalive) + if err := setKeepAlive(c.fd, keepalive); err != nil { + return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + return nil } // SetKeepAlivePeriod sets period between keep alives. @@ -123,7 +132,10 @@ func (c *TCPConn) SetKeepAlivePeriod(d time.Duration) error { if !c.ok() { return syscall.EINVAL } - return setKeepAlivePeriod(c.fd, d) + if err := setKeepAlivePeriod(c.fd, d); err != nil { + return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + return nil } // SetNoDelay controls whether the operating system should delay @@ -134,7 +146,10 @@ func (c *TCPConn) SetNoDelay(noDelay bool) error { if !c.ok() { return syscall.EINVAL } - return setNoDelay(c.fd, noDelay) + if err := setNoDelay(c.fd, noDelay); err != nil { + return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + return nil } // DialTCP connects to the remote address raddr on the network net, @@ -144,10 +159,10 @@ func DialTCP(net string, laddr, raddr *TCPAddr) (*TCPConn, error) { switch net { case "tcp", "tcp4", "tcp6": default: - return nil, &OpError{Op: "dial", Net: net, Addr: raddr, Err: UnknownNetworkError(net)} + return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(net)} } if raddr == nil { - return nil, &OpError{Op: "dial", Net: net, Addr: nil, Err: errMissingAddress} + return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: nil, Err: errMissingAddress} } return dialTCP(net, laddr, raddr, noDeadline) } @@ -170,7 +185,7 @@ func dialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time) (*TCPConn, e // see this happen, rather than expose the buggy effect to users, we // close the fd and try again. If it happens twice more, we relent and // use the result. See also: - // http://golang.org/issue/2690 + // https://golang.org/issue/2690 // http://stackoverflow.com/questions/4949858/ // // The opposite can also happen: if we ask the kernel to pick an appropriate @@ -187,7 +202,7 @@ func dialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time) (*TCPConn, e } if err != nil { - return nil, &OpError{Op: "dial", Net: net, Addr: raddr, Err: err} + return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err} } return newTCPConn(fd), nil } @@ -215,8 +230,13 @@ func selfConnect(fd *netFD, err error) bool { } func spuriousENOTAVAIL(err error) bool { - e, ok := err.(*OpError) - return ok && e.Err == syscall.EADDRNOTAVAIL + if op, ok := err.(*OpError); ok { + err = op.Err + } + if sys, ok := err.(*os.SyscallError); ok { + err = sys.Err + } + return err == syscall.EADDRNOTAVAIL } // TCPListener is a TCP network listener. Clients should typically @@ -233,7 +253,7 @@ func (l *TCPListener) AcceptTCP() (*TCPConn, error) { } fd, err := l.fd.accept() if err != nil { - return nil, err + return nil, &OpError{Op: "accept", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err} } return newTCPConn(fd), nil } @@ -254,10 +274,16 @@ func (l *TCPListener) Close() error { if l == nil || l.fd == nil { return syscall.EINVAL } - return l.fd.Close() + err := l.fd.Close() + if err != nil { + err = &OpError{Op: "close", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err} + } + return err } // Addr returns the listener's network address, a *TCPAddr. +// The Addr returned is shared by all invocations of Addr, so +// do not modify it. func (l *TCPListener) Addr() Addr { return l.fd.laddr } // SetDeadline sets the deadline associated with the listener. @@ -266,7 +292,10 @@ func (l *TCPListener) SetDeadline(t time.Time) error { if l == nil || l.fd == nil { return syscall.EINVAL } - return l.fd.setDeadline(t) + if err := l.fd.setDeadline(t); err != nil { + return &OpError{Op: "set", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err} + } + return nil } // File returns a copy of the underlying os.File, set to blocking @@ -276,7 +305,13 @@ func (l *TCPListener) SetDeadline(t time.Time) error { // The returned os.File's file descriptor is different from the // connection's. Attempting to change properties of the original // using this duplicate may or may not have the desired effect. -func (l *TCPListener) File() (f *os.File, err error) { return l.fd.dup() } +func (l *TCPListener) File() (f *os.File, err error) { + f, err = l.fd.dup() + if err != nil { + err = &OpError{Op: "file", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err} + } + return +} // ListenTCP announces on the TCP address laddr and returns a TCP // listener. Net must be "tcp", "tcp4", or "tcp6". If laddr has a @@ -286,14 +321,14 @@ func ListenTCP(net string, laddr *TCPAddr) (*TCPListener, error) { switch net { case "tcp", "tcp4", "tcp6": default: - return nil, &OpError{Op: "listen", Net: net, Addr: laddr, Err: UnknownNetworkError(net)} + return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(net)} } if laddr == nil { laddr = &TCPAddr{} } fd, err := internetSocket(net, laddr, nil, noDeadline, syscall.SOCK_STREAM, 0, "listen") if err != nil { - return nil, &OpError{Op: "listen", Net: net, Addr: laddr, Err: err} + return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err} } return &TCPListener{fd}, nil } diff --git a/libgo/go/net/tcpsockopt_plan9.go b/libgo/go/net/tcpsockopt_plan9.go index 0e7a6647caf..9abe186cecb 100644 --- a/libgo/go/net/tcpsockopt_plan9.go +++ b/libgo/go/net/tcpsockopt_plan9.go @@ -7,12 +7,13 @@ package net import ( + "strconv" "time" ) // Set keep alive period. func setKeepAlivePeriod(fd *netFD, d time.Duration) error { - cmd := "keepalive " + string(int64(d/time.Millisecond)) + cmd := "keepalive " + strconv.Itoa(int(d/time.Millisecond)) _, e := fd.ctl.WriteAt([]byte(cmd), 0) return e } diff --git a/libgo/go/net/tcpsockopt_solaris.go b/libgo/go/net/tcpsockopt_solaris.go index eaab6b6787b..31f5df0526f 100644 --- a/libgo/go/net/tcpsockopt_solaris.go +++ b/libgo/go/net/tcpsockopt_solaris.go @@ -1,9 +1,7 @@ -// Copyright 2013 The Go Authors. All rights reserved. +// Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// TCP socket options for solaris - package net import ( @@ -12,16 +10,26 @@ import ( "time" ) -// Set keep alive period. func setKeepAlivePeriod(fd *netFD, d time.Duration) error { if err := fd.incref(); err != nil { return err } defer fd.decref() + // The kernel expects milliseconds so round to next highest + // millisecond. + d += (time.Millisecond - time.Nanosecond) + msecs := int(d / time.Millisecond) - // The kernel expects seconds so round to next highest second. - d += (time.Second - time.Nanosecond) - secs := int(d.Seconds()) + // Normally we'd do + // syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, secs) + // here, but we can't because Solaris does not have TCP_KEEPINTVL. + // Solaris has TCP_KEEPALIVE_ABORT_THRESHOLD, but it's not the same + // thing, it refers to the total time until aborting (not between + // probes), and it uses an exponential backoff algorithm instead of + // waiting the same time between probes. We can't hope for the best + // and do it anyway, like on Darwin, because Solaris might eventually + // allocate a constant with a different meaning for the value of + // TCP_KEEPINTVL on illumos. - return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.SO_KEEPALIVE, secs)) + return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_KEEPALIVE_THRESHOLD, msecs)) } diff --git a/libgo/go/net/tcpsockopt_unix.go b/libgo/go/net/tcpsockopt_unix.go index c9f604cad7b..c8970d1b574 100644 --- a/libgo/go/net/tcpsockopt_unix.go +++ b/libgo/go/net/tcpsockopt_unix.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build freebsd linux netbsd solaris +// +build freebsd linux netbsd package net diff --git a/libgo/go/net/tcpsockopt_windows.go b/libgo/go/net/tcpsockopt_windows.go index 091f5233f20..ae2d7c8f182 100644 --- a/libgo/go/net/tcpsockopt_windows.go +++ b/libgo/go/net/tcpsockopt_windows.go @@ -28,5 +28,5 @@ func setKeepAlivePeriod(fd *netFD, d time.Duration) error { ret := uint32(0) size := uint32(unsafe.Sizeof(ka)) err := syscall.WSAIoctl(fd.sysfd, syscall.SIO_KEEPALIVE_VALS, (*byte)(unsafe.Pointer(&ka)), size, nil, 0, &ret, nil, 0) - return os.NewSyscallError("WSAIoctl", err) + return os.NewSyscallError("wsaioctl", err) } diff --git a/libgo/go/net/testdata/hosts_singleline b/libgo/go/net/testdata/hosts_singleline deleted file mode 100644 index 5f5f74a3fad..00000000000 --- a/libgo/go/net/testdata/hosts_singleline +++ /dev/null @@ -1 +0,0 @@ -127.0.0.2 odin \ No newline at end of file diff --git a/libgo/go/net/testdata/ipv4-hosts b/libgo/go/net/testdata/ipv4-hosts new file mode 100644 index 00000000000..5208bb44ac8 --- /dev/null +++ b/libgo/go/net/testdata/ipv4-hosts @@ -0,0 +1,12 @@ +# See https://tools.ietf.org/html/rfc1123. +# +# The literal IPv4 address parser in the net package is a relaxed +# one. It may accept a literal IPv4 address in dotted-decimal notation +# with leading zeros such as "001.2.003.4". + +# internet address and host name +127.0.0.1 localhost # inline comment separated by tab +127.000.000.002 localhost # inline comment separated by space + +# internet address, host name and aliases +127.000.000.003 localhost localhost.localdomain diff --git a/libgo/go/net/testdata/ipv6-hosts b/libgo/go/net/testdata/ipv6-hosts new file mode 100644 index 00000000000..f78b7fcf19e --- /dev/null +++ b/libgo/go/net/testdata/ipv6-hosts @@ -0,0 +1,11 @@ +# See https://tools.ietf.org/html/rfc5952, https://tools.ietf.org/html/rfc4007. + +# internet address and host name +::1 localhost # inline comment separated by tab +fe80:0000:0000:0000:0000:0000:0000:0001 localhost # inline comment separated by space + +# internet address with zone identifier and host name +fe80:0000:0000:0000:0000:0000:0000:0002%lo0 localhost + +# internet address, host name and aliases +fe80::3%lo0 localhost localhost.localdomain diff --git a/libgo/go/net/testdata/openbsd-resolv.conf b/libgo/go/net/testdata/openbsd-resolv.conf new file mode 100644 index 00000000000..8281a91b4a2 --- /dev/null +++ b/libgo/go/net/testdata/openbsd-resolv.conf @@ -0,0 +1,5 @@ +# Generated by vio0 dhclient +search c.symbolic-datum-552.internal. +nameserver 169.254.169.254 +nameserver 10.240.0.1 +lookup file bind diff --git a/libgo/go/net/testdata/singleline-hosts b/libgo/go/net/testdata/singleline-hosts new file mode 100644 index 00000000000..5f5f74a3fad --- /dev/null +++ b/libgo/go/net/testdata/singleline-hosts @@ -0,0 +1 @@ +127.0.0.2 odin \ No newline at end of file diff --git a/libgo/go/net/textproto/reader.go b/libgo/go/net/textproto/reader.go index eea9207f252..91303fec612 100644 --- a/libgo/go/net/textproto/reader.go +++ b/libgo/go/net/textproto/reader.go @@ -13,10 +13,6 @@ import ( "strings" ) -// BUG(rsc): To let callers manage exposure to denial of service -// attacks, Reader should allow them to set and reset a limit on -// the number of bytes read from the connection. - // A Reader implements convenience methods for reading requests // or responses from a text protocol network connection. type Reader struct { @@ -26,6 +22,10 @@ type Reader struct { } // NewReader returns a new Reader reading from r. +// +// To avoid denial of service attacks, the provided bufio.Reader +// should be reading from an io.LimitReader or similar Reader to bound +// the size of responses. func NewReader(r *bufio.Reader) *Reader { return &Reader{R: r} } @@ -485,6 +485,13 @@ func (r *Reader) ReadMIMEHeader() (MIMEHeader, error) { } key := canonicalMIMEHeaderKey(kv[:endKey]) + // As per RFC 7230 field-name is a token, tokens consist of one or more chars. + // We could return a ProtocolError here, but better to be liberal in what we + // accept, so if we get an empty key, skip it. + if key == "" { + continue + } + // Skip initial spaces in value. i++ // skip colon for i < len(kv) && (kv[i] == ' ' || kv[i] == '\t') { @@ -540,11 +547,16 @@ func (r *Reader) upcomingHeaderNewlines() (n int) { // the rest are converted to lowercase. For example, the // canonical key for "accept-encoding" is "Accept-Encoding". // MIME header keys are assumed to be ASCII only. +// If s contains a space or invalid header field bytes, it is +// returned without modifications. func CanonicalMIMEHeaderKey(s string) string { // Quick check for canonical encoding. upper := true for i := 0; i < len(s); i++ { c := s[i] + if !validHeaderFieldByte(c) { + return s + } if upper && 'a' <= c && c <= 'z' { return canonicalMIMEHeaderKey([]byte(s)) } @@ -558,19 +570,44 @@ func CanonicalMIMEHeaderKey(s string) string { const toLower = 'a' - 'A' +// validHeaderFieldByte reports whether b is a valid byte in a header +// field key. This is actually stricter than RFC 7230, which says: +// tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." / +// "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA +// token = 1*tchar +// TODO: revisit in Go 1.6+ and possibly expand this. But note that many +// servers have historically dropped '_' to prevent ambiguities when mapping +// to CGI environment variables. +func validHeaderFieldByte(b byte) bool { + return ('A' <= b && b <= 'Z') || + ('a' <= b && b <= 'z') || + ('0' <= b && b <= '9') || + b == '-' +} + // canonicalMIMEHeaderKey is like CanonicalMIMEHeaderKey but is // allowed to mutate the provided byte slice before returning the // string. +// +// For invalid inputs (if a contains spaces or non-token bytes), a +// is unchanged and a string copy is returned. func canonicalMIMEHeaderKey(a []byte) string { + // See if a looks like a header key. If not, return it unchanged. + for _, c := range a { + if validHeaderFieldByte(c) { + continue + } + // Don't canonicalize. + return string(a) + } + upper := true for i, c := range a { // Canonicalize: first letter upper case // and upper case after each dash. // (Host, User-Agent, If-Modified-Since). // MIME headers are ASCII only, so no Unicode issues. - if c == ' ' { - c = '-' - } else if upper && 'a' <= c && c <= 'z' { + if upper && 'a' <= c && c <= 'z' { c -= toLower } else if !upper && 'A' <= c && c <= 'Z' { c += toLower diff --git a/libgo/go/net/textproto/reader_test.go b/libgo/go/net/textproto/reader_test.go index c89566635e1..91550f74934 100644 --- a/libgo/go/net/textproto/reader_test.go +++ b/libgo/go/net/textproto/reader_test.go @@ -24,11 +24,14 @@ var canonicalHeaderKeyTests = []canonicalHeaderKeyTest{ {"uSER-aGENT", "User-Agent"}, {"user-agent", "User-Agent"}, {"USER-AGENT", "User-Agent"}, - {"üser-agenT", "üser-Agent"}, // non-ASCII unchanged + + // Non-ASCII or anything with spaces or non-token chars is unchanged: + {"üser-agenT", "üser-agenT"}, + {"a B", "a B"}, // This caused a panic due to mishandling of a space: - {"C Ontent-Transfer-Encoding", "C-Ontent-Transfer-Encoding"}, - {"foo bar", "Foo-Bar"}, + {"C Ontent-Transfer-Encoding", "C Ontent-Transfer-Encoding"}, + {"foo bar", "foo bar"}, } func TestCanonicalMIMEHeaderKey(t *testing.T) { @@ -153,6 +156,15 @@ func TestReadMIMEHeaderSingle(t *testing.T) { } } +func TestReadMIMEHeaderNoKey(t *testing.T) { + r := reader(": bar\ntest-1: 1\n\n") + m, err := r.ReadMIMEHeader() + want := MIMEHeader{"Test-1": {"1"}} + if !reflect.DeepEqual(m, want) || err != nil { + t.Fatalf("ReadMIMEHeader: %v, %v; want %v", m, err, want) + } +} + func TestLargeReadMIMEHeader(t *testing.T) { data := make([]byte, 16*1024) for i := 0; i < len(data); i++ { @@ -185,7 +197,7 @@ func TestReadMIMEHeaderNonCompliant(t *testing.T) { "Foo": {"bar"}, "Content-Language": {"en"}, "Sid": {"0"}, - "Audio-Mode": {"None"}, + "Audio Mode": {"None"}, "Privilege": {"127"}, } if !reflect.DeepEqual(m, want) || err != nil { diff --git a/libgo/go/net/timeout_test.go b/libgo/go/net/timeout_test.go index 9ef0c4d15cc..ca94e24c816 100644 --- a/libgo/go/net/timeout_test.go +++ b/libgo/go/net/timeout_test.go @@ -8,408 +8,727 @@ import ( "fmt" "io" "io/ioutil" + "net/internal/socktest" "runtime" + "sync" "testing" "time" ) -func isTimeout(err error) bool { - e, ok := err.(Error) - return ok && e.Timeout() +var dialTimeoutTests = []struct { + timeout time.Duration + delta time.Duration // for deadline + + guard time.Duration + max time.Duration +}{ + // Tests that dial timeouts, deadlines in the past work. + {-5 * time.Second, 0, -5 * time.Second, 100 * time.Millisecond}, + {0, -5 * time.Second, -5 * time.Second, 100 * time.Millisecond}, + {-5 * time.Second, 5 * time.Second, -5 * time.Second, 100 * time.Millisecond}, // timeout over deadline + + {50 * time.Millisecond, 0, 100 * time.Millisecond, time.Second}, + {0, 50 * time.Millisecond, 100 * time.Millisecond, time.Second}, + {50 * time.Millisecond, 5 * time.Second, 100 * time.Millisecond, time.Second}, // timeout over deadline } -type copyRes struct { - n int64 - err error - d time.Duration +func TestDialTimeout(t *testing.T) { + origTestHookDialChannel := testHookDialChannel + defer func() { testHookDialChannel = origTestHookDialChannel }() + defer sw.Set(socktest.FilterConnect, nil) + + // Avoid tracking open-close jitterbugs between netFD and + // socket that leads to confusion of information inside + // socktest.Switch. + // It may happen when the Dial call bumps against TCP + // simultaneous open. See selfConnect in tcpsock_posix.go. + defer func() { + sw.Set(socktest.FilterClose, nil) + forceCloseSockets() + }() + sw.Set(socktest.FilterClose, func(so *socktest.Status) (socktest.AfterFilter, error) { + return nil, errTimedout + }) + + for i, tt := range dialTimeoutTests { + switch runtime.GOOS { + case "plan9", "windows": + testHookDialChannel = func() { time.Sleep(tt.guard) } + if runtime.GOOS == "plan9" { + break + } + fallthrough + default: + sw.Set(socktest.FilterConnect, func(so *socktest.Status) (socktest.AfterFilter, error) { + time.Sleep(tt.guard) + return nil, errTimedout + }) + } + + ch := make(chan error) + d := Dialer{Timeout: tt.timeout} + if tt.delta != 0 { + d.Deadline = time.Now().Add(tt.delta) + } + max := time.NewTimer(tt.max) + defer max.Stop() + go func() { + // This dial never starts to send any TCP SYN + // segment because of above socket filter and + // test hook. + c, err := d.Dial("tcp", "127.0.0.1:0") + if err == nil { + err = fmt.Errorf("unexpectedly established: tcp:%s->%s", c.LocalAddr(), c.RemoteAddr()) + c.Close() + } + ch <- err + }() + + select { + case <-max.C: + t.Fatalf("#%d: Dial didn't return in an expected time", i) + case err := <-ch: + if perr := parseDialError(err); perr != nil { + t.Errorf("#%d: %v", i, perr) + } + if nerr, ok := err.(Error); !ok || !nerr.Timeout() { + t.Fatalf("#%d: %v", i, err) + } + } + } +} + +var acceptTimeoutTests = []struct { + timeout time.Duration + xerrs [2]error // expected errors in transition +}{ + // Tests that accept deadlines in the past work, even if + // there's incoming connections available. + {-5 * time.Second, [2]error{errTimeout, errTimeout}}, + + {50 * time.Millisecond, [2]error{nil, errTimeout}}, } func TestAcceptTimeout(t *testing.T) { switch runtime.GOOS { case "plan9": - t.Skipf("skipping test on %q", runtime.GOOS) + t.Skipf("not supported on %s", runtime.GOOS) } - ln := newLocalListener(t).(*TCPListener) - defer ln.Close() - ln.SetDeadline(time.Now().Add(-1 * time.Second)) - if _, err := ln.Accept(); !isTimeout(err) { - t.Fatalf("Accept: expected err %v, got %v", errTimeout, err) + ln, err := newLocalListener("tcp") + if err != nil { + t.Fatal(err) } - if _, err := ln.Accept(); !isTimeout(err) { - t.Fatalf("Accept: expected err %v, got %v", errTimeout, err) + defer ln.Close() + + for i, tt := range acceptTimeoutTests { + if tt.timeout < 0 { + go func() { + c, err := Dial(ln.Addr().Network(), ln.Addr().String()) + if err != nil { + t.Error(err) + return + } + var b [1]byte + c.Read(b[:]) + c.Close() + }() + } + + if err := ln.(*TCPListener).SetDeadline(time.Now().Add(tt.timeout)); err != nil { + t.Fatalf("$%d: %v", i, err) + } + for j, xerr := range tt.xerrs { + for { + c, err := ln.Accept() + if xerr != nil { + if perr := parseAcceptError(err); perr != nil { + t.Errorf("#%d/%d: %v", i, j, perr) + } + if nerr, ok := err.(Error); !ok || !nerr.Timeout() { + t.Fatalf("#%d/%d: %v", i, j, err) + } + } + if err == nil { + c.Close() + time.Sleep(tt.timeout / 3) + continue + } + break + } + } } - ln.SetDeadline(time.Now().Add(100 * time.Millisecond)) - if _, err := ln.Accept(); !isTimeout(err) { - t.Fatalf("Accept: expected err %v, got %v", errTimeout, err) +} + +func TestAcceptTimeoutMustReturn(t *testing.T) { + switch runtime.GOOS { + case "plan9": + t.Skipf("not supported on %s", runtime.GOOS) } - if _, err := ln.Accept(); !isTimeout(err) { - t.Fatalf("Accept: expected err %v, got %v", errTimeout, err) + + ln, err := newLocalListener("tcp") + if err != nil { + t.Fatal(err) } - ln.SetDeadline(noDeadline) - errc := make(chan error) + defer ln.Close() + + max := time.NewTimer(time.Second) + defer max.Stop() + ch := make(chan error) go func() { - _, err := ln.Accept() - errc <- err + if err := ln.(*TCPListener).SetDeadline(noDeadline); err != nil { + t.Error(err) + } + if err := ln.(*TCPListener).SetDeadline(time.Now().Add(10 * time.Millisecond)); err != nil { + t.Error(err) + } + c, err := ln.Accept() + if err == nil { + c.Close() + } + ch <- err }() - time.Sleep(100 * time.Millisecond) + select { - case err := <-errc: - t.Fatalf("Expected Accept() to not return, but it returned with %v\n", err) - default: - } - ln.Close() - switch nerr := <-errc; err := nerr.(type) { - case *OpError: - if err.Err != errClosing { - t.Fatalf("Accept: expected err %v, got %v", errClosing, err) + case <-max.C: + ln.Close() + <-ch // wait for tester goroutine to stop + t.Fatal("Accept didn't return in an expected time") + case err := <-ch: + if perr := parseAcceptError(err); perr != nil { + t.Error(perr) } - default: - if err != errClosing { - t.Fatalf("Accept: expected err %v, got %v", errClosing, err) + if nerr, ok := err.(Error); !ok || !nerr.Timeout() { + t.Fatal(err) } } } -func TestReadTimeout(t *testing.T) { +func TestAcceptTimeoutMustNotReturn(t *testing.T) { switch runtime.GOOS { case "plan9": - t.Skipf("skipping test on %q", runtime.GOOS) + t.Skipf("not supported on %s", runtime.GOOS) } - ln := newLocalListener(t) - defer ln.Close() - c, err := DialTCP("tcp", nil, ln.Addr().(*TCPAddr)) + ln, err := newLocalListener("tcp") if err != nil { - t.Fatalf("Connect: %v", err) - } - defer c.Close() - c.SetDeadline(time.Now().Add(time.Hour)) - c.SetReadDeadline(time.Now().Add(-1 * time.Second)) - buf := make([]byte, 1) - if _, err = c.Read(buf); !isTimeout(err) { - t.Fatalf("Read: expected err %v, got %v", errTimeout, err) - } - if _, err = c.Read(buf); !isTimeout(err) { - t.Fatalf("Read: expected err %v, got %v", errTimeout, err) - } - c.SetDeadline(time.Now().Add(100 * time.Millisecond)) - if _, err = c.Read(buf); !isTimeout(err) { - t.Fatalf("Read: expected err %v, got %v", errTimeout, err) - } - if _, err = c.Read(buf); !isTimeout(err) { - t.Fatalf("Read: expected err %v, got %v", errTimeout, err) + t.Fatal(err) } - c.SetReadDeadline(noDeadline) - c.SetWriteDeadline(time.Now().Add(-1 * time.Second)) - errc := make(chan error) + defer ln.Close() + + max := time.NewTimer(100 * time.Millisecond) + defer max.Stop() + ch := make(chan error) go func() { - _, err := c.Read(buf) - errc <- err - }() - time.Sleep(100 * time.Millisecond) - select { - case err := <-errc: - t.Fatalf("Expected Read() to not return, but it returned with %v\n", err) - default: - } - c.Close() - switch nerr := <-errc; err := nerr.(type) { - case *OpError: - if err.Err != errClosing { - t.Fatalf("Read: expected err %v, got %v", errClosing, err) + if err := ln.(*TCPListener).SetDeadline(time.Now().Add(-5 * time.Second)); err != nil { + t.Error(err) } - default: - if err == io.EOF && runtime.GOOS == "nacl" { // close enough; golang.org/issue/8044 - break + if err := ln.(*TCPListener).SetDeadline(noDeadline); err != nil { + t.Error(err) } - if err != errClosing { - t.Fatalf("Read: expected err %v, got %v", errClosing, err) + _, err := ln.Accept() + ch <- err + }() + + select { + case err := <-ch: + if perr := parseAcceptError(err); perr != nil { + t.Error(perr) } + t.Fatalf("expected Accept to not return, but it returned with %v", err) + case <-max.C: + ln.Close() + <-ch // wait for tester goroutine to stop } } -func TestWriteTimeout(t *testing.T) { +var readTimeoutTests = []struct { + timeout time.Duration + xerrs [2]error // expected errors in transition +}{ + // Tests that read deadlines work, even if there's data ready + // to be read. + {-5 * time.Second, [2]error{errTimeout, errTimeout}}, + + {50 * time.Millisecond, [2]error{nil, errTimeout}}, +} + +func TestReadTimeout(t *testing.T) { switch runtime.GOOS { case "plan9": - t.Skipf("skipping test on %q", runtime.GOOS) + t.Skipf("not supported on %s", runtime.GOOS) } - ln := newLocalListener(t) - defer ln.Close() - c, err := DialTCP("tcp", nil, ln.Addr().(*TCPAddr)) + handler := func(ls *localServer, ln Listener) { + c, err := ln.Accept() + if err != nil { + t.Error(err) + return + } + c.Write([]byte("READ TIMEOUT TEST")) + defer c.Close() + } + ls, err := newLocalServer("tcp") + if err != nil { + t.Fatal(err) + } + defer ls.teardown() + if err := ls.buildup(handler); err != nil { + t.Fatal(err) + } + + c, err := Dial(ls.Listener.Addr().Network(), ls.Listener.Addr().String()) if err != nil { - t.Fatalf("Connect: %v", err) + t.Fatal(err) } defer c.Close() - c.SetDeadline(time.Now().Add(time.Hour)) - c.SetWriteDeadline(time.Now().Add(-1 * time.Second)) - buf := make([]byte, 4096) - writeUntilTimeout := func() { - for { - _, err := c.Write(buf) - if err != nil { - if isTimeout(err) { - return + + for i, tt := range readTimeoutTests { + if err := c.SetReadDeadline(time.Now().Add(tt.timeout)); err != nil { + t.Fatalf("#%d: %v", i, err) + } + var b [1]byte + for j, xerr := range tt.xerrs { + for { + n, err := c.Read(b[:]) + if xerr != nil { + if perr := parseReadError(err); perr != nil { + t.Errorf("#%d/%d: %v", i, j, perr) + } + if nerr, ok := err.(Error); !ok || !nerr.Timeout() { + t.Fatalf("#%d/%d: %v", i, j, err) + } + } + if err == nil { + time.Sleep(tt.timeout / 3) + continue + } + if n != 0 { + t.Fatalf("#%d/%d: read %d; want 0", i, j, n) } - t.Fatalf("Write: expected err %v, got %v", errTimeout, err) + break } } } - writeUntilTimeout() - c.SetDeadline(time.Now().Add(10 * time.Millisecond)) - writeUntilTimeout() - writeUntilTimeout() - c.SetWriteDeadline(noDeadline) - c.SetReadDeadline(time.Now().Add(-1 * time.Second)) - errc := make(chan error) - go func() { - for { - _, err := c.Write(buf) - if err != nil { - errc <- err - } - } - }() - time.Sleep(100 * time.Millisecond) - select { - case err := <-errc: - t.Fatalf("Expected Write() to not return, but it returned with %v\n", err) - default: +} + +func TestReadTimeoutMustNotReturn(t *testing.T) { + switch runtime.GOOS { + case "plan9": + t.Skipf("not supported on %s", runtime.GOOS) } - c.Close() - switch nerr := <-errc; err := nerr.(type) { - case *OpError: - if err.Err != errClosing { - t.Fatalf("Write: expected err %v, got %v", errClosing, err) - } - default: - if err != errClosing { - t.Fatalf("Write: expected err %v, got %v", errClosing, err) - } + + ln, err := newLocalListener("tcp") + if err != nil { + t.Fatal(err) } -} + defer ln.Close() -func testTimeout(t *testing.T, net, addr string, readFrom bool) { - c, err := Dial(net, addr) + c, err := Dial(ln.Addr().Network(), ln.Addr().String()) if err != nil { - t.Errorf("Dial(%q, %q) failed: %v", net, addr, err) - return + t.Fatal(err) } defer c.Close() - what := "Read" - if readFrom { - what = "ReadFrom" - } - errc := make(chan error, 1) + max := time.NewTimer(100 * time.Millisecond) + defer max.Stop() + ch := make(chan error) go func() { - t0 := time.Now() - c.SetReadDeadline(time.Now().Add(100 * time.Millisecond)) - var b [100]byte - var n int - var err error - if readFrom { - n, _, err = c.(PacketConn).ReadFrom(b[0:]) - } else { - n, err = c.Read(b[0:]) - } - t1 := time.Now() - 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 err := c.SetDeadline(time.Now().Add(-5 * time.Second)); err != nil { + t.Error(err) } - if dt := t1.Sub(t0); dt < 50*time.Millisecond || !testing.Short() && dt > 250*time.Millisecond { - errc <- fmt.Errorf("%s(%q, %q) took %s, expected 0.1s", what, net, addr, dt) - return + if err := c.SetWriteDeadline(time.Now().Add(-5 * time.Second)); err != nil { + t.Error(err) + } + if err := c.SetReadDeadline(noDeadline); err != nil { + t.Error(err) } - errc <- nil + var b [1]byte + _, err := c.Read(b[:]) + ch <- err }() + select { - case err := <-errc: - if err != nil { - t.Error(err) + case err := <-ch: + if perr := parseReadError(err); perr != nil { + t.Error(perr) + } + t.Fatalf("expected Read to not return, but it returned with %v", err) + case <-max.C: + c.Close() + err := <-ch // wait for tester goroutine to stop + if perr := parseReadError(err); perr != nil { + t.Error(perr) + } + if err == io.EOF && runtime.GOOS == "nacl" { // see golang.org/issue/8044 + return + } + if nerr, ok := err.(Error); !ok || nerr.Timeout() || nerr.Temporary() { + t.Fatal(err) } - case <-time.After(1 * time.Second): - t.Errorf("%s(%q, %q) took over 1 second, expected 0.1s", what, net, addr) } } -func TestTimeoutUDP(t *testing.T) { +var readFromTimeoutTests = []struct { + timeout time.Duration + xerrs [2]error // expected errors in transition +}{ + // Tests that read deadlines work, even if there's data ready + // to be read. + {-5 * time.Second, [2]error{errTimeout, errTimeout}}, + + {50 * time.Millisecond, [2]error{nil, errTimeout}}, +} + +func TestReadFromTimeout(t *testing.T) { switch runtime.GOOS { - case "plan9": - t.Skipf("skipping test on %q", runtime.GOOS) + case "nacl", "plan9": + t.Skipf("not supported on %s", runtime.GOOS) // see golang.org/issue/8916 } - // 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 + ch := make(chan Addr) + defer close(ch) + handler := func(ls *localPacketServer, c PacketConn) { + if dst, ok := <-ch; ok { + c.WriteTo([]byte("READFROM TIMEOUT TEST"), dst) + } + } + ls, err := newLocalPacketServer("udp") + if err != nil { + t.Fatal(err) + } + defer ls.teardown() + if err := ls.buildup(handler); err != nil { + t.Fatal(err) + } - testTimeout(t, "udp", addr, false) - testTimeout(t, "udp", addr, true) - <-done -} + host, _, err := SplitHostPort(ls.PacketConn.LocalAddr().String()) + if err != nil { + t.Fatal(err) + } + c, err := ListenPacket(ls.PacketConn.LocalAddr().Network(), JoinHostPort(host, "0")) + if err != nil { + t.Fatal(err) + } + defer c.Close() + ch <- c.LocalAddr() -func TestTimeoutTCP(t *testing.T) { - switch runtime.GOOS { - case "plan9": - t.Skipf("skipping test on %q", runtime.GOOS) + for i, tt := range readFromTimeoutTests { + if err := c.SetReadDeadline(time.Now().Add(tt.timeout)); err != nil { + t.Fatalf("#%d: %v", i, err) + } + var b [1]byte + for j, xerr := range tt.xerrs { + for { + n, _, err := c.ReadFrom(b[:]) + if xerr != nil { + if perr := parseReadError(err); perr != nil { + t.Errorf("#%d/%d: %v", i, j, perr) + } + if nerr, ok := err.(Error); !ok || !nerr.Timeout() { + t.Fatalf("#%d/%d: %v", i, j, err) + } + } + if err == nil { + time.Sleep(tt.timeout / 3) + continue + } + if n != 0 { + t.Fatalf("#%d/%d: read %d; want 0", i, j, n) + } + break + } + } } +} - // set up a listener that won't talk back - listening := make(chan string) - done := make(chan int) - go runStreamConnServer(t, "tcp", "127.0.0.1:0", listening, done) - addr := <-listening +var writeTimeoutTests = []struct { + timeout time.Duration + xerrs [2]error // expected errors in transition +}{ + // Tests that write deadlines work, even if there's buffer + // space available to write. + {-5 * time.Second, [2]error{errTimeout, errTimeout}}, - testTimeout(t, "tcp", addr, false) - <-done + {10 * time.Millisecond, [2]error{nil, errTimeout}}, } -func TestDeadlineReset(t *testing.T) { +func TestWriteTimeout(t *testing.T) { switch runtime.GOOS { case "plan9": - t.Skipf("skipping test on %q", runtime.GOOS) + t.Skipf("not supported on %s", runtime.GOOS) } - ln, err := Listen("tcp", "127.0.0.1:0") + + ln, err := newLocalListener("tcp") if err != nil { t.Fatal(err) } defer ln.Close() - tl := ln.(*TCPListener) - tl.SetDeadline(time.Now().Add(1 * time.Minute)) - tl.SetDeadline(noDeadline) // reset it - errc := make(chan error, 1) - go func() { - _, err := ln.Accept() - errc <- err - }() - select { - case <-time.After(50 * time.Millisecond): - // Pass. - case err := <-errc: - // Accept should never return; we never - // connected to it. - t.Errorf("unexpected return from Accept; err=%v", err) + + for i, tt := range writeTimeoutTests { + c, err := Dial(ln.Addr().Network(), ln.Addr().String()) + if err != nil { + t.Fatal(err) + } + defer c.Close() + + if err := c.SetWriteDeadline(time.Now().Add(tt.timeout)); err != nil { + t.Fatalf("#%d: %v", i, err) + } + for j, xerr := range tt.xerrs { + for { + n, err := c.Write([]byte("WRITE TIMEOUT TEST")) + if xerr != nil { + if perr := parseWriteError(err); perr != nil { + t.Errorf("#%d/%d: %v", i, j, perr) + } + if nerr, ok := err.(Error); !ok || !nerr.Timeout() { + t.Fatalf("#%d/%d: %v", i, j, err) + } + } + if err == nil { + time.Sleep(tt.timeout / 3) + continue + } + if n != 0 { + t.Fatalf("#%d/%d: wrote %d; want 0", i, j, n) + } + break + } + } } } -func TestTimeoutAccept(t *testing.T) { +func TestWriteTimeoutMustNotReturn(t *testing.T) { switch runtime.GOOS { case "plan9": - t.Skipf("skipping test on %q", runtime.GOOS) + t.Skipf("not supported on %s", runtime.GOOS) } - ln, err := Listen("tcp", "127.0.0.1:0") + + ln, err := newLocalListener("tcp") if err != nil { t.Fatal(err) } defer ln.Close() - tl := ln.(*TCPListener) - tl.SetDeadline(time.Now().Add(100 * time.Millisecond)) - errc := make(chan error, 1) + + c, err := Dial(ln.Addr().Network(), ln.Addr().String()) + if err != nil { + t.Fatal(err) + } + defer c.Close() + + max := time.NewTimer(100 * time.Millisecond) + defer max.Stop() + ch := make(chan error) go func() { - _, err := ln.Accept() - errc <- err + if err := c.SetDeadline(time.Now().Add(-5 * time.Second)); err != nil { + t.Error(err) + } + if err := c.SetReadDeadline(time.Now().Add(-5 * time.Second)); err != nil { + t.Error(err) + } + if err := c.SetWriteDeadline(noDeadline); err != nil { + t.Error(err) + } + var b [1]byte + for { + if _, err := c.Write(b[:]); err != nil { + ch <- err + break + } + } }() + select { - case <-time.After(1 * time.Second): - // Accept shouldn't block indefinitely - t.Errorf("Accept didn't return in an expected time") - case <-errc: - // Pass. + case err := <-ch: + if perr := parseWriteError(err); perr != nil { + t.Error(perr) + } + t.Fatalf("expected Write to not return, but it returned with %v", err) + case <-max.C: + c.Close() + err := <-ch // wait for tester goroutine to stop + if perr := parseWriteError(err); perr != nil { + t.Error(perr) + } + if nerr, ok := err.(Error); !ok || nerr.Timeout() || nerr.Temporary() { + t.Fatal(err) + } } } -func TestReadWriteDeadline(t *testing.T) { +var writeToTimeoutTests = []struct { + timeout time.Duration + xerrs [2]error // expected errors in transition +}{ + // Tests that write deadlines work, even if there's buffer + // space available to write. + {-5 * time.Second, [2]error{errTimeout, errTimeout}}, + + {10 * time.Millisecond, [2]error{nil, errTimeout}}, +} + +func TestWriteToTimeout(t *testing.T) { switch runtime.GOOS { - case "plan9": - t.Skipf("skipping test on %q", runtime.GOOS) + case "nacl", "plan9": + t.Skipf("not supported on %s", runtime.GOOS) } - const ( - readTimeout = 50 * time.Millisecond - writeTimeout = 250 * time.Millisecond - ) - checkTimeout := func(command string, start time.Time, should time.Duration) { - is := time.Now().Sub(start) - d := is - should - if d < -30*time.Millisecond || !testing.Short() && 150*time.Millisecond < d { - t.Errorf("%s timeout test failed: is=%v should=%v\n", command, is, should) - } + c1, err := newLocalPacketListener("udp") + if err != nil { + t.Fatal(err) } + defer c1.Close() - ln, err := Listen("tcp", "127.0.0.1:0") + host, _, err := SplitHostPort(c1.LocalAddr().String()) if err != nil { - t.Fatalf("ListenTCP on :0: %v", err) + t.Fatal(err) } - defer ln.Close() - lnquit := make(chan bool) - - go func() { - c, err := ln.Accept() + for i, tt := range writeToTimeoutTests { + c2, err := ListenPacket(c1.LocalAddr().Network(), JoinHostPort(host, "0")) if err != nil { - t.Errorf("Accept: %v", err) - return + t.Fatal(err) } - defer c.Close() - lnquit <- true - }() + defer c2.Close() + + if err := c2.SetWriteDeadline(time.Now().Add(tt.timeout)); err != nil { + t.Fatalf("#%d: %v", i, err) + } + for j, xerr := range tt.xerrs { + for { + n, err := c2.WriteTo([]byte("WRITETO TIMEOUT TEST"), c1.LocalAddr()) + if xerr != nil { + if perr := parseWriteError(err); perr != nil { + t.Errorf("#%d/%d: %v", i, j, perr) + } + if nerr, ok := err.(Error); !ok || !nerr.Timeout() { + t.Fatalf("#%d/%d: %v", i, j, err) + } + } + if err == nil { + time.Sleep(tt.timeout / 3) + continue + } + if n != 0 { + t.Fatalf("#%d/%d: wrote %d; want 0", i, j, n) + } + break + } + } + } +} + +func TestReadTimeoutFluctuation(t *testing.T) { + switch runtime.GOOS { + case "plan9": + t.Skipf("not supported on %s", runtime.GOOS) + } - c, err := Dial("tcp", ln.Addr().String()) + ln, err := newLocalListener("tcp") if err != nil { - t.Fatalf("Dial: %v", err) + t.Fatal(err) + } + defer ln.Close() + + c, err := Dial(ln.Addr().Network(), ln.Addr().String()) + if err != nil { + t.Fatal(err) } defer c.Close() - start := time.Now() - err = c.SetReadDeadline(start.Add(readTimeout)) + max := time.NewTimer(time.Second) + defer max.Stop() + ch := make(chan error) + go timeoutReceiver(c, 100*time.Millisecond, 50*time.Millisecond, 250*time.Millisecond, ch) + + select { + case <-max.C: + t.Fatal("Read took over 1s; expected 0.1s") + case err := <-ch: + if perr := parseReadError(err); perr != nil { + t.Error(perr) + } + if nerr, ok := err.(Error); !ok || !nerr.Timeout() { + t.Fatal(err) + } + } +} + +func TestReadFromTimeoutFluctuation(t *testing.T) { + switch runtime.GOOS { + case "plan9": + t.Skipf("not supported on %s", runtime.GOOS) + } + + c1, err := newLocalPacketListener("udp") if err != nil { - t.Fatalf("SetReadDeadline: %v", err) + t.Fatal(err) } - err = c.SetWriteDeadline(start.Add(writeTimeout)) + defer c1.Close() + + c2, err := Dial(c1.LocalAddr().Network(), c1.LocalAddr().String()) if err != nil { - t.Fatalf("SetWriteDeadline: %v", err) + t.Fatal(err) } + defer c2.Close() - quit := make(chan bool) + max := time.NewTimer(time.Second) + defer max.Stop() + ch := make(chan error) + go timeoutPacketReceiver(c2.(PacketConn), 100*time.Millisecond, 50*time.Millisecond, 250*time.Millisecond, ch) - go func() { - var buf [10]byte - _, err := c.Read(buf[:]) - if err == nil { - t.Errorf("Read should not succeed") + select { + case <-max.C: + t.Fatal("ReadFrom took over 1s; expected 0.1s") + case err := <-ch: + if perr := parseReadError(err); perr != nil { + t.Error(perr) } - checkTimeout("Read", start, readTimeout) - quit <- true - }() - - go func() { - var buf [10000]byte - for { - _, err := c.Write(buf[:]) - if err != nil { - break - } + if nerr, ok := err.(Error); !ok || !nerr.Timeout() { + t.Fatal(err) } - checkTimeout("Write", start, writeTimeout) - quit <- true - }() - - <-quit - <-quit - <-lnquit + } } -type neverEnding byte +func TestWriteTimeoutFluctuation(t *testing.T) { + switch runtime.GOOS { + case "plan9": + t.Skipf("not supported on %s", runtime.GOOS) + } -func (b neverEnding) Read(p []byte) (n int, err error) { - for i := range p { - p[i] = byte(b) + ln, err := newLocalListener("tcp") + if err != nil { + t.Fatal(err) + } + defer ln.Close() + + c, err := Dial(ln.Addr().Network(), ln.Addr().String()) + if err != nil { + t.Fatal(err) + } + defer c.Close() + + d := time.Second + if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") { + d = 3 * time.Second // see golang.org/issue/10775 + } + max := time.NewTimer(d) + defer max.Stop() + ch := make(chan error) + go timeoutTransmitter(c, 100*time.Millisecond, 50*time.Millisecond, 250*time.Millisecond, ch) + + select { + case <-max.C: + t.Fatalf("Write took over %v; expected 0.1s", d) + case err := <-ch: + if perr := parseWriteError(err); perr != nil { + t.Error(perr) + } + if nerr, ok := err.(Error); !ok || !nerr.Timeout() { + t.Fatal(err) + } } - return len(p), nil } func TestVariousDeadlines1Proc(t *testing.T) { @@ -420,36 +739,57 @@ func TestVariousDeadlines4Proc(t *testing.T) { testVariousDeadlines(t, 4) } +type neverEnding byte + +func (b neverEnding) Read(p []byte) (int, error) { + for i := range p { + p[i] = byte(b) + } + return len(p), nil +} + func testVariousDeadlines(t *testing.T, maxProcs int) { switch runtime.GOOS { case "plan9": - t.Skipf("skipping test on %q", runtime.GOOS) + t.Skipf("not supported on %s", runtime.GOOS) } defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(maxProcs)) - ln := newLocalListener(t) - defer ln.Close() - acceptc := make(chan error, 1) - // The server, with no timeouts of its own, sending bytes to clients - // as fast as it can. - servec := make(chan copyRes) - go func() { + type result struct { + n int64 + err error + d time.Duration + } + + ch := make(chan error, 1) + pasvch := make(chan result) + handler := func(ls *localServer, ln Listener) { for { c, err := ln.Accept() if err != nil { - acceptc <- err + ch <- err return } + // The server, with no timeouts of its own, + // sending bytes to clients as fast as it can. go func() { t0 := time.Now() n, err := io.Copy(c, neverEnding('a')) - d := time.Since(t0) + dt := time.Since(t0) c.Close() - servec <- copyRes{n, err, d} + pasvch <- result{n, err, dt} }() } - }() + } + ls, err := newLocalServer("tcp") + if err != nil { + t.Fatal(err) + } + defer ls.teardown() + if err := ls.buildup(handler); err != nil { + t.Fatal(err) + } for _, timeout := range []time.Duration{ 1 * time.Nanosecond, @@ -483,236 +823,133 @@ func testVariousDeadlines(t *testing.T, maxProcs int) { name := fmt.Sprintf("%v run %d/%d", timeout, run+1, numRuns) t.Log(name) - c, err := Dial("tcp", ln.Addr().String()) + c, err := Dial(ls.Listener.Addr().Network(), ls.Listener.Addr().String()) if err != nil { - t.Fatalf("Dial: %v", err) + t.Fatal(err) } - clientc := make(chan copyRes) + + tooLong := 5 * time.Second + max := time.NewTimer(tooLong) + defer max.Stop() + actvch := make(chan result) go func() { t0 := time.Now() - c.SetDeadline(t0.Add(timeout)) + if err := c.SetDeadline(t0.Add(timeout)); err != nil { + t.Error(err) + } n, err := io.Copy(ioutil.Discard, c) - d := time.Since(t0) + dt := time.Since(t0) c.Close() - clientc <- copyRes{n, err, d} + actvch <- result{n, err, dt} }() - tooLong := 5 * time.Second select { - case res := <-clientc: - if isTimeout(res.err) { + case res := <-actvch: + if nerr, ok := res.err.(Error); ok && nerr.Timeout() { t.Logf("for %v, good client timeout after %v, reading %d bytes", name, res.d, res.n) } else { - t.Fatalf("for %v: client Copy = %d, %v (want timeout)", name, res.n, res.err) + t.Fatalf("for %v, client Copy = %d, %v; want timeout", name, res.n, res.err) } - case <-time.After(tooLong): - t.Fatalf("for %v: timeout (%v) waiting for client to timeout (%v) reading", name, tooLong, timeout) + case <-max.C: + t.Fatalf("for %v, timeout (%v) waiting for client to timeout (%v) reading", name, tooLong, timeout) } select { - case res := <-servec: - t.Logf("for %v: server in %v wrote %d, %v", name, res.d, res.n, res.err) - case err := <-acceptc: - t.Fatalf("for %v: server Accept = %v", name, err) - case <-time.After(tooLong): + case res := <-pasvch: + t.Logf("for %v, server in %v wrote %d: %v", name, res.d, res.n, res.err) + case err := <-ch: + t.Fatalf("for %v, Accept = %v", name, err) + case <-max.C: t.Fatalf("for %v, timeout waiting for server to finish writing", name) } } } } -// TestReadDeadlineDataAvailable tests that read deadlines work, even -// if there's data ready to be read. -func TestReadDeadlineDataAvailable(t *testing.T) { +// TestReadWriteProlongedTimeout tests concurrent deadline +// modification. Known to cause data races in the past. +func TestReadWriteProlongedTimeout(t *testing.T) { switch runtime.GOOS { case "plan9": - t.Skipf("skipping test on %q", runtime.GOOS) + t.Skipf("not supported on %s", runtime.GOOS) } - ln := newLocalListener(t) - defer ln.Close() - - servec := make(chan copyRes) - const msg = "data client shouldn't read, even though it'll be waiting" - go func() { + handler := func(ls *localServer, ln Listener) { c, err := ln.Accept() if err != nil { - t.Errorf("Accept: %v", err) - return - } - defer c.Close() - n, err := c.Write([]byte(msg)) - servec <- copyRes{n: int64(n), err: err} - }() - - c, err := Dial("tcp", ln.Addr().String()) - if err != nil { - t.Fatalf("Dial: %v", err) - } - defer c.Close() - if res := <-servec; res.err != nil || res.n != int64(len(msg)) { - t.Fatalf("unexpected server Write: n=%d, err=%v; want n=%d, err=nil", res.n, res.err, len(msg)) - } - c.SetReadDeadline(time.Now().Add(-5 * time.Second)) // in the psat. - buf := make([]byte, len(msg)/2) - n, err := c.Read(buf) - if n > 0 || !isTimeout(err) { - t.Fatalf("client read = %d (%q) err=%v; want 0, timeout", n, buf[:n], err) - } -} - -// TestWriteDeadlineBufferAvailable tests that write deadlines work, even -// if there's buffer space available to write. -func TestWriteDeadlineBufferAvailable(t *testing.T) { - switch runtime.GOOS { - case "plan9": - t.Skipf("skipping test on %q", runtime.GOOS) - } - - ln := newLocalListener(t) - defer ln.Close() - - servec := make(chan copyRes) - go func() { - c, err := ln.Accept() - if err != nil { - t.Errorf("Accept: %v", err) - return - } - defer c.Close() - c.SetWriteDeadline(time.Now().Add(-5 * time.Second)) // in the past - n, err := c.Write([]byte{'x'}) - servec <- copyRes{n: int64(n), err: err} - }() - - c, err := Dial("tcp", ln.Addr().String()) - if err != nil { - t.Fatalf("Dial: %v", err) - } - defer c.Close() - res := <-servec - if res.n != 0 { - t.Errorf("Write = %d; want 0", res.n) - } - if !isTimeout(res.err) { - t.Errorf("Write error = %v; want timeout", res.err) - } -} - -// TestAcceptDeadlineConnectionAvailable tests that accept deadlines work, even -// if there's incoming connections available. -func TestAcceptDeadlineConnectionAvailable(t *testing.T) { - switch runtime.GOOS { - case "plan9": - t.Skipf("skipping test on %q", runtime.GOOS) - } - - ln := newLocalListener(t).(*TCPListener) - defer ln.Close() - - go func() { - c, err := Dial("tcp", ln.Addr().String()) - if err != nil { - t.Errorf("Dial: %v", err) + t.Error(err) return } defer c.Close() - var buf [1]byte - c.Read(buf[:]) // block until the connection or listener is closed - }() - time.Sleep(10 * time.Millisecond) - ln.SetDeadline(time.Now().Add(-5 * time.Second)) // in the past - c, err := ln.Accept() - if err == nil { - defer c.Close() - } - if !isTimeout(err) { - t.Fatalf("Accept: got %v; want timeout", err) - } -} - -// TestConnectDeadlineInThePast tests that connect deadlines work, even -// if the connection can be established w/o blocking. -func TestConnectDeadlineInThePast(t *testing.T) { - switch runtime.GOOS { - case "plan9": - t.Skipf("skipping test on %q", runtime.GOOS) - } - - ln := newLocalListener(t).(*TCPListener) - defer ln.Close() - - go func() { - c, err := ln.Accept() - if err == nil { - defer c.Close() - } - }() - time.Sleep(10 * time.Millisecond) - c, err := DialTimeout("tcp", ln.Addr().String(), -5*time.Second) // in the past - if err == nil { - defer c.Close() - } - if !isTimeout(err) { - t.Fatalf("DialTimeout: got %v; want timeout", err) - } -} -// TestProlongTimeout tests concurrent deadline modification. -// Known to cause data races in the past. -func TestProlongTimeout(t *testing.T) { - switch runtime.GOOS { - case "plan9": - t.Skipf("skipping test on %q", runtime.GOOS) - } - - ln := newLocalListener(t) - defer ln.Close() - connected := make(chan bool) - go func() { - s, err := ln.Accept() - connected <- true - if err != nil { - t.Errorf("ln.Accept: %v", err) - return - } - defer s.Close() - s.SetDeadline(time.Now().Add(time.Hour)) + var wg sync.WaitGroup + wg.Add(2) go func() { - var buf [4096]byte + defer wg.Done() + var b [1]byte for { - _, err := s.Write(buf[:]) - if err != nil { - break + if err := c.SetReadDeadline(time.Now().Add(time.Hour)); err != nil { + if perr := parseCommonError(err); perr != nil { + t.Error(perr) + } + t.Error(err) + return + } + if _, err := c.Read(b[:]); err != nil { + if perr := parseReadError(err); perr != nil { + t.Error(perr) + } + return } - s.SetDeadline(time.Now().Add(time.Hour)) } }() - buf := make([]byte, 1) - for { - _, err := s.Read(buf) - if err != nil { - break + go func() { + defer wg.Done() + var b [1]byte + for { + if err := c.SetWriteDeadline(time.Now().Add(time.Hour)); err != nil { + if perr := parseCommonError(err); perr != nil { + t.Error(perr) + } + t.Error(err) + return + } + if _, err := c.Write(b[:]); err != nil { + if perr := parseWriteError(err); perr != nil { + t.Error(perr) + } + return + } } - s.SetDeadline(time.Now().Add(time.Hour)) - } - }() - c, err := Dial("tcp", ln.Addr().String()) + }() + wg.Wait() + } + ls, err := newLocalServer("tcp") + if err != nil { + t.Fatal(err) + } + defer ls.teardown() + if err := ls.buildup(handler); err != nil { + t.Fatal(err) + } + + c, err := Dial(ls.Listener.Addr().Network(), ls.Listener.Addr().String()) if err != nil { - t.Fatalf("DialTCP: %v", err) + t.Fatal(err) } defer c.Close() - <-connected - for i := 0; i < 1024; i++ { - var buf [1]byte - c.Write(buf[:]) + + var b [1]byte + for i := 0; i < 1000; i++ { + c.Write(b[:]) + c.Read(b[:]) } } -func TestDeadlineRace(t *testing.T) { +func TestReadWriteDeadlineRace(t *testing.T) { switch runtime.GOOS { case "nacl", "plan9": - t.Skipf("skipping test on %q", runtime.GOOS) + t.Skipf("not supported on %s", runtime.GOOS) } N := 1000 @@ -720,28 +957,54 @@ func TestDeadlineRace(t *testing.T) { N = 50 } defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4)) - ln := newLocalListener(t) + + ln, err := newLocalListener("tcp") + if err != nil { + t.Fatal(err) + } defer ln.Close() - c, err := Dial("tcp", ln.Addr().String()) + + c, err := Dial(ln.Addr().Network(), ln.Addr().String()) if err != nil { - t.Fatalf("Dial: %v", err) + t.Fatal(err) } defer c.Close() - done := make(chan bool) + + var wg sync.WaitGroup + wg.Add(3) go func() { - t := time.NewTicker(2 * time.Microsecond).C + defer wg.Done() + tic := time.NewTicker(2 * time.Microsecond) + defer tic.Stop() for i := 0; i < N; i++ { - if err := c.SetDeadline(time.Now().Add(2 * time.Microsecond)); err != nil { + if err := c.SetReadDeadline(time.Now().Add(2 * time.Microsecond)); err != nil { + if perr := parseCommonError(err); perr != nil { + t.Error(perr) + } + break + } + if err := c.SetWriteDeadline(time.Now().Add(2 * time.Microsecond)); err != nil { + if perr := parseCommonError(err); perr != nil { + t.Error(perr) + } break } - <-t + <-tic.C } - done <- true }() - var buf [1]byte - for i := 0; i < N; i++ { - c.Read(buf[:]) // ignore possible timeout errors - } - c.Close() - <-done + go func() { + defer wg.Done() + var b [1]byte + for i := 0; i < N; i++ { + c.Read(b[:]) // ignore possible timeout errors + } + }() + go func() { + defer wg.Done() + var b [1]byte + for i := 0; i < N; i++ { + c.Write(b[:]) // ignore possible timeout errors + } + }() + wg.Wait() // wait for tester goroutine to stop } diff --git a/libgo/go/net/udp_test.go b/libgo/go/net/udp_test.go index 125bbca6c40..b25f96a3fd3 100644 --- a/libgo/go/net/udp_test.go +++ b/libgo/go/net/udp_test.go @@ -7,149 +7,164 @@ package net import ( "reflect" "runtime" - "strings" "testing" "time" ) -func TestResolveUDPAddr(t *testing.T) { - for _, tt := range resolveTCPAddrTests { - net := strings.Replace(tt.net, "tcp", "udp", -1) - addr, err := ResolveUDPAddr(net, tt.litAddrOrName) - if err != tt.err { - t.Fatalf("ResolveUDPAddr(%q, %q) failed: %v", net, tt.litAddrOrName, err) - } - if !reflect.DeepEqual(addr, (*UDPAddr)(tt.addr)) { - t.Fatalf("ResolveUDPAddr(%q, %q) = %#v, want %#v", net, tt.litAddrOrName, addr, tt.addr) - } - if err == nil { - str := addr.String() - addr1, err := ResolveUDPAddr(net, str) - if err != nil { - t.Fatalf("ResolveUDPAddr(%q, %q) [from %q]: %v", net, str, tt.litAddrOrName, err) - } - if !reflect.DeepEqual(addr1, addr) { - t.Fatalf("ResolveUDPAddr(%q, %q) [from %q] = %#v, want %#v", net, str, tt.litAddrOrName, addr1, addr) - } - } - } +type resolveUDPAddrTest struct { + network string + litAddrOrName string + addr *UDPAddr + err error } -func TestReadFromUDP(t *testing.T) { - switch runtime.GOOS { - case "nacl", "plan9": - t.Skipf("skipping test on %q, see issue 8916", runtime.GOOS) - } +var resolveUDPAddrTests = []resolveUDPAddrTest{ + {"udp", "127.0.0.1:0", &UDPAddr{IP: IPv4(127, 0, 0, 1), Port: 0}, nil}, + {"udp4", "127.0.0.1:65535", &UDPAddr{IP: IPv4(127, 0, 0, 1), Port: 65535}, nil}, - ra, err := ResolveUDPAddr("udp", "127.0.0.1:7") - if err != nil { - t.Fatal(err) - } + {"udp", "[::1]:0", &UDPAddr{IP: ParseIP("::1"), Port: 0}, nil}, + {"udp6", "[::1]:65535", &UDPAddr{IP: ParseIP("::1"), Port: 65535}, nil}, - la, err := ResolveUDPAddr("udp", "127.0.0.1:0") - if err != nil { - t.Fatal(err) - } + {"udp", "[::1%en0]:1", &UDPAddr{IP: ParseIP("::1"), Port: 1, Zone: "en0"}, nil}, + {"udp6", "[::1%911]:2", &UDPAddr{IP: ParseIP("::1"), Port: 2, Zone: "911"}, nil}, - c, err := ListenUDP("udp", la) - if err != nil { - t.Fatal(err) - } - defer c.Close() + {"", "127.0.0.1:0", &UDPAddr{IP: IPv4(127, 0, 0, 1), Port: 0}, nil}, // Go 1.0 behavior + {"", "[::1]:0", &UDPAddr{IP: ParseIP("::1"), Port: 0}, nil}, // Go 1.0 behavior - _, err = c.WriteToUDP([]byte("a"), ra) - if err != nil { - t.Fatal(err) - } + {"udp", ":12345", &UDPAddr{Port: 12345}, nil}, - err = c.SetDeadline(time.Now().Add(100 * time.Millisecond)) - if err != nil { - t.Fatal(err) - } - b := make([]byte, 1) - _, _, err = c.ReadFromUDP(b) - if err == nil { - t.Fatal("ReadFromUDP should fail") - } else if !isTimeout(err) { - t.Fatal(err) + {"http", "127.0.0.1:0", nil, UnknownNetworkError("http")}, +} + +func TestResolveUDPAddr(t *testing.T) { + origTestHookLookupIP := testHookLookupIP + defer func() { testHookLookupIP = origTestHookLookupIP }() + testHookLookupIP = lookupLocalhost + + for i, tt := range resolveUDPAddrTests { + addr, err := ResolveUDPAddr(tt.network, tt.litAddrOrName) + if err != tt.err { + t.Errorf("#%d: %v", i, err) + } else if !reflect.DeepEqual(addr, tt.addr) { + t.Errorf("#%d: got %#v; want %#v", i, addr, tt.addr) + } + if err != nil { + continue + } + rtaddr, err := ResolveUDPAddr(addr.Network(), addr.String()) + if err != nil { + t.Errorf("#%d: %v", i, err) + } else if !reflect.DeepEqual(rtaddr, addr) { + t.Errorf("#%d: got %#v; want %#v", i, rtaddr, addr) + } } } func TestWriteToUDP(t *testing.T) { switch runtime.GOOS { case "plan9": - t.Skipf("skipping test on %q", runtime.GOOS) + t.Skipf("not supported on %s", runtime.GOOS) } - l, err := ListenPacket("udp", "127.0.0.1:0") + c, err := ListenPacket("udp", "127.0.0.1:0") if err != nil { - t.Fatalf("Listen failed: %v", err) + t.Fatal(err) } - defer l.Close() + defer c.Close() - testWriteToConn(t, l.LocalAddr().String()) - testWriteToPacketConn(t, l.LocalAddr().String()) + testWriteToConn(t, c.LocalAddr().String()) + testWriteToPacketConn(t, c.LocalAddr().String()) } func testWriteToConn(t *testing.T, raddr string) { c, err := Dial("udp", raddr) if err != nil { - t.Fatalf("Dial failed: %v", err) + t.Fatal(err) } defer c.Close() ra, err := ResolveUDPAddr("udp", raddr) if err != nil { - t.Fatalf("ResolveUDPAddr failed: %v", err) + t.Fatal(err) } - _, err = c.(*UDPConn).WriteToUDP([]byte("Connection-oriented mode socket"), ra) + b := []byte("CONNECTED-MODE SOCKET") + _, err = c.(*UDPConn).WriteToUDP(b, ra) if err == nil { - t.Fatal("WriteToUDP should fail") + t.Fatal("should fail") } if err != nil && err.(*OpError).Err != ErrWriteToConnected { - t.Fatalf("WriteToUDP should fail as ErrWriteToConnected: %v", err) + t.Fatalf("should fail as ErrWriteToConnected: %v", err) } - - _, err = c.(*UDPConn).WriteTo([]byte("Connection-oriented mode socket"), ra) + _, err = c.(*UDPConn).WriteTo(b, ra) if err == nil { - t.Fatal("WriteTo should fail") + t.Fatal("should fail") } if err != nil && err.(*OpError).Err != ErrWriteToConnected { - t.Fatalf("WriteTo should fail as ErrWriteToConnected: %v", err) + t.Fatalf("should fail as ErrWriteToConnected: %v", err) } - - _, err = c.Write([]byte("Connection-oriented mode socket")) + _, err = c.Write(b) if err != nil { - t.Fatalf("Write failed: %v", err) + t.Fatal(err) + } + _, _, err = c.(*UDPConn).WriteMsgUDP(b, nil, ra) + if err == nil { + t.Fatal("should fail") + } + if err != nil && err.(*OpError).Err != ErrWriteToConnected { + t.Fatalf("should fail as ErrWriteToConnected: %v", err) + } + _, _, err = c.(*UDPConn).WriteMsgUDP(b, nil, nil) + switch runtime.GOOS { + case "nacl", "windows": // see golang.org/issue/9252 + t.Skipf("not implemented yet on %s", runtime.GOOS) + default: + if err != nil { + t.Fatal(err) + } } } func testWriteToPacketConn(t *testing.T, raddr string) { c, err := ListenPacket("udp", "127.0.0.1:0") if err != nil { - t.Fatalf("ListenPacket failed: %v", err) + t.Fatal(err) } defer c.Close() ra, err := ResolveUDPAddr("udp", raddr) if err != nil { - t.Fatalf("ResolveUDPAddr failed: %v", err) + t.Fatal(err) } - _, err = c.(*UDPConn).WriteToUDP([]byte("Connection-less mode socket"), ra) + b := []byte("UNCONNECTED-MODE SOCKET") + _, err = c.(*UDPConn).WriteToUDP(b, ra) if err != nil { - t.Fatalf("WriteToUDP failed: %v", err) + t.Fatal(err) } - - _, err = c.WriteTo([]byte("Connection-less mode socket"), ra) + _, err = c.WriteTo(b, ra) if err != nil { - t.Fatalf("WriteTo failed: %v", err) + t.Fatal(err) } - - _, err = c.(*UDPConn).Write([]byte("Connection-less mode socket")) + _, err = c.(*UDPConn).Write(b) + if err == nil { + t.Fatal("should fail") + } + _, _, err = c.(*UDPConn).WriteMsgUDP(b, nil, nil) if err == nil { - t.Fatal("Write should fail") + t.Fatal("should fail") + } + if err != nil && err.(*OpError).Err != errMissingAddress { + t.Fatalf("should fail as errMissingAddress: %v", err) + } + _, _, err = c.(*UDPConn).WriteMsgUDP(b, nil, ra) + switch runtime.GOOS { + case "nacl", "windows": // see golang.org/issue/9252 + t.Skipf("not implemented yet on %s", runtime.GOOS) + default: + if err != nil { + t.Fatal(err) + } } } @@ -164,13 +179,13 @@ var udpConnLocalNameTests = []struct { func TestUDPConnLocalName(t *testing.T) { if testing.Short() || !*testExternal { - t.Skip("skipping test to avoid external network") + t.Skip("avoid external network") } for _, tt := range udpConnLocalNameTests { c, err := ListenUDP(tt.net, tt.laddr) if err != nil { - t.Fatalf("ListenUDP failed: %v", err) + t.Fatal(err) } defer c.Close() la := c.LocalAddr() @@ -184,7 +199,7 @@ func TestUDPConnLocalAndRemoteNames(t *testing.T) { for _, laddr := range []string{"", "127.0.0.1:0"} { c1, err := ListenPacket("udp", "127.0.0.1:0") if err != nil { - t.Fatalf("ListenUDP failed: %v", err) + t.Fatal(err) } defer c1.Close() @@ -192,12 +207,12 @@ func TestUDPConnLocalAndRemoteNames(t *testing.T) { if laddr != "" { var err error if la, err = ResolveUDPAddr("udp", laddr); err != nil { - t.Fatalf("ResolveUDPAddr failed: %v", err) + t.Fatal(err) } } c2, err := DialUDP("udp", la, c1.LocalAddr().(*UDPAddr)) if err != nil { - t.Fatalf("DialUDP failed: %v", err) + t.Fatal(err) } defer c2.Close() @@ -220,60 +235,37 @@ func TestUDPConnLocalAndRemoteNames(t *testing.T) { func TestIPv6LinkLocalUnicastUDP(t *testing.T) { if testing.Short() || !*testExternal { - t.Skip("skipping test to avoid external network") + t.Skip("avoid external network") } if !supportsIPv6 { - t.Skip("ipv6 is not supported") - } - ifi := loopbackInterface() - if ifi == nil { - t.Skip("loopback interface not found") - } - laddr := ipv6LinkLocalUnicastAddr(ifi) - if laddr == "" { - t.Skip("ipv6 unicast address on loopback not found") + t.Skip("IPv6 is not supported") } - type test struct { - net, addr string - nameLookup bool - } - var tests = []test{ - {"udp", "[" + laddr + "%" + ifi.Name + "]:0", false}, - {"udp6", "[" + laddr + "%" + ifi.Name + "]:0", false}, - } - // The first udp test fails on DragonFly - see issue 7473. - if runtime.GOOS == "dragonfly" { - tests = tests[1:] - } - switch runtime.GOOS { - case "darwin", "dragonfly", "freebsd", "openbsd", "netbsd": - tests = append(tests, []test{ - {"udp", "[localhost%" + ifi.Name + "]:0", true}, - {"udp6", "[localhost%" + ifi.Name + "]:0", true}, - }...) - case "linux": - tests = append(tests, []test{ - {"udp", "[ip6-localhost%" + ifi.Name + "]:0", true}, - {"udp6", "[ip6-localhost%" + ifi.Name + "]:0", true}, - }...) - } - for _, tt := range tests { - c1, err := ListenPacket(tt.net, tt.addr) + for i, tt := range ipv6LinkLocalUnicastUDPTests { + c1, err := ListenPacket(tt.network, tt.address) if err != nil { // It might return "LookupHost returned no // suitable address" error on some platforms. - t.Logf("ListenPacket failed: %v", err) + t.Log(err) continue } - defer c1.Close() + ls, err := (&packetListener{PacketConn: c1}).newLocalServer() + if err != nil { + t.Fatal(err) + } + defer ls.teardown() + ch := make(chan error, 1) + handler := func(ls *localPacketServer, c PacketConn) { packetTransponder(c, ch) } + if err := ls.buildup(handler); err != nil { + t.Fatal(err) + } if la, ok := c1.LocalAddr().(*UDPAddr); !ok || !tt.nameLookup && la.Zone == "" { t.Fatalf("got %v; expected a proper address with zone identifier", la) } - c2, err := Dial(tt.net, c1.LocalAddr().String()) + c2, err := Dial(tt.network, ls.PacketConn.LocalAddr().String()) if err != nil { - t.Fatalf("Dial failed: %v", err) + t.Fatal(err) } defer c2.Close() if la, ok := c2.LocalAddr().(*UDPAddr); !ok || !tt.nameLookup && la.Zone == "" { @@ -284,14 +276,88 @@ func TestIPv6LinkLocalUnicastUDP(t *testing.T) { } if _, err := c2.Write([]byte("UDP OVER IPV6 LINKLOCAL TEST")); err != nil { - t.Fatalf("Conn.Write failed: %v", err) + t.Fatal(err) } b := make([]byte, 32) - if _, from, err := c1.ReadFrom(b); err != nil { - t.Fatalf("PacketConn.ReadFrom failed: %v", err) + if _, err := c2.Read(b); err != nil { + t.Fatal(err) + } + + for err := range ch { + t.Errorf("#%d: %v", i, err) + } + } +} + +func TestUDPZeroBytePayload(t *testing.T) { + switch runtime.GOOS { + case "nacl", "plan9": + t.Skipf("not supported on %s", runtime.GOOS) + } + + c, err := newLocalPacketListener("udp") + if err != nil { + t.Fatal(err) + } + defer c.Close() + + for _, genericRead := range []bool{false, true} { + n, err := c.WriteTo(nil, c.LocalAddr()) + if err != nil { + t.Fatal(err) + } + if n != 0 { + t.Errorf("got %d; want 0", n) + } + c.SetReadDeadline(time.Now().Add(100 * time.Millisecond)) + var b [1]byte + if genericRead { + _, err = c.(Conn).Read(b[:]) } else { - if ra, ok := from.(*UDPAddr); !ok || !tt.nameLookup && ra.Zone == "" { - t.Fatalf("got %v; expected a proper address with zone identifier", ra) + _, _, err = c.ReadFrom(b[:]) + } + switch err { + case nil: // ReadFrom succeeds + default: // Read may timeout, it depends on the platform + if nerr, ok := err.(Error); !ok || !nerr.Timeout() { + t.Fatal(err) + } + } + } +} + +func TestUDPZeroByteBuffer(t *testing.T) { + switch runtime.GOOS { + case "nacl", "plan9": + t.Skipf("not supported on %s", runtime.GOOS) + } + + c, err := newLocalPacketListener("udp") + if err != nil { + t.Fatal(err) + } + defer c.Close() + + b := []byte("UDP ZERO BYTE BUFFER TEST") + for _, genericRead := range []bool{false, true} { + n, err := c.WriteTo(b, c.LocalAddr()) + if err != nil { + t.Fatal(err) + } + if n != len(b) { + t.Errorf("got %d; want %d", n, len(b)) + } + c.SetReadDeadline(time.Now().Add(100 * time.Millisecond)) + if genericRead { + _, err = c.(Conn).Read(nil) + } else { + _, _, err = c.ReadFrom(nil) + } + switch err { + case nil: // ReadFrom succeeds + default: // Read may timeout, it depends on the platform + if nerr, ok := err.(Error); (!ok || !nerr.Timeout()) && runtime.GOOS != "windows" { // Windows retruns WSAEMSGSIZ + t.Fatal(err) } } } diff --git a/libgo/go/net/udpsock.go b/libgo/go/net/udpsock.go index 4c99ae4af68..9292133aeb8 100644 --- a/libgo/go/net/udpsock.go +++ b/libgo/go/net/udpsock.go @@ -25,7 +25,14 @@ func (a *UDPAddr) String() string { return JoinHostPort(ip, itoa(a.Port)) } -func (a *UDPAddr) toAddr() Addr { +func (a *UDPAddr) isWildcard() bool { + if a == nil || a.IP == nil { + return true + } + return a.IP.IsUnspecified() +} + +func (a *UDPAddr) opAddr() Addr { if a == nil { return nil } @@ -46,9 +53,9 @@ func ResolveUDPAddr(net, addr string) (*UDPAddr, error) { default: return nil, UnknownNetworkError(net) } - a, err := resolveInternetAddr(net, addr, noDeadline) + addrs, err := internetAddrList(net, addr, noDeadline) if err != nil { return nil, err } - return a.toAddr().(*UDPAddr), nil + return addrs.first(isIPv4).(*UDPAddr), nil } diff --git a/libgo/go/net/udpsock_plan9.go b/libgo/go/net/udpsock_plan9.go index 510ac5e4aaa..1ba57a227e9 100644 --- a/libgo/go/net/udpsock_plan9.go +++ b/libgo/go/net/udpsock_plan9.go @@ -33,10 +33,10 @@ func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error) { buf := make([]byte, udpHeaderSize+len(b)) m, err := c.fd.data.Read(buf) if err != nil { - return + return 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} } if m < udpHeaderSize { - return 0, nil, errors.New("short read reading UDP header") + return 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: errors.New("short read reading UDP header")} } buf = buf[:m] @@ -59,7 +59,7 @@ func (c *UDPConn) ReadFrom(b []byte) (int, Addr, error) { // flags that were set on the packet and the source address of the // packet. func (c *UDPConn) ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *UDPAddr, err error) { - return 0, 0, 0, nil, syscall.EPLAN9 + return 0, 0, 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9} } // WriteToUDP writes a UDP packet to addr via c, copying the payload @@ -74,7 +74,7 @@ func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (int, error) { return 0, syscall.EINVAL } if addr == nil { - return 0, &OpError{Op: "write", Net: c.fd.dir, Addr: nil, Err: errMissingAddress} + return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: nil, Err: errMissingAddress} } h := new(udpHeader) h.raddr = addr.IP.To16() @@ -86,7 +86,10 @@ func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (int, error) { buf := make([]byte, udpHeaderSize+len(b)) i := copy(buf, h.Bytes()) copy(buf[i:], b) - return c.fd.data.Write(buf) + if _, err := c.fd.data.Write(buf); err != nil { + return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err} + } + return len(b), nil } // WriteTo implements the PacketConn WriteTo method. @@ -96,16 +99,18 @@ func (c *UDPConn) WriteTo(b []byte, addr Addr) (int, error) { } a, ok := addr.(*UDPAddr) if !ok { - return 0, &OpError{"write", c.fd.dir, addr, syscall.EINVAL} + return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr, Err: syscall.EINVAL} } return c.WriteToUDP(b, a) } -// WriteMsgUDP 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. +// WriteMsgUDP writes a packet to addr via c if c isn't connected, or +// to c's remote destination address if c is connected (in which case +// addr must be nil). The payload is copied from b and the associated +// out-of-band data is copied from oob. It returns the number of +// payload and out-of-band bytes written. func (c *UDPConn) WriteMsgUDP(b, oob []byte, addr *UDPAddr) (n, oobn int, err error) { - return 0, 0, syscall.EPLAN9 + return 0, 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr.opAddr(), Err: syscall.EPLAN9} } // DialUDP connects to the remote address raddr on the network net, @@ -122,10 +127,10 @@ func dialUDP(net string, laddr, raddr *UDPAddr, deadline time.Time) (*UDPConn, e switch net { case "udp", "udp4", "udp6": default: - return nil, UnknownNetworkError(net) + return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(net)} } if raddr == nil { - return nil, &OpError{"dial", net, nil, errMissingAddress} + return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: nil, Err: errMissingAddress} } fd, err := dialPlan9(net, laddr, raddr) if err != nil { @@ -173,7 +178,7 @@ func ListenUDP(net string, laddr *UDPAddr) (*UDPConn, error) { switch net { case "udp", "udp4", "udp6": default: - return nil, UnknownNetworkError(net) + return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(net)} } if laddr == nil { laddr = &UDPAddr{} @@ -184,20 +189,27 @@ func ListenUDP(net string, laddr *UDPAddr) (*UDPConn, error) { } _, err = l.ctl.WriteString("headers") if err != nil { - return nil, err + return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err} } l.data, err = os.OpenFile(l.dir+"/data", os.O_RDWR, 0) if err != nil { - return nil, err + return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err} } fd, err := l.netFD() return newUDPConn(fd), err } // ListenMulticastUDP listens for incoming multicast UDP packets -// addressed to the group address gaddr on ifi, which specifies the -// interface to join. ListenMulticastUDP uses default multicast -// interface if ifi is nil. -func ListenMulticastUDP(net string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) { - return nil, syscall.EPLAN9 +// addressed to the group address gaddr on the interface ifi. +// Network must be "udp", "udp4" or "udp6". +// ListenMulticastUDP uses the system-assigned multicast interface +// when ifi is nil, although this is not recommended because the +// assignment depends on platforms and sometimes it might require +// routing configuration. +// +// ListenMulticastUDP is just for convenience of simple, small +// applications. There are golang.org/x/net/ipv4 and +// golang.org/x/net/ipv6 packages for general purpose uses. +func ListenMulticastUDP(network string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) { + return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: gaddr.opAddr(), Err: syscall.EPLAN9} } diff --git a/libgo/go/net/udpsock_posix.go b/libgo/go/net/udpsock_posix.go index a0533366a42..61868c4b0cf 100644 --- a/libgo/go/net/udpsock_posix.go +++ b/libgo/go/net/udpsock_posix.go @@ -31,13 +31,6 @@ 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) { if a == nil { return nil, nil @@ -60,10 +53,11 @@ func newUDPConn(fd *netFD) *UDPConn { return &UDPConn{conn{fd}} } // ReadFromUDP can be made to time out and return an error with // Timeout() == true after a fixed time limit; see SetDeadline and // SetReadDeadline. -func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error) { +func (c *UDPConn) ReadFromUDP(b []byte) (int, *UDPAddr, error) { if !c.ok() { return 0, nil, syscall.EINVAL } + var addr *UDPAddr n, sa, err := c.fd.readFrom(b) switch sa := sa.(type) { case *syscall.SockaddrInet4: @@ -71,7 +65,10 @@ func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error) { case *syscall.SockaddrInet6: addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneToString(int(sa.ZoneId))} } - return + if err != nil { + err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + return n, addr, err } // ReadFrom implements the PacketConn ReadFrom method. @@ -80,7 +77,10 @@ func (c *UDPConn) ReadFrom(b []byte) (int, Addr, error) { return 0, nil, syscall.EINVAL } n, addr, err := c.ReadFromUDP(b) - return n, addr.toAddr(), err + if addr == nil { + return n, nil, err + } + return n, addr, err } // ReadMsgUDP reads a packet from c, copying the payload into b and @@ -100,6 +100,9 @@ func (c *UDPConn) ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *UDPAddr, case *syscall.SockaddrInet6: addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneToString(int(sa.ZoneId))} } + if err != nil { + err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } return } @@ -115,16 +118,20 @@ func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (int, error) { return 0, syscall.EINVAL } if c.fd.isConnected { - return 0, &OpError{"write", c.fd.net, addr, ErrWriteToConnected} + return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: ErrWriteToConnected} } if addr == nil { - return 0, &OpError{Op: "write", Net: c.fd.net, Addr: nil, Err: errMissingAddress} + return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: nil, Err: errMissingAddress} } sa, err := addr.sockaddr(c.fd.family) if err != nil { - return 0, &OpError{"write", c.fd.net, addr, err} + return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err} } - return c.fd.writeTo(b, sa) + n, err := c.fd.writeTo(b, sa) + if err != nil { + err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err} + } + return n, err } // WriteTo implements the PacketConn WriteTo method. @@ -134,29 +141,36 @@ func (c *UDPConn) WriteTo(b []byte, addr Addr) (int, error) { } a, ok := addr.(*UDPAddr) if !ok { - return 0, &OpError{"write", c.fd.net, addr, syscall.EINVAL} + return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: syscall.EINVAL} } return c.WriteToUDP(b, a) } -// WriteMsgUDP 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. +// WriteMsgUDP writes a packet to addr via c if c isn't connected, or +// to c's remote destination address if c is connected (in which case +// addr must be nil). The payload is copied from b and the associated +// out-of-band data is copied from oob. It returns the number of +// payload and out-of-band bytes written. func (c *UDPConn) WriteMsgUDP(b, oob []byte, addr *UDPAddr) (n, oobn int, err error) { if !c.ok() { return 0, 0, syscall.EINVAL } - if c.fd.isConnected { - return 0, 0, &OpError{"write", c.fd.net, addr, ErrWriteToConnected} + if c.fd.isConnected && addr != nil { + return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: ErrWriteToConnected} } - if addr == nil { - return 0, 0, &OpError{Op: "write", Net: c.fd.net, Addr: nil, Err: errMissingAddress} + if !c.fd.isConnected && addr == nil { + return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: errMissingAddress} } - sa, err := addr.sockaddr(c.fd.family) + var sa syscall.Sockaddr + sa, err = addr.sockaddr(c.fd.family) if err != nil { - return 0, 0, &OpError{"write", c.fd.net, addr, err} + return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err} } - return c.fd.writeMsg(b, oob, sa) + n, oobn, err = c.fd.writeMsg(b, oob, sa) + if err != nil { + err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err} + } + return } // DialUDP connects to the remote address raddr on the network net, @@ -166,10 +180,10 @@ func DialUDP(net string, laddr, raddr *UDPAddr) (*UDPConn, error) { switch net { case "udp", "udp4", "udp6": default: - return nil, &OpError{Op: "dial", Net: net, Addr: raddr, Err: UnknownNetworkError(net)} + return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(net)} } if raddr == nil { - return nil, &OpError{Op: "dial", Net: net, Addr: nil, Err: errMissingAddress} + return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: nil, Err: errMissingAddress} } return dialUDP(net, laddr, raddr, noDeadline) } @@ -177,7 +191,7 @@ func DialUDP(net string, laddr, raddr *UDPAddr) (*UDPConn, error) { func dialUDP(net string, laddr, raddr *UDPAddr, deadline time.Time) (*UDPConn, error) { fd, err := internetSocket(net, laddr, raddr, deadline, syscall.SOCK_DGRAM, 0, "dial") if err != nil { - return nil, &OpError{Op: "dial", Net: net, Addr: raddr, Err: err} + return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err} } return newUDPConn(fd), nil } @@ -193,45 +207,52 @@ func ListenUDP(net string, laddr *UDPAddr) (*UDPConn, error) { switch net { case "udp", "udp4", "udp6": default: - return nil, &OpError{Op: "listen", Net: net, Addr: laddr, Err: UnknownNetworkError(net)} + return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(net)} } if laddr == nil { laddr = &UDPAddr{} } fd, err := internetSocket(net, laddr, nil, noDeadline, syscall.SOCK_DGRAM, 0, "listen") if err != nil { - return nil, &OpError{Op: "listen", Net: net, Addr: laddr, Err: err} + return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err} } return newUDPConn(fd), nil } // ListenMulticastUDP listens for incoming multicast UDP packets -// addressed to the group address gaddr on ifi, which specifies the -// interface to join. ListenMulticastUDP uses default multicast -// interface if ifi is nil. -func ListenMulticastUDP(net string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) { - switch net { +// addressed to the group address gaddr on the interface ifi. +// Network must be "udp", "udp4" or "udp6". +// ListenMulticastUDP uses the system-assigned multicast interface +// when ifi is nil, although this is not recommended because the +// assignment depends on platforms and sometimes it might require +// routing configuration. +// +// ListenMulticastUDP is just for convenience of simple, small +// applications. There are golang.org/x/net/ipv4 and +// golang.org/x/net/ipv6 packages for general purpose uses. +func ListenMulticastUDP(network string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) { + switch network { case "udp", "udp4", "udp6": default: - return nil, &OpError{Op: "listen", Net: net, Addr: gaddr, Err: UnknownNetworkError(net)} + return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: gaddr.opAddr(), Err: UnknownNetworkError(network)} } if gaddr == nil || gaddr.IP == nil { - return nil, &OpError{Op: "listen", Net: net, Addr: nil, Err: errMissingAddress} + return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: gaddr.opAddr(), Err: errMissingAddress} } - fd, err := internetSocket(net, gaddr, nil, noDeadline, syscall.SOCK_DGRAM, 0, "listen") + fd, err := internetSocket(network, gaddr, nil, noDeadline, syscall.SOCK_DGRAM, 0, "listen") if err != nil { - return nil, &OpError{Op: "listen", Net: net, Addr: gaddr, Err: err} + return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: gaddr, Err: err} } c := newUDPConn(fd) if ip4 := gaddr.IP.To4(); ip4 != nil { if err := listenIPv4MulticastUDP(c, ifi, ip4); err != nil { c.Close() - return nil, &OpError{Op: "listen", Net: net, Addr: &IPAddr{IP: ip4}, Err: err} + return nil, &OpError{Op: "listen", Net: network, Source: c.fd.laddr, Addr: &IPAddr{IP: ip4}, Err: err} } } else { if err := listenIPv6MulticastUDP(c, ifi, gaddr.IP); err != nil { c.Close() - return nil, &OpError{Op: "listen", Net: net, Addr: &IPAddr{IP: gaddr.IP}, Err: err} + return nil, &OpError{Op: "listen", Net: network, Source: c.fd.laddr, Addr: &IPAddr{IP: gaddr.IP}, Err: err} } } return c, nil diff --git a/libgo/go/net/unicast_posix_test.go b/libgo/go/net/unicast_posix_test.go deleted file mode 100644 index ab7ef40a758..00000000000 --- a/libgo/go/net/unicast_posix_test.go +++ /dev/null @@ -1,469 +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 !plan9 - -package net - -import ( - "runtime" - "syscall" - "testing" -) - -var listenerTests = []struct { - net string - laddr string - ipv6 bool // test with underlying AF_INET6 socket - wildcard bool // test with wildcard address -}{ - {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}, -} - -// 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": - t.Skipf("skipping test on %q", runtime.GOOS) - } - - for _, tt := range listenerTests { - if tt.wildcard && (testing.Short() || !*testExternal) { - continue - } - if tt.ipv6 && !supportsIPv6 { - 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() - } -} - -// 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": - t.Skipf("skipping test on %q", runtime.GOOS) - } - - toudpnet := func(net string) string { - switch net { - case "tcp": - return "udp" - case "tcp4": - return "udp4" - case "tcp6": - return "udp6" - } - return "" - } - - 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) - 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, different -// listening address and same port. -func TestDualStackTCPListener(t *testing.T) { - if testing.Short() { - t.Skip("skipping in -short mode, see issue 5001") - } - switch runtime.GOOS { - case "plan9": - t.Skipf("skipping test on %q", runtime.GOOS) - } - if !supportsIPv6 { - t.Skip("ipv6 is not supported") - } - - for _, tt := range dualStackListenerTests { - if tt.wildcard && !*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) { - if testing.Short() { - t.Skip("skipping in -short mode, see issue 5001") - } - switch runtime.GOOS { - case "plan9": - t.Skipf("skipping test on %q", runtime.GOOS) - } - if !supportsIPv6 { - t.Skip("ipv6 is not supported") - } - - toudpnet := func(net string) string { - switch net { - case "tcp": - return "udp" - case "tcp4": - return "udp4" - case "tcp6": - return "udp6" - } - return "" - } - - 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 - } - } - 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) - } - if err == nil { - 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) - } - if err == nil { - 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) - } - } else { - if fd.family != a.family() { - t.Fatalf("Listen(%q, %q) returns address family %v, expected %v", net, laddr, fd.family, a.family()) - } - } - 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 { - if fd.family != a.family() { - t.Fatalf("ListenPacket(%q, %q) returns address family %v, expected %v", net, laddr, fd.family, a.family()) - } - } - default: - t.Fatalf("Unexpected protocol address type: %T", a) - } -} - -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.Skipf("skipping test on %q", runtime.GOOS) - } - // 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) - } - } -} - -func TestWildWildcardListener(t *testing.T) { - switch runtime.GOOS { - case "plan9": - t.Skipf("skipping test on %q", runtime.GOOS) - } - - if testing.Short() || !*testExternal { - t.Skip("skipping test to avoid external network") - } - - defer func() { - if p := recover(); p != nil { - t.Fatalf("Listen, ListenPacket or protocol-specific Listen panicked: %v", p) - } - }() - - if ln, err := Listen("tcp", ""); err == nil { - ln.Close() - } - if ln, err := ListenPacket("udp", ""); err == nil { - ln.Close() - } - if ln, err := ListenTCP("tcp", nil); err == nil { - ln.Close() - } - if ln, err := ListenUDP("udp", nil); err == nil { - ln.Close() - } - if ln, err := ListenIP("ip:icmp", nil); err == nil { - ln.Close() - } -} diff --git a/libgo/go/net/unix_test.go b/libgo/go/net/unix_test.go index 1cdff3908c1..358ff310725 100644 --- a/libgo/go/net/unix_test.go +++ b/libgo/go/net/unix_test.go @@ -17,14 +17,18 @@ import ( ) func TestReadUnixgramWithUnnamedSocket(t *testing.T) { + if !testableNetwork("unixgram") { + t.Skip("unixgram test") + } + addr := testUnixAddr() la, err := ResolveUnixAddr("unixgram", addr) if err != nil { - t.Fatalf("ResolveUnixAddr failed: %v", err) + t.Fatal(err) } c, err := ListenUnixgram("unixgram", la) if err != nil { - t.Fatalf("ListenUnixgram failed: %v", err) + t.Fatal(err) } defer func() { c.Close() @@ -37,13 +41,13 @@ func TestReadUnixgramWithUnnamedSocket(t *testing.T) { defer func() { off <- true }() s, err := syscall.Socket(syscall.AF_UNIX, syscall.SOCK_DGRAM, 0) if err != nil { - t.Errorf("syscall.Socket failed: %v", err) + t.Error(err) return } defer syscall.Close(s) rsa := &syscall.SockaddrUnix{Name: addr} if err := syscall.Sendto(s, data[:], 0, rsa); err != nil { - t.Errorf("syscall.Sendto failed: %v", err) + t.Error(err) return } }() @@ -53,69 +57,123 @@ func TestReadUnixgramWithUnnamedSocket(t *testing.T) { c.SetReadDeadline(time.Now().Add(100 * time.Millisecond)) n, from, err := c.ReadFrom(b) if err != nil { - t.Fatalf("UnixConn.ReadFrom failed: %v", err) + t.Fatal(err) } if from != nil { - t.Fatalf("neighbor address is %v", from) + t.Fatalf("unexpected peer address: %v", from) } if !bytes.Equal(b[:n], data[:]) { - t.Fatalf("got %v, want %v", b[:n], data[:]) + t.Fatalf("got %v; want %v", b[:n], data[:]) } } -func TestReadUnixgramWithZeroBytesBuffer(t *testing.T) { - // issue 4352: Recvfrom failed with "address family not - // supported by protocol family" if zero-length buffer provided +func TestUnixgramZeroBytePayload(t *testing.T) { + if !testableNetwork("unixgram") { + t.Skip("unixgram test") + } - addr := testUnixAddr() - la, err := ResolveUnixAddr("unixgram", addr) + c1, err := newLocalPacketListener("unixgram") if err != nil { - t.Fatalf("ResolveUnixAddr failed: %v", err) + t.Fatal(err) } - c, err := ListenUnixgram("unixgram", la) + defer os.Remove(c1.LocalAddr().String()) + defer c1.Close() + + c2, err := Dial("unixgram", c1.LocalAddr().String()) if err != nil { - t.Fatalf("ListenUnixgram failed: %v", err) + t.Fatal(err) } - defer func() { - c.Close() - os.Remove(addr) - }() + defer os.Remove(c2.LocalAddr().String()) + defer c2.Close() - off := make(chan bool) - go func() { - defer func() { off <- true }() - c, err := DialUnix("unixgram", nil, la) + for _, genericRead := range []bool{false, true} { + n, err := c2.Write(nil) if err != nil { - t.Errorf("DialUnix failed: %v", err) - return + t.Fatal(err) } - defer c.Close() - if _, err := c.Write([]byte{1, 2, 3, 4, 5}); err != nil { - t.Errorf("UnixConn.Write failed: %v", err) - return + if n != 0 { + t.Errorf("got %d; want 0", n) } - }() + c1.SetReadDeadline(time.Now().Add(100 * time.Millisecond)) + var b [1]byte + var peer Addr + if genericRead { + _, err = c1.(Conn).Read(b[:]) + } else { + _, peer, err = c1.ReadFrom(b[:]) + } + switch err { + case nil: // ReadFrom succeeds + if peer != nil { // peer is connected-mode + t.Fatalf("unexpected peer address: %v", peer) + } + default: // Read may timeout, it depends on the platform + if nerr, ok := err.(Error); !ok || !nerr.Timeout() { + t.Fatal(err) + } + } + } +} - <-off - c.SetReadDeadline(time.Now().Add(100 * time.Millisecond)) - _, from, err := c.ReadFrom(nil) +func TestUnixgramZeroByteBuffer(t *testing.T) { + if !testableNetwork("unixgram") { + t.Skip("unixgram test") + } + // issue 4352: Recvfrom failed with "address family not + // supported by protocol family" if zero-length buffer provided + + c1, err := newLocalPacketListener("unixgram") if err != nil { - t.Fatalf("UnixConn.ReadFrom failed: %v", err) + t.Fatal(err) } - if from != nil { - t.Fatalf("neighbor address is %v", from) + defer os.Remove(c1.LocalAddr().String()) + defer c1.Close() + + c2, err := Dial("unixgram", c1.LocalAddr().String()) + if err != nil { + t.Fatal(err) + } + defer os.Remove(c2.LocalAddr().String()) + defer c2.Close() + + b := []byte("UNIXGRAM ZERO BYTE BUFFER TEST") + for _, genericRead := range []bool{false, true} { + n, err := c2.Write(b) + if err != nil { + t.Fatal(err) + } + if n != len(b) { + t.Errorf("got %d; want %d", n, len(b)) + } + c1.SetReadDeadline(time.Now().Add(100 * time.Millisecond)) + var peer Addr + if genericRead { + _, err = c1.(Conn).Read(nil) + } else { + _, peer, err = c1.ReadFrom(nil) + } + switch err { + case nil: // ReadFrom succeeds + if peer != nil { // peer is connected-mode + t.Fatalf("unexpected peer address: %v", peer) + } + default: // Read may timeout, it depends on the platform + if nerr, ok := err.(Error); !ok || !nerr.Timeout() { + t.Fatal(err) + } + } } } func TestUnixgramAutobind(t *testing.T) { if runtime.GOOS != "linux" { - t.Skip("skipping: autobind is linux only") + t.Skip("autobind is linux only") } laddr := &UnixAddr{Name: "", Net: "unixgram"} c1, err := ListenUnixgram("unixgram", laddr) if err != nil { - t.Fatalf("ListenUnixgram failed: %v", err) + t.Fatal(err) } defer c1.Close() @@ -130,7 +188,7 @@ func TestUnixgramAutobind(t *testing.T) { c2, err := DialUnix("unixgram", nil, autoAddr) if err != nil { - t.Fatalf("DialUnix failed: %v", err) + t.Fatal(err) } defer c2.Close() @@ -141,25 +199,30 @@ func TestUnixgramAutobind(t *testing.T) { func TestUnixAutobindClose(t *testing.T) { if runtime.GOOS != "linux" { - t.Skip("skipping: autobind is linux only") + t.Skip("autobind is linux only") } + laddr := &UnixAddr{Name: "", Net: "unix"} ln, err := ListenUnix("unix", laddr) if err != nil { - t.Fatalf("ListenUnix failed: %v", err) + t.Fatal(err) } ln.Close() } func TestUnixgramWrite(t *testing.T) { + if !testableNetwork("unixgram") { + t.Skip("unixgram test") + } + addr := testUnixAddr() laddr, err := ResolveUnixAddr("unixgram", addr) if err != nil { - t.Fatalf("ResolveUnixAddr failed: %v", err) + t.Fatal(err) } c, err := ListenPacket("unixgram", addr) if err != nil { - t.Fatalf("ListenPacket failed: %v", err) + t.Fatal(err) } defer os.Remove(addr) defer c.Close() @@ -171,27 +234,28 @@ func TestUnixgramWrite(t *testing.T) { func testUnixgramWriteConn(t *testing.T, raddr *UnixAddr) { c, err := Dial("unixgram", raddr.String()) if err != nil { - t.Fatalf("Dial failed: %v", err) + t.Fatal(err) } defer c.Close() - if _, err := c.(*UnixConn).WriteToUnix([]byte("Connection-oriented mode socket"), raddr); err == nil { - t.Fatal("WriteToUnix should fail") + b := []byte("CONNECTED-MODE SOCKET") + if _, err := c.(*UnixConn).WriteToUnix(b, raddr); err == nil { + t.Fatal("should fail") } else if err.(*OpError).Err != ErrWriteToConnected { - t.Fatalf("WriteToUnix should fail as ErrWriteToConnected: %v", err) + t.Fatalf("should fail as ErrWriteToConnected: %v", err) } - if _, err = c.(*UnixConn).WriteTo([]byte("Connection-oriented mode socket"), raddr); err == nil { - t.Fatal("WriteTo should fail") + if _, err = c.(*UnixConn).WriteTo(b, raddr); err == nil { + t.Fatal("should fail") } else if err.(*OpError).Err != ErrWriteToConnected { - t.Fatalf("WriteTo should fail as ErrWriteToConnected: %v", err) + t.Fatalf("should fail as ErrWriteToConnected: %v", err) } - if _, _, err = c.(*UnixConn).WriteMsgUnix([]byte("Connection-oriented mode socket"), nil, raddr); err == nil { - t.Fatal("WriteTo should fail") + if _, _, err = c.(*UnixConn).WriteMsgUnix(b, nil, raddr); err == nil { + t.Fatal("should fail") } else if err.(*OpError).Err != ErrWriteToConnected { - t.Fatalf("WriteMsgUnix should fail as ErrWriteToConnected: %v", err) + t.Fatalf("should fail as ErrWriteToConnected: %v", err) } - if _, err := c.Write([]byte("Connection-oriented mode socket")); err != nil { - t.Fatalf("Write failed: %v", err) + if _, err := c.Write(b); err != nil { + t.Fatal(err) } } @@ -199,52 +263,59 @@ func testUnixgramWritePacketConn(t *testing.T, raddr *UnixAddr) { addr := testUnixAddr() c, err := ListenPacket("unixgram", addr) if err != nil { - t.Fatalf("ListenPacket failed: %v", err) + t.Fatal(err) } defer os.Remove(addr) defer c.Close() - if _, err := c.(*UnixConn).WriteToUnix([]byte("Connectionless mode socket"), raddr); err != nil { - t.Fatalf("WriteToUnix failed: %v", err) + b := []byte("UNCONNECTED-MODE SOCKET") + if _, err := c.(*UnixConn).WriteToUnix(b, raddr); err != nil { + t.Fatal(err) } - if _, err := c.WriteTo([]byte("Connectionless mode socket"), raddr); err != nil { - t.Fatalf("WriteTo failed: %v", err) + if _, err := c.WriteTo(b, raddr); err != nil { + t.Fatal(err) } - if _, _, err := c.(*UnixConn).WriteMsgUnix([]byte("Connectionless mode socket"), nil, raddr); err != nil { - t.Fatalf("WriteMsgUnix failed: %v", err) + if _, _, err := c.(*UnixConn).WriteMsgUnix(b, nil, raddr); err != nil { + t.Fatal(err) } - if _, err := c.(*UnixConn).Write([]byte("Connectionless mode socket")); err == nil { - t.Fatal("Write should fail") + if _, err := c.(*UnixConn).Write(b); err == nil { + t.Fatal("should fail") } } func TestUnixConnLocalAndRemoteNames(t *testing.T) { + if !testableNetwork("unix") { + t.Skip("unix test") + } + + handler := func(ls *localServer, ln Listener) {} for _, laddr := range []string{"", testUnixAddr()} { laddr := laddr taddr := testUnixAddr() ta, err := ResolveUnixAddr("unix", taddr) if err != nil { - t.Fatalf("ResolveUnixAddr failed: %v", err) + t.Fatal(err) } ln, err := ListenUnix("unix", ta) if err != nil { - t.Fatalf("ListenUnix failed: %v", err) + t.Fatal(err) + } + ls, err := (&streamListener{Listener: ln}).newLocalServer() + if err != nil { + t.Fatal(err) + } + defer ls.teardown() + if err := ls.buildup(handler); err != nil { + t.Fatal(err) } - defer func() { - ln.Close() - os.Remove(taddr) - }() - - done := make(chan int) - go transponder(t, ln, done) la, err := ResolveUnixAddr("unix", laddr) if err != nil { - t.Fatalf("ResolveUnixAddr failed: %v", err) + t.Fatal(err) } c, err := DialUnix("unix", la, ta) if err != nil { - t.Fatalf("DialUnix failed: %v", err) + t.Fatal(err) } defer func() { c.Close() @@ -253,7 +324,7 @@ func TestUnixConnLocalAndRemoteNames(t *testing.T) { } }() if _, err := c.Write([]byte("UNIXCONN LOCAL AND REMOTE NAME TEST")); err != nil { - t.Fatalf("UnixConn.Write failed: %v", err) + t.Fatal(err) } switch runtime.GOOS { @@ -272,22 +343,24 @@ func TestUnixConnLocalAndRemoteNames(t *testing.T) { t.Fatalf("got %#v, expected %#v", ca.got, ca.want) } } - - <-done } } func TestUnixgramConnLocalAndRemoteNames(t *testing.T) { + if !testableNetwork("unixgram") { + t.Skip("unixgram test") + } + for _, laddr := range []string{"", testUnixAddr()} { laddr := laddr taddr := testUnixAddr() ta, err := ResolveUnixAddr("unixgram", taddr) if err != nil { - t.Fatalf("ResolveUnixAddr failed: %v", err) + t.Fatal(err) } c1, err := ListenUnixgram("unixgram", ta) if err != nil { - t.Fatalf("ListenUnixgram failed: %v", err) + t.Fatal(err) } defer func() { c1.Close() @@ -297,12 +370,12 @@ func TestUnixgramConnLocalAndRemoteNames(t *testing.T) { var la *UnixAddr if laddr != "" { if la, err = ResolveUnixAddr("unixgram", laddr); err != nil { - t.Fatalf("ResolveUnixAddr failed: %v", err) + t.Fatal(err) } } c2, err := DialUnix("unixgram", la, ta) if err != nil { - t.Fatalf("DialUnix failed: %v", err) + t.Fatal(err) } defer func() { c2.Close() @@ -326,8 +399,33 @@ func TestUnixgramConnLocalAndRemoteNames(t *testing.T) { } for _, ca := range connAddrs { if !reflect.DeepEqual(ca.got, ca.want) { - t.Fatalf("got %#v, expected %#v", ca.got, ca.want) + t.Fatalf("got %#v; want %#v", ca.got, ca.want) } } } } + +// forceGoDNS forces the resolver configuration to use the pure Go resolver +// and returns a fixup function to restore the old settings. +func forceGoDNS() func() { + c := systemConf() + oldGo := c.netGo + oldCgo := c.netCgo + fixup := func() { + c.netGo = oldGo + c.netCgo = oldCgo + } + c.netGo = true + c.netCgo = false + return fixup +} + +// forceCgoDNS forces the resolver configuration to use the cgo resolver +// and returns true to indicate that it did so. +// (On non-Unix systems forceCgoDNS returns false.) +func forceCgoDNS() bool { + c := systemConf() + c.netGo = false + c.netCgo = true + return true +} diff --git a/libgo/go/net/unixsock.go b/libgo/go/net/unixsock.go index 85955845b80..eb91d0d6309 100644 --- a/libgo/go/net/unixsock.go +++ b/libgo/go/net/unixsock.go @@ -23,7 +23,11 @@ func (a *UnixAddr) String() string { return a.Name } -func (a *UnixAddr) toAddr() Addr { +func (a *UnixAddr) isWildcard() bool { + return a == nil || a.Name == "" +} + +func (a *UnixAddr) opAddr() Addr { if a == nil { return nil } diff --git a/libgo/go/net/unixsock_plan9.go b/libgo/go/net/unixsock_plan9.go index c60c1d83bb3..84b6b600f66 100644 --- a/libgo/go/net/unixsock_plan9.go +++ b/libgo/go/net/unixsock_plan9.go @@ -24,12 +24,12 @@ type UnixConn struct { // Timeout() == true after a fixed time limit; see SetDeadline and // SetReadDeadline. func (c *UnixConn) ReadFromUnix(b []byte) (int, *UnixAddr, error) { - return 0, nil, syscall.EPLAN9 + return 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9} } // ReadFrom implements the PacketConn ReadFrom method. func (c *UnixConn) ReadFrom(b []byte) (int, Addr, error) { - return 0, nil, syscall.EPLAN9 + return 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9} } // ReadMsgUnix reads a packet from c, copying the payload into b and @@ -37,7 +37,7 @@ func (c *UnixConn) ReadFrom(b []byte) (int, Addr, error) { // 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) { - return 0, 0, 0, nil, syscall.EPLAN9 + return 0, 0, 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9} } // WriteToUnix writes a packet to addr via c, copying the payload from b. @@ -47,31 +47,31 @@ func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAdd // SetWriteDeadline. On packet-oriented connections, write timeouts // are rare. func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (int, error) { - return 0, syscall.EPLAN9 + return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr.opAddr(), Err: syscall.EPLAN9} } // WriteTo implements the PacketConn WriteTo method. func (c *UnixConn) WriteTo(b []byte, addr Addr) (int, error) { - return 0, syscall.EPLAN9 + return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr, Err: syscall.EPLAN9} } // 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) { - return 0, 0, syscall.EPLAN9 + return 0, 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr.opAddr(), Err: syscall.EPLAN9} } // CloseRead shuts down the reading side of the Unix domain connection. // Most callers should just use Close. func (c *UnixConn) CloseRead() error { - return syscall.EPLAN9 + return &OpError{Op: "close", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9} } // CloseWrite shuts down the writing side of the Unix domain connection. // Most callers should just use Close. func (c *UnixConn) CloseWrite() error { - return syscall.EPLAN9 + return &OpError{Op: "close", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9} } // DialUnix connects to the remote address raddr on the network net, @@ -82,45 +82,49 @@ func DialUnix(net string, laddr, raddr *UnixAddr) (*UnixConn, error) { } func dialUnix(net string, laddr, raddr *UnixAddr, deadline time.Time) (*UnixConn, error) { - return nil, syscall.EPLAN9 + return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: syscall.EPLAN9} } // UnixListener is a Unix domain socket listener. Clients should // typically use variables of type Listener instead of assuming Unix // domain sockets. -type UnixListener struct{} +type UnixListener struct { + fd *netFD +} // ListenUnix announces on the Unix domain socket laddr and returns a // Unix listener. The network net must be "unix" or "unixpacket". func ListenUnix(net string, laddr *UnixAddr) (*UnixListener, error) { - return nil, syscall.EPLAN9 + return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: syscall.EPLAN9} } // AcceptUnix accepts the next incoming call and returns the new // connection. func (l *UnixListener) AcceptUnix() (*UnixConn, error) { - return nil, syscall.EPLAN9 + return nil, &OpError{Op: "accept", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: syscall.EPLAN9} } // Accept implements the Accept method in the Listener interface; it // waits for the next call and returns a generic Conn. func (l *UnixListener) Accept() (Conn, error) { - return nil, syscall.EPLAN9 + return nil, &OpError{Op: "accept", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: syscall.EPLAN9} } // Close stops listening on the Unix address. Already accepted // connections are not closed. func (l *UnixListener) Close() error { - return syscall.EPLAN9 + return &OpError{Op: "close", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: syscall.EPLAN9} } // Addr returns the listener's network address. +// The Addr returned is shared by all invocations of Addr, so +// do not modify it. func (l *UnixListener) Addr() Addr { return nil } // SetDeadline sets the deadline associated with the listener. // A zero time value disables the deadline. func (l *UnixListener) SetDeadline(t time.Time) error { - return syscall.EPLAN9 + return &OpError{Op: "set", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: syscall.EPLAN9} } // File returns a copy of the underlying os.File, set to blocking @@ -131,7 +135,7 @@ func (l *UnixListener) SetDeadline(t time.Time) error { // connection's. Attempting to change properties of the original // using this duplicate may or may not have the desired effect. func (l *UnixListener) File() (*os.File, error) { - return nil, syscall.EPLAN9 + return nil, &OpError{Op: "file", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: syscall.EPLAN9} } // ListenUnixgram listens for incoming Unix datagram packets addressed @@ -139,5 +143,5 @@ func (l *UnixListener) File() (*os.File, error) { // The returned connection's ReadFrom and WriteTo methods can be used // to receive and send packets with per-packet addressing. func ListenUnixgram(net string, laddr *UnixAddr) (*UnixConn, error) { - return nil, syscall.EPLAN9 + return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: syscall.EPLAN9} } diff --git a/libgo/go/net/unixsock_posix.go b/libgo/go/net/unixsock_posix.go index 3c2e78bdca3..351d9b3a39a 100644 --- a/libgo/go/net/unixsock_posix.go +++ b/libgo/go/net/unixsock_posix.go @@ -87,10 +87,6 @@ func (a *UnixAddr) family() int { return syscall.AF_UNIX } -func (a *UnixAddr) isWildcard() bool { - return a == nil || a.Name == "" -} - func (a *UnixAddr) sockaddr(family int) (syscall.Sockaddr, error) { if a == nil { return nil, nil @@ -113,10 +109,11 @@ func newUnixConn(fd *netFD) *UnixConn { return &UnixConn{conn{fd}} } // ReadFromUnix can be made to time out and return an error with // Timeout() == true after a fixed time limit; see SetDeadline and // SetReadDeadline. -func (c *UnixConn) ReadFromUnix(b []byte) (n int, addr *UnixAddr, err error) { +func (c *UnixConn) ReadFromUnix(b []byte) (int, *UnixAddr, error) { if !c.ok() { return 0, nil, syscall.EINVAL } + var addr *UnixAddr n, sa, err := c.fd.readFrom(b) switch sa := sa.(type) { case *syscall.SockaddrUnix: @@ -124,7 +121,10 @@ func (c *UnixConn) ReadFromUnix(b []byte) (n int, addr *UnixAddr, err error) { addr = &UnixAddr{Name: sa.Name, Net: sotypeToNet(c.fd.sotype)} } } - return + if err != nil { + err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + return n, addr, err } // ReadFrom implements the PacketConn ReadFrom method. @@ -133,7 +133,10 @@ func (c *UnixConn) ReadFrom(b []byte) (int, Addr, error) { return 0, nil, syscall.EINVAL } n, addr, err := c.ReadFromUnix(b) - return n, addr.toAddr(), err + if addr == nil { + return n, nil, err + } + return n, addr, err } // ReadMsgUnix reads a packet from c, copying the payload into b and @@ -151,6 +154,9 @@ func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAdd addr = &UnixAddr{Name: sa.Name, Net: sotypeToNet(c.fd.sotype)} } } + if err != nil { + err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } return } @@ -160,21 +166,25 @@ func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAdd // Timeout() == true after a fixed time limit; see SetDeadline and // SetWriteDeadline. On packet-oriented connections, write timeouts // are rare. -func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (n int, err error) { +func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (int, error) { if !c.ok() { return 0, syscall.EINVAL } if c.fd.isConnected { - return 0, &OpError{Op: "write", Net: c.fd.net, Addr: addr, Err: ErrWriteToConnected} + return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: ErrWriteToConnected} } if addr == nil { - return 0, &OpError{Op: "write", Net: c.fd.net, Addr: nil, Err: errMissingAddress} + return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: nil, Err: errMissingAddress} } if addr.Net != sotypeToNet(c.fd.sotype) { - return 0, syscall.EAFNOSUPPORT + return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: syscall.EAFNOSUPPORT} } sa := &syscall.SockaddrUnix{Name: addr.Name} - return c.fd.writeTo(b, sa) + n, err := c.fd.writeTo(b, sa) + if err != nil { + err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err} + } + return n, err } // WriteTo implements the PacketConn WriteTo method. @@ -184,7 +194,7 @@ func (c *UnixConn) WriteTo(b []byte, addr Addr) (n int, err error) { } a, ok := addr.(*UnixAddr) if !ok { - return 0, &OpError{"write", c.fd.net, addr, syscall.EINVAL} + return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: syscall.EINVAL} } return c.WriteToUnix(b, a) } @@ -197,16 +207,20 @@ func (c *UnixConn) WriteMsgUnix(b, oob []byte, addr *UnixAddr) (n, oobn int, err return 0, 0, syscall.EINVAL } if c.fd.sotype == syscall.SOCK_DGRAM && c.fd.isConnected { - return 0, 0, &OpError{Op: "write", Net: c.fd.net, Addr: addr, Err: ErrWriteToConnected} + return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: ErrWriteToConnected} } + var sa syscall.Sockaddr if addr != nil { if addr.Net != sotypeToNet(c.fd.sotype) { - return 0, 0, syscall.EAFNOSUPPORT + return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: syscall.EAFNOSUPPORT} } - sa := &syscall.SockaddrUnix{Name: addr.Name} - return c.fd.writeMsg(b, oob, sa) + sa = &syscall.SockaddrUnix{Name: addr.Name} } - return c.fd.writeMsg(b, oob, nil) + n, oobn, err = c.fd.writeMsg(b, oob, sa) + if err != nil { + err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err} + } + return } // CloseRead shuts down the reading side of the Unix domain connection. @@ -215,7 +229,11 @@ func (c *UnixConn) CloseRead() error { if !c.ok() { return syscall.EINVAL } - return c.fd.closeRead() + err := c.fd.closeRead() + if err != nil { + err = &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + return err } // CloseWrite shuts down the writing side of the Unix domain connection. @@ -224,7 +242,11 @@ func (c *UnixConn) CloseWrite() error { if !c.ok() { return syscall.EINVAL } - return c.fd.closeWrite() + err := c.fd.closeWrite() + if err != nil { + err = &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err} + } + return err } // DialUnix connects to the remote address raddr on the network net, @@ -234,7 +256,7 @@ func DialUnix(net string, laddr, raddr *UnixAddr) (*UnixConn, error) { switch net { case "unix", "unixgram", "unixpacket": default: - return nil, &OpError{Op: "dial", Net: net, Addr: raddr, Err: UnknownNetworkError(net)} + return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(net)} } return dialUnix(net, laddr, raddr, noDeadline) } @@ -242,7 +264,7 @@ func DialUnix(net string, laddr, raddr *UnixAddr) (*UnixConn, error) { func dialUnix(net string, laddr, raddr *UnixAddr, deadline time.Time) (*UnixConn, error) { fd, err := unixSocket(net, laddr, raddr, "dial", deadline) if err != nil { - return nil, &OpError{Op: "dial", Net: net, Addr: raddr, Err: err} + return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err} } return newUnixConn(fd), nil } @@ -261,16 +283,16 @@ func ListenUnix(net string, laddr *UnixAddr) (*UnixListener, error) { switch net { case "unix", "unixpacket": default: - return nil, &OpError{Op: "listen", Net: net, Addr: laddr, Err: UnknownNetworkError(net)} + return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(net)} } if laddr == nil { - return nil, &OpError{Op: "listen", Net: net, Addr: nil, Err: errMissingAddress} + return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: errMissingAddress} } fd, err := unixSocket(net, laddr, nil, "listen", noDeadline) if err != nil { - return nil, &OpError{Op: "listen", Net: net, Addr: laddr, Err: err} + return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: err} } - return &UnixListener{fd, fd.laddr.String()}, nil + return &UnixListener{fd: fd, path: fd.laddr.String()}, nil } // AcceptUnix accepts the next incoming call and returns the new @@ -281,10 +303,9 @@ func (l *UnixListener) AcceptUnix() (*UnixConn, error) { } fd, err := l.fd.accept() if err != nil { - return nil, err + return nil, &OpError{Op: "accept", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err} } - c := newUnixConn(fd) - return c, nil + return newUnixConn(fd), nil } // Accept implements the Accept method in the Listener interface; it @@ -317,19 +338,28 @@ func (l *UnixListener) Close() error { if l.path[0] != '@' { syscall.Unlink(l.path) } - return l.fd.Close() + err := l.fd.Close() + if err != nil { + err = &OpError{Op: "close", Net: l.fd.net, Source: l.fd.laddr, Addr: l.fd.raddr, Err: err} + } + return err } // Addr returns the listener's network address. +// The Addr returned is shared by all invocations of Addr, so +// do not modify it. func (l *UnixListener) Addr() Addr { return l.fd.laddr } // SetDeadline sets the deadline associated with the listener. // A zero time value disables the deadline. -func (l *UnixListener) SetDeadline(t time.Time) (err error) { +func (l *UnixListener) SetDeadline(t time.Time) error { if l == nil || l.fd == nil { return syscall.EINVAL } - return l.fd.setDeadline(t) + if err := l.fd.setDeadline(t); err != nil { + return &OpError{Op: "set", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err} + } + return nil } // File returns a copy of the underlying os.File, set to blocking @@ -339,7 +369,13 @@ func (l *UnixListener) SetDeadline(t time.Time) (err error) { // The returned os.File's file descriptor is different from the // connection's. Attempting to change properties of the original // using this duplicate may or may not have the desired effect. -func (l *UnixListener) File() (f *os.File, err error) { return l.fd.dup() } +func (l *UnixListener) File() (f *os.File, err error) { + f, err = l.fd.dup() + if err != nil { + err = &OpError{Op: "file", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err} + } + return +} // ListenUnixgram listens for incoming Unix datagram packets addressed // to the local address laddr. The network net must be "unixgram". @@ -349,14 +385,14 @@ func ListenUnixgram(net string, laddr *UnixAddr) (*UnixConn, error) { switch net { case "unixgram": default: - return nil, &OpError{Op: "listen", Net: net, Addr: laddr, Err: UnknownNetworkError(net)} + return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(net)} } if laddr == nil { - return nil, &OpError{Op: "listen", Net: net, Addr: nil, Err: errMissingAddress} + return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: nil, Err: errMissingAddress} } fd, err := unixSocket(net, laddr, nil, "listen", noDeadline) if err != nil { - return nil, &OpError{Op: "listen", Net: net, Addr: laddr, Err: err} + return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: err} } return newUnixConn(fd), nil } diff --git a/libgo/go/net/url/url.go b/libgo/go/net/url/url.go index f167408faba..8ffad663d5c 100644 --- a/libgo/go/net/url/url.go +++ b/libgo/go/net/url/url.go @@ -9,6 +9,7 @@ package url import ( "bytes" "errors" + "fmt" "sort" "strconv" "strings" @@ -51,6 +52,7 @@ type encoding int const ( encodePath encoding = 1 + iota + encodeHost encodeUserPassword encodeQueryComponent encodeFragment @@ -64,12 +66,27 @@ func (e EscapeError) Error() string { // Return true if the specified character should be escaped when // appearing in a URL string, according to RFC 3986. +// +// Please be informed that for now shouldEscape does not check all +// reserved characters correctly. See golang.org/issue/5684. func shouldEscape(c byte, mode encoding) bool { // §2.3 Unreserved characters (alphanum) if 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' { return false } + if mode == encodeHost { + // §3.2.2 Host allows + // sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "=" + // as part of reg-name. + // We add : because we include :port as part of host. + // We add [ ] because we include [ipv6]:port as part of host + switch c { + case '!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '=', ':', '[', ']': + return false + } + } + switch c { case '-', '_', '.', '~': // §2.3 Unreserved characters (mark) return false @@ -127,7 +144,7 @@ func unescape(s string, mode encoding) (string, error) { if i+2 >= len(s) || !ishex(s[i+1]) || !ishex(s[i+2]) { s = s[i:] if len(s) > 3 { - s = s[0:3] + s = s[:3] } return "", EscapeError(s) } @@ -224,16 +241,24 @@ func escape(s string, mode encoding) string { // Note that the Path field is stored in decoded form: /%47%6f%2f becomes /Go/. // A consequence is that it is impossible to tell which slashes in the Path were // slashes in the raw URL and which were %2f. This distinction is rarely important, -// but when it is a client must use other routines to parse the raw URL or construct -// the parsed URL. For example, an HTTP server can consult req.RequestURI, and -// an HTTP client can use URL{Host: "example.com", Opaque: "//example.com/Go%2f"} -// instead of URL{Host: "example.com", Path: "/Go/"}. +// but when it is, code must not use Path directly. +// +// Go 1.5 introduced the RawPath field to hold the encoded form of Path. +// The Parse function sets both Path and RawPath in the URL it returns, +// and URL's String method uses RawPath if it is a valid encoding of Path, +// by calling the EncodedPath method. +// +// In earlier versions of Go, the more indirect workarounds were that an +// HTTP server could consult req.RequestURI and an HTTP client could +// construct a URL struct directly and set the Opaque field instead of Path. +// These still work as well. type URL struct { Scheme string Opaque string // encoded opaque data User *Userinfo // username and password information Host string // host or host:port Path string + RawPath string // encoded path hint (Go 1.5 and later only; see EscapedPath method) RawQuery string // encoded query values, without '?' Fragment string // fragment for references, without '#' } @@ -305,7 +330,7 @@ func getscheme(rawurl string) (scheme, path string, err error) { if i == 0 { return "", "", errors.New("missing protocol scheme") } - return rawurl[0:i], rawurl[i+1:], nil + return rawurl[:i], rawurl[i+1:], nil default: // we have encountered an invalid character, // so there is no valid scheme @@ -324,9 +349,9 @@ func split(s string, c string, cutc bool) (string, string) { return s, "" } if cutc { - return s[0:i], s[i+len(c):] + return s[:i], s[i+len(c):] } - return s[0:i], s[i:] + return s[:i], s[i:] } // Parse parses rawurl into a URL structure. @@ -401,14 +426,17 @@ func parse(rawurl string, viaRequest bool) (url *URL, err error) { if err != nil { goto Error } - if strings.Contains(url.Host, "%") { - err = errors.New("hexadecimal escape in host") - goto Error - } } if url.Path, err = unescape(rest, encodePath); err != nil { goto Error } + // RawPath is a hint as to the encoding of Path to use + // in url.EncodedPath. If that method already gets the + // right answer without RawPath, leave it empty. + // This will help make sure that people don't rely on it in general. + if url.EscapedPath() != rest && validEncodedPath(rest) { + url.RawPath = rest + } return url, nil Error: @@ -418,36 +446,157 @@ Error: func parseAuthority(authority string) (user *Userinfo, host string, err error) { i := strings.LastIndex(authority, "@") if i < 0 { - host = authority - return + host, err = parseHost(authority) + } else { + host, err = parseHost(authority[i+1:]) } - userinfo, host := authority[:i], authority[i+1:] + if err != nil { + return nil, "", err + } + if i < 0 { + return nil, host, nil + } + userinfo := authority[:i] if strings.Index(userinfo, ":") < 0 { if userinfo, err = unescape(userinfo, encodeUserPassword); err != nil { - return + return nil, "", err } user = User(userinfo) } else { username, password := split(userinfo, ":", true) if username, err = unescape(username, encodeUserPassword); err != nil { - return + return nil, "", err } if password, err = unescape(password, encodeUserPassword); err != nil { - return + return nil, "", err } user = UserPassword(username, password) } - return + return user, host, nil +} + +// parseHost parses host as an authority without user +// information. That is, as host[:port]. +func parseHost(host string) (string, error) { + litOrName := host + if strings.HasPrefix(host, "[") { + // Parse an IP-Literal in RFC 3986 and RFC 6874. + // E.g., "[fe80::1], "[fe80::1%25en0]" + // + // RFC 4007 defines "%" as a delimiter character in + // the textual representation of IPv6 addresses. + // Per RFC 6874, in URIs that "%" is encoded as "%25". + i := strings.LastIndex(host, "]") + if i < 0 { + return "", errors.New("missing ']' in host") + } + colonPort := host[i+1:] + if !validOptionalPort(colonPort) { + return "", fmt.Errorf("invalid port %q after host", colonPort) + } + // Parse a host subcomponent without a ZoneID in RFC + // 6874 because the ZoneID is allowed to use the + // percent encoded form. + j := strings.Index(host[:i], "%25") + if j < 0 { + litOrName = host[1:i] + } else { + litOrName = host[1:j] + } + } + + // A URI containing an IP-Literal without a ZoneID or + // IPv4address in RFC 3986 and RFC 6847 must not be + // percent-encoded. + // + // A URI containing a DNS registered name in RFC 3986 is + // allowed to be percent-encoded, though we don't use it for + // now to avoid messing up with the gap between allowed + // characters in URI and allowed characters in DNS. + // See golang.org/issue/7991. + if strings.Contains(litOrName, "%") { + return "", errors.New("percent-encoded characters in host") + } + var err error + if host, err = unescape(host, encodeHost); err != nil { + return "", err + } + return host, nil +} + +// EscapedPath returns the escaped form of u.Path. +// In general there are multiple possible escaped forms of any path. +// EscapedPath returns u.RawPath when it is a valid escaping of u.Path. +// Otherwise EscapedPath ignores u.RawPath and computes an escaped +// form on its own. +// The String and RequestURI methods use EscapedPath to construct +// their results. +// In general, code should call EscapedPath instead of +// reading u.RawPath directly. +func (u *URL) EscapedPath() string { + if u.RawPath != "" && validEncodedPath(u.RawPath) { + p, err := unescape(u.RawPath, encodePath) + if err == nil && p == u.Path { + return u.RawPath + } + } + if u.Path == "*" { + return "*" // don't escape (Issue 11202) + } + return escape(u.Path, encodePath) +} + +// validEncodedPath reports whether s is a valid encoded path. +// It must not contain any bytes that require escaping during path encoding. +func validEncodedPath(s string) bool { + for i := 0; i < len(s); i++ { + // RFC 3986, Appendix A. + // pchar = unreserved / pct-encoded / sub-delims / ":" / "@". + // shouldEscape is not quite compliant with the RFC, + // so we check the sub-delims ourselves and let + // shouldEscape handle the others. + switch s[i] { + case '!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '=', ':', '@': + // ok + case '[', ']': + // ok - not specified in RFC 3986 but left alone by modern browsers + case '%': + // ok - percent encoded, will decode + default: + if shouldEscape(s[i], encodePath) { + return false + } + } + } + return true +} + +// validOptionalPort reports whether port is either an empty string +// or matches /^:\d+$/ +func validOptionalPort(port string) bool { + if port == "" { + return true + } + if port[0] != ':' || len(port) == 1 { + return false + } + for _, b := range port[1:] { + if b < '0' || b > '9' { + return false + } + } + return true } // String reassembles the URL into a valid URL string. // The general form of the result is one of: // -// scheme:opaque +// scheme:opaque?query#fragment // scheme://userinfo@host/path?query#fragment // // If u.Opaque is non-empty, String uses the first form; // otherwise it uses the second form. +// To obtain the path, String uses u.EncodedPath(). // // In the second form, the following rules apply: // - if u.Scheme is empty, scheme: is omitted. @@ -475,13 +624,14 @@ func (u *URL) String() string { buf.WriteByte('@') } if h := u.Host; h != "" { - buf.WriteString(h) + buf.WriteString(escape(h, encodeHost)) } } - if u.Path != "" && u.Path[0] != '/' && u.Host != "" { + path := u.EscapedPath() + if path != "" && path[0] != '/' && u.Host != "" { buf.WriteByte('/') } - buf.WriteString(escape(u.Path, encodePath)) + buf.WriteString(path) } if u.RawQuery != "" { buf.WriteByte('?') @@ -639,7 +789,7 @@ func resolvePath(base, ref string) string { return "/" + strings.TrimLeft(strings.Join(dst, "/"), "/") } -// IsAbs returns true if the URL is absolute. +// IsAbs reports whether the URL is absolute. func (u *URL) IsAbs() bool { return u.Scheme != "" } @@ -703,7 +853,7 @@ func (u *URL) Query() Values { func (u *URL) RequestURI() string { result := u.Opaque if result == "" { - result = escape(u.Path, encodePath) + result = u.EscapedPath() if result == "" { result = "/" } diff --git a/libgo/go/net/url/url_test.go b/libgo/go/net/url/url_test.go index d8b19d805d0..ff6e9e4541a 100644 --- a/libgo/go/net/url/url_test.go +++ b/libgo/go/net/url/url_test.go @@ -13,7 +13,7 @@ import ( type URLTest struct { in string - out *URL + out *URL // expected parse; RawPath="" means same as Path roundtrip string // expected result of reserializing the URL; empty means same as "in". } @@ -41,11 +41,12 @@ var urltests = []URLTest{ { "http://www.google.com/file%20one%26two", &URL{ - Scheme: "http", - Host: "www.google.com", - Path: "/file one&two", + Scheme: "http", + Host: "www.google.com", + Path: "/file one&two", + RawPath: "/file%20one%26two", }, - "http://www.google.com/file%20one&two", + "", }, // user { @@ -289,6 +290,140 @@ var urltests = []URLTest{ }, "", }, + // host subcomponent; IPv4 address in RFC 3986 + { + "http://192.168.0.1/", + &URL{ + Scheme: "http", + Host: "192.168.0.1", + Path: "/", + }, + "", + }, + // host and port subcomponents; IPv4 address in RFC 3986 + { + "http://192.168.0.1:8080/", + &URL{ + Scheme: "http", + Host: "192.168.0.1:8080", + Path: "/", + }, + "", + }, + // host subcomponent; IPv6 address in RFC 3986 + { + "http://[fe80::1]/", + &URL{ + Scheme: "http", + Host: "[fe80::1]", + Path: "/", + }, + "", + }, + // host and port subcomponents; IPv6 address in RFC 3986 + { + "http://[fe80::1]:8080/", + &URL{ + Scheme: "http", + Host: "[fe80::1]:8080", + Path: "/", + }, + "", + }, + // host subcomponent; IPv6 address with zone identifier in RFC 6847 + { + "http://[fe80::1%25en0]/", // alphanum zone identifier + &URL{ + Scheme: "http", + Host: "[fe80::1%en0]", + Path: "/", + }, + "", + }, + // host and port subcomponents; IPv6 address with zone identifier in RFC 6847 + { + "http://[fe80::1%25en0]:8080/", // alphanum zone identifier + &URL{ + Scheme: "http", + Host: "[fe80::1%en0]:8080", + Path: "/", + }, + "", + }, + // host subcomponent; IPv6 address with zone identifier in RFC 6847 + { + "http://[fe80::1%25%65%6e%301-._~]/", // percent-encoded+unreserved zone identifier + &URL{ + Scheme: "http", + Host: "[fe80::1%en01-._~]", + Path: "/", + }, + "http://[fe80::1%25en01-._~]/", + }, + // host and port subcomponents; IPv6 address with zone identifier in RFC 6847 + { + "http://[fe80::1%25%65%6e%301-._~]:8080/", // percent-encoded+unreserved zone identifier + &URL{ + Scheme: "http", + Host: "[fe80::1%en01-._~]:8080", + Path: "/", + }, + "http://[fe80::1%25en01-._~]:8080/", + }, + // alternate escapings of path survive round trip + { + "http://rest.rsc.io/foo%2fbar/baz%2Fquux?alt=media", + &URL{ + Scheme: "http", + Host: "rest.rsc.io", + Path: "/foo/bar/baz/quux", + RawPath: "/foo%2fbar/baz%2Fquux", + RawQuery: "alt=media", + }, + "", + }, + // issue 12036 + { + "mysql://a,b,c/bar", + &URL{ + Scheme: "mysql", + Host: "a,b,c", + Path: "/bar", + }, + "", + }, + // worst case host, still round trips + { + "scheme://!$&'()*+,;=hello!:port/path", + &URL{ + Scheme: "scheme", + Host: "!$&'()*+,;=hello!:port", + Path: "/path", + }, + "", + }, + // worst case path, still round trips + { + "http://host/!$&'()*+,;=:@[hello]", + &URL{ + Scheme: "http", + Host: "host", + Path: "/!$&'()*+,;=:@[hello]", + RawPath: "/!$&'()*+,;=:@[hello]", + }, + "", + }, + // golang.org/issue/5684 + { + "http://example.com/oid/[order_id]", + &URL{ + Scheme: "http", + Host: "example.com", + Path: "/oid/[order_id]", + RawPath: "/oid/[order_id]", + }, + "", + }, } // more useful string for debugging than fmt's struct printer @@ -300,8 +435,8 @@ func ufmt(u *URL) string { pass = p } } - return fmt.Sprintf("opaque=%q, scheme=%q, user=%#v, pass=%#v, host=%q, path=%q, rawq=%q, frag=%q", - u.Opaque, u.Scheme, user, pass, u.Host, u.Path, u.RawQuery, u.Fragment) + return fmt.Sprintf("opaque=%q, scheme=%q, user=%#v, pass=%#v, host=%q, path=%q, rawpath=%q, rawq=%q, frag=%q", + u.Opaque, u.Scheme, user, pass, u.Host, u.Path, u.RawPath, u.RawQuery, u.Fragment) } func DoTest(t *testing.T, parse func(string) (*URL, error), name string, tests []URLTest) { @@ -358,9 +493,33 @@ var parseRequestURLTests = []struct { {"/", true}, {pathThatLooksSchemeRelative, true}, {"//not.a.user@%66%6f%6f.com/just/a/path/also", true}, + {"*", true}, + {"http://192.168.0.1/", true}, + {"http://192.168.0.1:8080/", true}, + {"http://[fe80::1]/", true}, + {"http://[fe80::1]:8080/", true}, + + // Tests exercising RFC 6874 compliance: + {"http://[fe80::1%25en0]/", true}, // with alphanum zone identifier + {"http://[fe80::1%25en0]:8080/", true}, // with alphanum zone identifier + {"http://[fe80::1%25%65%6e%301-._~]/", true}, // with percent-encoded+unreserved zone identifier + {"http://[fe80::1%25%65%6e%301-._~]:8080/", true}, // with percent-encoded+unreserved zone identifier + {"foo.html", false}, {"../dir/", false}, - {"*", true}, + {"http://192.168.0.%31/", false}, + {"http://192.168.0.%31:8080/", false}, + {"http://[fe80::%31]/", false}, + {"http://[fe80::%31]:8080/", false}, + {"http://[fe80::%31%25en0]/", false}, + {"http://[fe80::%31%25en0]:8080/", false}, + + // These two cases are valid as textual representations as + // described in RFC 4007, but are not valid as address + // literals with IPv6 zone identifiers in URIs as described in + // RFC 6874. + {"http://[fe80::1%en0]/", false}, + {"http://[fe80::1%en0]:8080/", false}, } func TestParseRequestURI(t *testing.T) { @@ -869,6 +1028,25 @@ var requritests = []RequestURITest{ }, "http://other.example.com/%2F/%2F/", }, + // better fix for issue 4860 + { + &URL{ + Scheme: "http", + Host: "example.com", + Path: "/////", + RawPath: "/%2F/%2F/", + }, + "/%2F/%2F/", + }, + { + &URL{ + Scheme: "http", + Host: "example.com", + Path: "/////", + RawPath: "/WRONG/", // ignored because doesn't match Path + }, + "/////", + }, { &URL{ Scheme: "http", @@ -878,6 +1056,26 @@ var requritests = []RequestURITest{ }, "/a%20b?q=go+language", }, + { + &URL{ + Scheme: "http", + Host: "example.com", + Path: "/a b", + RawPath: "/a b", // ignored because invalid + RawQuery: "q=go+language", + }, + "/a%20b?q=go+language", + }, + { + &URL{ + Scheme: "http", + Host: "example.com", + Path: "/a?b", + RawPath: "/a?b", // ignored because invalid + RawQuery: "q=go+language", + }, + "/a%3Fb?q=go+language", + }, { &URL{ Scheme: "myschema", @@ -914,6 +1112,54 @@ func TestParseFailure(t *testing.T) { } } +func TestParseAuthority(t *testing.T) { + tests := []struct { + in string + wantErr bool + }{ + {"http://[::1]", false}, + {"http://[::1]:80", false}, + {"http://[::1]:namedport", true}, // rfc3986 3.2.3 + {"http://[::1]/", false}, + {"http://[::1]a", true}, + {"http://[::1]%23", true}, + {"http://[::1%25en0]", false}, // valid zone id + {"http://[::1]:", true}, // colon, but no port + {"http://[::1]:%38%30", true}, // no hex in port + {"http://[::1%25%10]", false}, // TODO: reject the %10 after the valid zone %25 separator? + {"http://[%10::1]", true}, // no %xx escapes in IP address + {"http://[::1]/%48", false}, // %xx in path is fine + {"http://%41:8080/", true}, // TODO: arguably we should accept reg-name with %xx + {"mysql://x@y(z:123)/foo", false}, // golang.org/issue/12023 + {"mysql://x@y(1.2.3.4:123)/foo", false}, + {"mysql://x@y([2001:db8::1]:123)/foo", false}, + {"http://[]%20%48%54%54%50%2f%31%2e%31%0a%4d%79%48%65%61%64%65%72%3a%20%31%32%33%0a%0a/", true}, // golang.org/issue/11208 + } + for _, tt := range tests { + u, err := Parse(tt.in) + if tt.wantErr { + if err == nil { + t.Errorf("Parse(%q) = %#v; want an error", tt.in, u) + } + continue + } + if err != nil { + t.Logf("Parse(%q) = %v; want no error", tt.in, err) + } + } +} + +// Issue 11202 +func TestStarRequest(t *testing.T) { + u, err := Parse("*") + if err != nil { + t.Fatal(err) + } + if got, want := u.RequestURI(), "*"; got != want { + t.Errorf("RequestURI = %q; want %q", got, want) + } +} + type shouldEscapeTest struct { in byte mode encoding @@ -926,6 +1172,7 @@ var shouldEscapeTests = []shouldEscapeTest{ {'a', encodeUserPassword, false}, {'a', encodeQueryComponent, false}, {'a', encodeFragment, false}, + {'a', encodeHost, false}, {'z', encodePath, false}, {'A', encodePath, false}, {'Z', encodePath, false}, @@ -950,6 +1197,29 @@ var shouldEscapeTests = []shouldEscapeTest{ {',', encodeUserPassword, false}, {';', encodeUserPassword, false}, {'=', encodeUserPassword, false}, + + // Host (IP address, IPv6 address, registered name, port suffix; §3.2.2) + {'!', encodeHost, false}, + {'$', encodeHost, false}, + {'&', encodeHost, false}, + {'\'', encodeHost, false}, + {'(', encodeHost, false}, + {')', encodeHost, false}, + {'*', encodeHost, false}, + {'+', encodeHost, false}, + {',', encodeHost, false}, + {';', encodeHost, false}, + {'=', encodeHost, false}, + {':', encodeHost, false}, + {'[', encodeHost, false}, + {']', encodeHost, false}, + {'0', encodeHost, false}, + {'9', encodeHost, false}, + {'A', encodeHost, false}, + {'z', encodeHost, false}, + {'_', encodeHost, false}, + {'-', encodeHost, false}, + {'.', encodeHost, false}, } func TestShouldEscape(t *testing.T) { diff --git a/libgo/go/net/z_last_test.go b/libgo/go/net/z_last_test.go deleted file mode 100644 index 716c103db26..00000000000 --- a/libgo/go/net/z_last_test.go +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package net - -import ( - "flag" - "fmt" - "testing" - "time" -) - -var testDNSFlood = flag.Bool("dnsflood", false, "whether to test dns query flooding") - -func TestDNSThreadLimit(t *testing.T) { - if !*testDNSFlood { - t.Skip("test disabled; use -dnsflood to enable") - } - - const N = 10000 - c := make(chan int, N) - for i := 0; i < N; i++ { - go func(i int) { - LookupIP(fmt.Sprintf("%d.net-test.golang.org", i)) - c <- 1 - }(i) - } - // Don't bother waiting for the stragglers; stop at 0.9 N. - for i := 0; i < N*9/10; i++ { - if i%100 == 0 { - //println("TestDNSThreadLimit:", i) - } - <-c - } - - // If we're still here, it worked. -} - -func TestLookupIPDeadline(t *testing.T) { - if !*testDNSFlood { - t.Skip("test disabled; use -dnsflood to enable") - } - - const N = 5000 - const timeout = 3 * time.Second - c := make(chan error, 2*N) - for i := 0; i < N; i++ { - name := fmt.Sprintf("%d.net-test.golang.org", i) - go func() { - _, err := lookupIPDeadline(name, time.Now().Add(timeout/2)) - c <- err - }() - go func() { - _, err := lookupIPDeadline(name, time.Now().Add(timeout)) - c <- err - }() - } - qstats := struct { - succeeded, failed int - timeout, temporary, other int - unknown int - }{} - deadline := time.After(timeout + time.Second) - for i := 0; i < 2*N; i++ { - select { - case <-deadline: - t.Fatal("deadline exceeded") - case err := <-c: - switch err := err.(type) { - case nil: - qstats.succeeded++ - case Error: - qstats.failed++ - if err.Timeout() { - qstats.timeout++ - } - if err.Temporary() { - qstats.temporary++ - } - if !err.Timeout() && !err.Temporary() { - qstats.other++ - } - default: - qstats.failed++ - qstats.unknown++ - } - } - } - - // A high volume of DNS queries for sub-domain of golang.org - // would be coordinated by authoritative or recursive server, - // or stub resolver which implements query-response rate - // limitation, so we can expect some query successes and more - // failures including timeout, temporary and other here. - // As a rule, unknown must not be shown but it might possibly - // happen due to issue 4856 for now. - t.Logf("%v succeeded, %v failed (%v timeout, %v temporary, %v other, %v unknown)", qstats.succeeded, qstats.failed, qstats.timeout, qstats.temporary, qstats.other, qstats.unknown) -} diff --git a/libgo/go/os/env.go b/libgo/go/os/env.go index d0494a47634..a4ede15e613 100644 --- a/libgo/go/os/env.go +++ b/libgo/go/os/env.go @@ -33,7 +33,7 @@ func ExpandEnv(s string) string { return Expand(s, Getenv) } -// isSpellSpecialVar reports whether the character identifies a special +// isShellSpecialVar reports whether the character identifies a special // shell variable such as $*. func isShellSpecialVar(c uint8) bool { switch c { @@ -48,7 +48,7 @@ func isAlphaNum(c uint8) bool { return c == '_' || '0' <= c && c <= '9' || 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z' } -// getName returns the name that begins the string and the number of bytes +// getShellName returns the name that begins the string and the number of bytes // consumed to extract it. If the name is enclosed in {}, it's part of a ${} // expansion and two more bytes are needed than the length of the name. func getShellName(s string) (string, int) { @@ -81,6 +81,15 @@ func Getenv(key string) string { return v } +// LookupEnv retrieves the value of the environment variable named +// by the key. If the variable is present in the environment the +// value (which may be empty) is returned and the boolean is true. +// Otherwise the returned value will be empty and the boolean will +// be false. +func LookupEnv(key string) (string, bool) { + return syscall.Getenv(key) +} + // Setenv sets the value of the environment variable named by the key. // It returns an error, if any. func Setenv(key, value string) error { diff --git a/libgo/go/os/env_test.go b/libgo/go/os/env_test.go index e6180675137..d1074cdc60a 100644 --- a/libgo/go/os/env_test.go +++ b/libgo/go/os/env_test.go @@ -94,3 +94,20 @@ func TestUnsetenv(t *testing.T) { t.Fatal("Unsetenv didn't clear TestUnsetenv") } } + +func TestLookupEnv(t *testing.T) { + const smallpox = "SMALLPOX" // No one has smallpox. + value, ok := LookupEnv(smallpox) // Should not exist. + if ok || value != "" { + t.Fatalf("%s=%q", smallpox, value) + } + defer Unsetenv(smallpox) + err := Setenv(smallpox, "virus") + if err != nil { + t.Fatalf("failed to release smallpox virus") + } + value, ok = LookupEnv(smallpox) + if !ok { + t.Errorf("smallpox release failed; world remains safe but LookupEnv is broken") + } +} diff --git a/libgo/go/os/exec.go b/libgo/go/os/exec.go index 5aea3098b54..15e95b91722 100644 --- a/libgo/go/os/exec.go +++ b/libgo/go/os/exec.go @@ -13,8 +13,8 @@ import ( // Process stores the information about a process created by StartProcess. type Process struct { Pid int - handle uintptr - isdone uint32 // process has been successfully waited on, non zero if true + handle uintptr // handle is accessed atomically on Windows + isdone uint32 // process has been successfully waited on, non zero if true } func newProcess(pid int, handle uintptr) *Process { diff --git a/libgo/go/os/exec/exec.go b/libgo/go/os/exec/exec.go index 72b4905d560..8a84e263dc8 100644 --- a/libgo/go/os/exec/exec.go +++ b/libgo/go/os/exec/exec.go @@ -32,6 +32,9 @@ func (e *Error) Error() string { } // Cmd represents an external command being prepared or run. +// +// A Cmd cannot be reused after calling its Run, Output or CombinedOutput +// methods. type Cmd struct { // Path is the path of the command to run. // @@ -80,8 +83,8 @@ type Cmd struct { // new process. It does not include standard input, standard output, or // standard error. If non-nil, entry i becomes file descriptor 3+i. // - // BUG: on OS X 10.6, child processes may sometimes inherit unwanted fds. - // http://golang.org/issue/2603 + // BUG(rsc): On OS X 10.6, child processes may sometimes inherit unwanted fds. + // https://golang.org/issue/2603 ExtraFiles []*os.File // SysProcAttr holds optional, operating system-specific attributes. @@ -154,6 +157,11 @@ func (c *Cmd) argv() []string { return []string{c.Path} } +// skipStdinCopyError optionally specifies a function which reports +// whether the provided the stdin copy error should be ignored. +// It is non-nil everywhere but Plan 9, which lacks EPIPE. See exec_posix.go. +var skipStdinCopyError func(error) bool + func (c *Cmd) stdin() (f *os.File, err error) { if c.Stdin == nil { f, err = os.Open(os.DevNull) @@ -177,6 +185,9 @@ func (c *Cmd) stdin() (f *os.File, err error) { c.closeAfterWait = append(c.closeAfterWait, pw) c.goroutine = append(c.goroutine, func() error { _, err := io.Copy(pw, c.Stdin) + if skip := skipStdinCopyError; skip != nil && skip(err) { + err = nil + } if err1 := pw.Close(); err == nil { err = err1 } @@ -219,6 +230,7 @@ func (c *Cmd) writerDescriptor(w io.Writer) (f *os.File, err error) { c.closeAfterWait = append(c.closeAfterWait, pr) c.goroutine = append(c.goroutine, func() error { _, err := io.Copy(w, pr) + pr.Close() // in case io.Copy stopped due to write error return err }) return pw, nil @@ -352,6 +364,10 @@ func (e *ExitError) Error() string { // error is of type *ExitError. Other error types may be // returned for I/O problems. // +// If c.Stdin is not an *os.File, Wait also waits for the I/O loop +// copying from c.Stdin into the process's standard input +// to complete. +// // Wait releases any resources associated with the Cmd. func (c *Cmd) Wait() error { if c.Process == nil { diff --git a/libgo/go/os/exec/exec_posix.go b/libgo/go/os/exec/exec_posix.go new file mode 100644 index 00000000000..5e1113748cd --- /dev/null +++ b/libgo/go/os/exec/exec_posix.go @@ -0,0 +1,24 @@ +// Copyright 2015 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 !plan9 + +package exec + +import ( + "os" + "syscall" +) + +func init() { + skipStdinCopyError = func(err error) bool { + // Ignore EPIPE errors copying to stdin if the program + // completed successfully otherwise. + // See Issue 9173. + pe, ok := err.(*os.PathError) + return ok && + pe.Op == "write" && pe.Path == "|1" && + pe.Err == syscall.EPIPE + } +} diff --git a/libgo/go/os/exec/exec_test.go b/libgo/go/os/exec/exec_test.go index f9ffde602ca..f4c025e839f 100644 --- a/libgo/go/os/exec/exec_test.go +++ b/libgo/go/os/exec/exec_test.go @@ -11,6 +11,7 @@ import ( "bufio" "bytes" "fmt" + "internal/testenv" "io" "io/ioutil" "log" @@ -28,9 +29,8 @@ import ( ) func helperCommand(t *testing.T, s ...string) *exec.Cmd { - if runtime.GOOS == "nacl" { - t.Skip("skipping on nacl") - } + testenv.MustHaveExec(t) + cs := []string{"-test.run=TestHelperProcess", "--"} cs = append(cs, s...) cmd := exec.Command(os.Args[0], cs...) @@ -53,6 +53,8 @@ func TestEcho(t *testing.T) { } func TestCommandRelativeName(t *testing.T) { + testenv.MustHaveExec(t) + // Run our own binary as a relative path // (e.g. "_test/exec.test") our parent directory. base := filepath.Base(os.Args[0]) // "exec.test" @@ -250,6 +252,12 @@ func TestPipeLookPathLeak(t *testing.T) { } func numOpenFDS(t *testing.T) (n int, lsof []byte) { + if runtime.GOOS == "android" { + // Android's stock lsof does not obey the -p option, + // so extra filtering is needed. (golang.org/issue/10206) + return numOpenFDsAndroid(t) + } + lsof, err := exec.Command("lsof", "-b", "-n", "-p", strconv.Itoa(os.Getpid())).Output() if err != nil { t.Skip("skipping test; error finding or running lsof") @@ -257,6 +265,45 @@ func numOpenFDS(t *testing.T) (n int, lsof []byte) { return bytes.Count(lsof, []byte("\n")), lsof } +func numOpenFDsAndroid(t *testing.T) (n int, lsof []byte) { + raw, err := exec.Command("lsof").Output() + if err != nil { + t.Skip("skipping test; error finding or running lsof") + } + + // First find the PID column index by parsing the first line, and + // select lines containing pid in the column. + pid := []byte(strconv.Itoa(os.Getpid())) + pidCol := -1 + + s := bufio.NewScanner(bytes.NewReader(raw)) + for s.Scan() { + line := s.Bytes() + fields := bytes.Fields(line) + if pidCol < 0 { + for i, v := range fields { + if bytes.Equal(v, []byte("PID")) { + pidCol = i + break + } + } + lsof = append(lsof, line...) + continue + } + if bytes.Equal(fields[pidCol], pid) { + lsof = append(lsof, '\n') + lsof = append(lsof, line...) + } + } + if pidCol < 0 { + t.Fatal("error processing lsof output: unexpected header format") + } + if err := s.Err(); err != nil { + t.Fatalf("error processing lsof output: %v", err) + } + return bytes.Count(lsof, []byte("\n")), lsof +} + var testedAlreadyLeaked = false // basefds returns the number of expected file descriptors @@ -275,15 +322,15 @@ func closeUnexpectedFds(t *testing.T, m string) { } func TestExtraFilesFDShuffle(t *testing.T) { - t.Skip("flaky test; see http://golang.org/issue/5780") + t.Skip("flaky test; see https://golang.org/issue/5780") switch runtime.GOOS { case "darwin": - // TODO(cnicolaou): http://golang.org/issue/2603 + // TODO(cnicolaou): https://golang.org/issue/2603 // leads to leaked file descriptors in this test when it's // run from a builder. closeUnexpectedFds(t, "TestExtraFilesFDShuffle") case "netbsd": - // http://golang.org/issue/3955 + // https://golang.org/issue/3955 closeUnexpectedFds(t, "TestExtraFilesFDShuffle") case "windows": t.Skip("no operating system support; skipping") @@ -379,8 +426,9 @@ func TestExtraFilesFDShuffle(t *testing.T) { } func TestExtraFiles(t *testing.T) { - switch runtime.GOOS { - case "nacl", "windows": + testenv.MustHaveExec(t) + + if runtime.GOOS == "windows" { t.Skipf("skipping test on %q", runtime.GOOS) } @@ -608,21 +656,21 @@ func TestHelperProcess(*testing.T) { // file descriptors... case "darwin": // TODO(bradfitz): broken? Sometimes. - // http://golang.org/issue/2603 + // https://golang.org/issue/2603 // Skip this additional part of the test for now. case "netbsd": // TODO(jsing): This currently fails on NetBSD due to // the cloned file descriptors that result from opening // /dev/urandom. - // http://golang.org/issue/3955 + // https://golang.org/issue/3955 case "plan9": // TODO(0intro): Determine why Plan 9 is leaking // file descriptors. - // http://golang.org/issue/7118 + // https://golang.org/issue/7118 case "solaris": // TODO(aram): This fails on Solaris because libc opens // its own files, as it sees fit. Darwin does the same, - // see: http://golang.org/issue/2603 + // see: https://golang.org/issue/2603 default: // Now verify that there are no other open fds. var files []*os.File @@ -721,3 +769,54 @@ func TestHelperProcess(*testing.T) { os.Exit(2) } } + +// Issue 9173: ignore stdin pipe writes if the program completes successfully. +func TestIgnorePipeErrorOnSuccess(t *testing.T) { + testenv.MustHaveExec(t) + + // We really only care about testing this on Unixy things. + if runtime.GOOS == "windows" || runtime.GOOS == "plan9" { + t.Skipf("skipping test on %q", runtime.GOOS) + } + + cmd := helperCommand(t, "echo", "foo") + var out bytes.Buffer + cmd.Stdin = strings.NewReader(strings.Repeat("x", 10<<20)) + cmd.Stdout = &out + if err := cmd.Run(); err != nil { + t.Fatal(err) + } + if got, want := out.String(), "foo\n"; got != want { + t.Errorf("output = %q; want %q", got, want) + } +} + +type badWriter struct{} + +func (w *badWriter) Write(data []byte) (int, error) { + return 0, io.ErrUnexpectedEOF +} + +func TestClosePipeOnCopyError(t *testing.T) { + testenv.MustHaveExec(t) + + if runtime.GOOS == "windows" || runtime.GOOS == "plan9" { + t.Skipf("skipping test on %s - no yes command", runtime.GOOS) + } + cmd := exec.Command("yes") + cmd.Stdout = new(badWriter) + c := make(chan int, 1) + go func() { + err := cmd.Run() + if err == nil { + t.Errorf("yes completed successfully") + } + c <- 1 + }() + select { + case <-c: + // ok + case <-time.After(5 * time.Second): + t.Fatalf("yes got stuck writing to bad writer") + } +} diff --git a/libgo/go/os/exec_posix.go b/libgo/go/os/exec_posix.go index fb9d291e664..94dd04beb23 100644 --- a/libgo/go/os/exec_posix.go +++ b/libgo/go/os/exec_posix.go @@ -81,33 +81,6 @@ func (p *ProcessState) sysUsage() interface{} { return p.rusage } -// Convert i to decimal string. -func itod(i int) string { - if i == 0 { - return "0" - } - - u := uint64(i) - if i < 0 { - u = -u - } - - // Assemble decimal in reverse order. - var b [32]byte - bp := len(b) - for ; u > 0; u /= 10 { - bp-- - b[bp] = byte(u%10) + '0' - } - - if i < 0 { - bp-- - b[bp] = '-' - } - - return string(b[bp:]) -} - func (p *ProcessState) String() string { if p == nil { return "" @@ -116,13 +89,13 @@ func (p *ProcessState) String() string { res := "" switch { case status.Exited(): - res = "exit status " + itod(status.ExitStatus()) + res = "exit status " + itoa(status.ExitStatus()) case status.Signaled(): res = "signal: " + status.Signal().String() case status.Stopped(): res = "stop signal: " + status.StopSignal().String() if status.StopSignal() == syscall.SIGTRAP && status.TrapCause() != 0 { - res += " (trap " + itod(status.TrapCause()) + ")" + res += " (trap " + itoa(status.TrapCause()) + ")" } case status.Continued(): res = "continued" diff --git a/libgo/go/os/exec_windows.go b/libgo/go/os/exec_windows.go index 393393b2375..3264271b2e9 100644 --- a/libgo/go/os/exec_windows.go +++ b/libgo/go/os/exec_windows.go @@ -7,13 +7,15 @@ package os import ( "errors" "runtime" + "sync/atomic" "syscall" "time" "unsafe" ) func (p *Process) wait() (ps *ProcessState, err error) { - s, e := syscall.WaitForSingleObject(syscall.Handle(p.handle), syscall.INFINITE) + handle := atomic.LoadUintptr(&p.handle) + s, e := syscall.WaitForSingleObject(syscall.Handle(handle), syscall.INFINITE) switch s { case syscall.WAIT_OBJECT_0: break @@ -23,12 +25,12 @@ func (p *Process) wait() (ps *ProcessState, err error) { return nil, errors.New("os: unexpected result from WaitForSingleObject") } var ec uint32 - e = syscall.GetExitCodeProcess(syscall.Handle(p.handle), &ec) + e = syscall.GetExitCodeProcess(syscall.Handle(handle), &ec) if e != nil { return nil, NewSyscallError("GetExitCodeProcess", e) } var u syscall.Rusage - e = syscall.GetProcessTimes(syscall.Handle(p.handle), &u.CreationTime, &u.ExitTime, &u.KernelTime, &u.UserTime) + e = syscall.GetProcessTimes(syscall.Handle(handle), &u.CreationTime, &u.ExitTime, &u.KernelTime, &u.UserTime) if e != nil { return nil, NewSyscallError("GetProcessTimes", e) } @@ -53,7 +55,8 @@ func terminateProcess(pid, exitcode int) error { } func (p *Process) signal(sig Signal) error { - if p.handle == uintptr(syscall.InvalidHandle) { + handle := atomic.LoadUintptr(&p.handle) + if handle == uintptr(syscall.InvalidHandle) { return syscall.EINVAL } if p.done() { @@ -67,14 +70,15 @@ func (p *Process) signal(sig Signal) error { } func (p *Process) release() error { - if p.handle == uintptr(syscall.InvalidHandle) { + handle := atomic.LoadUintptr(&p.handle) + if handle == uintptr(syscall.InvalidHandle) { return syscall.EINVAL } - e := syscall.CloseHandle(syscall.Handle(p.handle)) + e := syscall.CloseHandle(syscall.Handle(handle)) if e != nil { return NewSyscallError("CloseHandle", e) } - p.handle = uintptr(syscall.InvalidHandle) + atomic.StoreUintptr(&p.handle, uintptr(syscall.InvalidHandle)) // no need for a finalizer anymore runtime.SetFinalizer(p, nil) return nil diff --git a/libgo/go/os/file.go b/libgo/go/os/file.go index e12428cbe12..8c0e3ffe1ba 100644 --- a/libgo/go/os/file.go +++ b/libgo/go/os/file.go @@ -192,7 +192,7 @@ func (f *File) Seek(offset int64, whence int) (ret int64, err error) { // WriteString is like Write, but writes the contents of string s rather than // a slice of bytes. -func (f *File) WriteString(s string) (ret int, err error) { +func (f *File) WriteString(s string) (n int, err error) { if f == nil { return 0, ErrInvalid } @@ -203,9 +203,16 @@ func (f *File) WriteString(s string) (ret int, err error) { // If there is an error, it will be of type *PathError. func Mkdir(name string, perm FileMode) error { e := syscall.Mkdir(name, syscallMode(perm)) + if e != nil { return &PathError{"mkdir", name, e} } + + // mkdir(2) itself won't handle the sticky bit on *BSD and Solaris + if !supportsCreateWithStickyBit && perm&ModeSticky != 0 { + Chmod(name, perm) + } + return nil } @@ -235,16 +242,16 @@ func (f *File) Chdir() error { // the returned file can be used for reading; the associated file // descriptor has mode O_RDONLY. // If there is an error, it will be of type *PathError. -func Open(name string) (file *File, err error) { +func Open(name string) (*File, error) { return OpenFile(name, O_RDONLY, 0) } -// Create creates the named file mode 0666 (before umask), truncating -// it if it already exists. If successful, methods on the returned +// Create creates the named file with mode 0666 (before umask), truncating +// it if it already exists. If successful, methods on the returned // File can be used for I/O; the associated file descriptor has mode // O_RDWR. // If there is an error, it will be of type *PathError. -func Create(name string) (file *File, err error) { +func Create(name string) (*File, error) { return OpenFile(name, O_RDWR|O_CREATE|O_TRUNC, 0666) } @@ -252,6 +259,7 @@ func Create(name string) (file *File, err error) { var lstat = Lstat // Rename renames (moves) a file. OS-specific restrictions might apply. +// If there is an error, it will be of type *LinkError. func Rename(oldpath, newpath string) error { return rename(oldpath, newpath) } diff --git a/libgo/go/os/file_plan9.go b/libgo/go/os/file_plan9.go index 132594eede9..085ebc4c8a6 100644 --- a/libgo/go/os/file_plan9.go +++ b/libgo/go/os/file_plan9.go @@ -79,7 +79,7 @@ func syscallMode(i FileMode) (o uint32) { // (O_RDONLY etc.) and perm, (0666 etc.) if applicable. If successful, // methods on the returned File can be used for I/O. // If there is an error, it will be of type *PathError. -func OpenFile(name string, flag int, perm FileMode) (file *File, err error) { +func OpenFile(name string, flag int, perm FileMode) (*File, error) { var ( fd int e error @@ -159,7 +159,7 @@ func (file *file) close() error { // Stat returns the FileInfo structure describing file. // If there is an error, it will be of type *PathError. -func (f *File) Stat() (fi FileInfo, err error) { +func (f *File) Stat() (FileInfo, error) { if f == nil { return nil, ErrInvalid } @@ -224,7 +224,7 @@ func (f *File) Chmod(mode FileMode) error { // Sync commits the current contents of the file to stable storage. // Typically, this means flushing the file system's in-memory copy // of recently written data to disk. -func (f *File) Sync() (err error) { +func (f *File) Sync() error { if f == nil { return ErrInvalid } @@ -319,7 +319,7 @@ func hasPrefix(s, prefix string) bool { return len(s) >= len(prefix) && s[0:len(prefix)] == prefix } -// Variant of LastIndex from the strings package. +// LastIndexByte from the strings package. func lastIndex(s string, sep byte) int { for i := len(s) - 1; i >= 0; i-- { if s[i] == sep { diff --git a/libgo/go/os/file_posix.go b/libgo/go/os/file_posix.go index fbb3b5e4d81..6d8076fdf5c 100644 --- a/libgo/go/os/file_posix.go +++ b/libgo/go/os/file_posix.go @@ -28,14 +28,6 @@ func Readlink(name string) (string, error) { } } -func rename(oldname, newname string) error { - e := syscall.Rename(oldname, newname) - if e != nil { - return &LinkError{"rename", oldname, newname, e} - } - return nil -} - // syscallMode returns the syscall-specific mode bits from Go's portable mode bits. func syscallMode(i FileMode) (o uint32) { o |= uint32(i.Perm()) @@ -122,7 +114,7 @@ func (f *File) Truncate(size int64) error { // Sync commits the current contents of the file to stable storage. // Typically, this means flushing the file system's in-memory copy // of recently written data to disk. -func (f *File) Sync() (err error) { +func (f *File) Sync() error { if f == nil { return ErrInvalid } diff --git a/libgo/go/os/file_unix.go b/libgo/go/os/file_unix.go index b25e62ff003..7a18987d283 100644 --- a/libgo/go/os/file_unix.go +++ b/libgo/go/os/file_unix.go @@ -12,6 +12,14 @@ import ( "syscall" ) +func rename(oldname, newname string) error { + e := syscall.Rename(oldname, newname) + if e != nil { + return &LinkError{"rename", oldname, newname, e} + } + return nil +} + // File represents an open file descriptor. type File struct { *file @@ -73,12 +81,24 @@ const DevNull = "/dev/null" // (O_RDONLY etc.) and perm, (0666 etc.) if applicable. If successful, // methods on the returned File can be used for I/O. // If there is an error, it will be of type *PathError. -func OpenFile(name string, flag int, perm FileMode) (file *File, err error) { +func OpenFile(name string, flag int, perm FileMode) (*File, error) { + chmod := false + if !supportsCreateWithStickyBit && flag&O_CREATE != 0 && perm&ModeSticky != 0 { + if _, err := Stat(name); IsNotExist(err) { + chmod = true + } + } + r, e := syscall.Open(name, flag|syscall.O_CLOEXEC, syscallMode(perm)) if e != nil { return nil, &PathError{"open", name, e} } + // open(2) itself won't handle the sticky bit on *BSD and Solaris + if chmod { + Chmod(name, perm) + } + // There's a race here with fork/exec, which we are // content to live with. See ../syscall/exec_unix.go. if !supportsCloseOnExec { @@ -126,12 +146,12 @@ func (file *file) close() error { // Stat returns the FileInfo structure describing file. // If there is an error, it will be of type *PathError. -func (f *File) Stat() (fi FileInfo, err error) { +func (f *File) Stat() (FileInfo, error) { if f == nil { return nil, ErrInvalid } var stat syscall.Stat_t - err = syscall.Fstat(f.fd, &stat) + err := syscall.Fstat(f.fd, &stat) if err != nil { return nil, &PathError{"stat", f.name, err} } @@ -140,9 +160,9 @@ func (f *File) Stat() (fi FileInfo, err error) { // Stat returns a FileInfo describing the named file. // If there is an error, it will be of type *PathError. -func Stat(name string) (fi FileInfo, err error) { +func Stat(name string) (FileInfo, error) { var stat syscall.Stat_t - err = syscall.Stat(name, &stat) + err := syscall.Stat(name, &stat) if err != nil { return nil, &PathError{"stat", name, err} } @@ -153,9 +173,9 @@ func Stat(name string) (fi FileInfo, err error) { // If the file is a symbolic link, the returned FileInfo // describes the symbolic link. Lstat makes no attempt to follow the link. // If there is an error, it will be of type *PathError. -func Lstat(name string) (fi FileInfo, err error) { +func Lstat(name string) (FileInfo, error) { var stat syscall.Stat_t - err = syscall.Lstat(name, &stat) + err := syscall.Lstat(name, &stat) if err != nil { return nil, &PathError{"lstat", name, err} } diff --git a/libgo/go/os/os_test.go b/libgo/go/os/os_test.go index 7a86efac218..78201f2c27e 100644 --- a/libgo/go/os/os_test.go +++ b/libgo/go/os/os_test.go @@ -9,6 +9,7 @@ import ( "errors" "flag" "fmt" + "internal/testenv" "io" "io/ioutil" . "os" @@ -21,7 +22,6 @@ import ( "sync" "syscall" "testing" - "text/template" "time" ) @@ -41,18 +41,33 @@ type sysDir struct { files []string } -var sysdir = func() (sd *sysDir) { +var sysdir = func() *sysDir { switch runtime.GOOS { case "android": - sd = &sysDir{ + return &sysDir{ "/system/etc", []string{ "audio_policy.conf", "system_fonts.xml", }, } + case "darwin": + switch runtime.GOARCH { + case "arm", "arm64": + wd, err := syscall.Getwd() + if err != nil { + wd = err.Error() + } + return &sysDir{ + filepath.Join(wd, "..", ".."), + []string{ + "ResourceRules.plist", + "Info.plist", + }, + } + } case "windows": - sd = &sysDir{ + return &sysDir{ Getenv("SystemRoot") + "\\system32\\drivers\\etc", []string{ "networks", @@ -61,24 +76,22 @@ var sysdir = func() (sd *sysDir) { }, } case "plan9": - sd = &sysDir{ + return &sysDir{ "/lib/ndb", []string{ "common", "local", }, } - default: - sd = &sysDir{ - "/etc", - []string{ - "group", - "hosts", - "passwd", - }, - } } - return + return &sysDir{ + "/etc", + []string{ + "group", + "hosts", + "passwd", + }, + } }() func size(name string, t *testing.T) int64 { @@ -112,15 +125,22 @@ func equal(name1, name2 string) (r bool) { return } -func newFile(testName string, t *testing.T) (f *File) { - // Use a local file system, not NFS. - // On Unix, override $TMPDIR in case the user - // has it set to an NFS-mounted directory. - dir := "" - if runtime.GOOS != "android" && runtime.GOOS != "windows" { - dir = "/tmp" +// localTmp returns a local temporary directory not on NFS. +func localTmp() string { + switch runtime.GOOS { + case "android", "windows": + return TempDir() + case "darwin": + switch runtime.GOARCH { + case "arm", "arm64": + return TempDir() + } } - f, err := ioutil.TempFile(dir, "_Go_"+testName) + return "/tmp" +} + +func newFile(testName string, t *testing.T) (f *File) { + f, err := ioutil.TempFile(localTmp(), "_Go_"+testName) if err != nil { t.Fatalf("TempFile %s: %s", testName, err) } @@ -128,14 +148,7 @@ func newFile(testName string, t *testing.T) (f *File) { } func newDir(testName string, t *testing.T) (name string) { - // Use a local file system, not NFS. - // On Unix, override $TMPDIR in case the user - // has it set to an NFS-mounted directory. - dir := "" - if runtime.GOOS != "android" && runtime.GOOS != "windows" { - dir = "/tmp" - } - name, err := ioutil.TempDir(dir, "_Go_"+testName) + name, err := ioutil.TempDir(localTmp(), "_Go_"+testName) if err != nil { t.Fatalf("TempDir %s: %s", testName, err) } @@ -310,6 +323,15 @@ func TestReaddirnamesOneAtATime(t *testing.T) { switch runtime.GOOS { case "android": dir = "/system/bin" + case "darwin": + switch runtime.GOARCH { + case "arm", "arm64": + wd, err := Getwd() + if err != nil { + t.Fatal(err) + } + dir = wd + } case "plan9": dir = "/bin" case "windows": @@ -489,11 +511,35 @@ func TestReaddirStatFailures(t *testing.T) { } } +// Readdir on a regular file should fail. +func TestReaddirOfFile(t *testing.T) { + f, err := ioutil.TempFile("", "_Go_ReaddirOfFile") + if err != nil { + t.Fatal(err) + } + defer Remove(f.Name()) + f.Write([]byte("foo")) + f.Close() + reg, err := Open(f.Name()) + if err != nil { + t.Fatal(err) + } + defer reg.Close() + + names, err := reg.Readdirnames(-1) + if err == nil { + t.Error("Readdirnames succeeded; want non-nil error") + } + if len(names) > 0 { + t.Errorf("unexpected dir names in regular file: %q", names) + } +} + func TestHardLink(t *testing.T) { - // Hardlinks are not supported under windows or Plan 9. if runtime.GOOS == "plan9" { - return + t.Skip("skipping on plan9, hardlinks not supported") } + defer chtmpdir(t)() from, to := "hardlinktestfrom", "hardlinktestto" Remove(from) // Just in case. file, err := Create(to) @@ -508,6 +554,14 @@ func TestHardLink(t *testing.T) { if err != nil { t.Fatalf("link %q, %q failed: %v", to, from, err) } + + none := "hardlinktestnone" + err = Link(none, none) + // Check the returned error is well-formed. + if lerr, ok := err.(*LinkError); !ok || lerr.Error() == "" { + t.Errorf("link %q, %q failed to return a valid error", none, none) + } + defer Remove(from) tostat, err := Stat(to) if err != nil { @@ -522,6 +576,31 @@ func TestHardLink(t *testing.T) { } } +// chtmpdir changes the working directory to a new temporary directory and +// provides a cleanup function. Used when PWD is read-only. +func chtmpdir(t *testing.T) func() { + if runtime.GOOS != "darwin" || (runtime.GOARCH != "arm" && runtime.GOARCH != "arm64") { + return func() {} // only needed on darwin/arm{,64} + } + oldwd, err := Getwd() + if err != nil { + t.Fatalf("chtmpdir: %v", err) + } + d, err := ioutil.TempDir("", "test") + if err != nil { + t.Fatalf("chtmpdir: %v", err) + } + if err := Chdir(d); err != nil { + t.Fatalf("chtmpdir: %v", err) + } + return func() { + if err := Chdir(oldwd); err != nil { + t.Fatalf("chtmpdir: %v", err) + } + RemoveAll(d) + } +} + func TestSymlink(t *testing.T) { switch runtime.GOOS { case "android", "nacl", "plan9": @@ -531,6 +610,7 @@ func TestSymlink(t *testing.T) { t.Skipf("skipping on %s", runtime.GOOS) } } + defer chtmpdir(t)() from, to := "symlinktestfrom", "symlinktestto" Remove(from) // Just in case. file, err := Create(to) @@ -597,6 +677,7 @@ func TestLongSymlink(t *testing.T) { t.Skipf("skipping on %s", runtime.GOOS) } } + defer chtmpdir(t)() s := "0123456789abcdef" // Long, but not too long: a common limit is 255. s = s + s + s + s + s + s + s + s + s + s + s + s + s + s + s @@ -617,14 +698,18 @@ func TestLongSymlink(t *testing.T) { } func TestRename(t *testing.T) { + defer chtmpdir(t)() from, to := "renamefrom", "renameto" - Remove(to) // Just in case. + // Ensure we are not testing the overwrite case here. + Remove(from) + Remove(to) + file, err := Create(from) if err != nil { - t.Fatalf("open %q failed: %v", to, err) + t.Fatalf("open %q failed: %v", from, err) } if err = file.Close(); err != nil { - t.Errorf("close %q failed: %v", to, err) + t.Errorf("close %q failed: %v", from, err) } err = Rename(from, to) if err != nil { @@ -637,6 +722,79 @@ func TestRename(t *testing.T) { } } +func TestRenameOverwriteDest(t *testing.T) { + if runtime.GOOS == "plan9" { + t.Skip("skipping on plan9") + } + defer chtmpdir(t)() + from, to := "renamefrom", "renameto" + // Just in case. + Remove(from) + Remove(to) + + toData := []byte("to") + fromData := []byte("from") + + err := ioutil.WriteFile(to, toData, 0777) + if err != nil { + t.Fatalf("write file %q failed: %v", to, err) + } + + err = ioutil.WriteFile(from, fromData, 0777) + if err != nil { + t.Fatalf("write file %q failed: %v", from, err) + } + err = Rename(from, to) + if err != nil { + t.Fatalf("rename %q, %q failed: %v", to, from, err) + } + defer Remove(to) + + _, err = Stat(from) + if err == nil { + t.Errorf("from file %q still exists", from) + } + if err != nil && !IsNotExist(err) { + t.Fatalf("stat from: %v", err) + } + toFi, err := Stat(to) + if err != nil { + t.Fatalf("stat %q failed: %v", to, err) + } + if toFi.Size() != int64(len(fromData)) { + t.Errorf(`"to" size = %d; want %d (old "from" size)`, toFi.Size(), len(fromData)) + } +} + +func TestRenameFailed(t *testing.T) { + defer chtmpdir(t)() + from, to := "renamefrom", "renameto" + // Ensure we are not testing the overwrite case here. + Remove(from) + Remove(to) + + err := Rename(from, to) + switch err := err.(type) { + case *LinkError: + if err.Op != "rename" { + t.Errorf("rename %q, %q: err.Op: want %q, got %q", from, to, "rename", err.Op) + } + if err.Old != from { + t.Errorf("rename %q, %q: err.Old: want %q, got %q", from, to, from, err.Old) + } + if err.New != to { + t.Errorf("rename %q, %q: err.New: want %q, got %q", from, to, to, err.New) + } + case nil: + t.Errorf("rename %q, %q: expected error, got nil", from, to) + + // cleanup whatever was placed in "renameto" + Remove(to) + default: + t.Errorf("rename %q, %q: expected %T, got %T %v", from, to, new(LinkError), err, err) + } +} + func exec(t *testing.T, dir, cmd string, args []string, expect string) { r, w, err := Pipe() if err != nil { @@ -664,18 +822,18 @@ func exec(t *testing.T, dir, cmd string, args []string, expect string) { } func TestStartProcess(t *testing.T) { - switch runtime.GOOS { - case "android", "nacl": - t.Skipf("skipping on %s", runtime.GOOS) - } + testenv.MustHaveExec(t) var dir, cmd string var args []string - if runtime.GOOS == "windows" { + switch runtime.GOOS { + case "android": + t.Skip("android doesn't have /bin/pwd") + case "windows": cmd = Getenv("COMSPEC") dir = Getenv("SystemRoot") args = []string{"/c", "cd"} - } else { + default: cmd = "/bin/pwd" dir = "/" args = []string{} @@ -847,6 +1005,19 @@ func TestChdirAndGetwd(t *testing.T) { dirs = []string{"/", "/system/bin"} case "plan9": dirs = []string{"/", "/usr"} + case "darwin": + switch runtime.GOARCH { + case "arm", "arm64": + d1, err := ioutil.TempDir("", "d1") + if err != nil { + t.Fatalf("TempDir: %v", err) + } + d2, err := ioutil.TempDir("", "d2") + if err != nil { + t.Fatalf("TempDir: %v", err) + } + dirs = []string{d1, d2} + } } oldwd := Getenv("PWD") for mode := 0; mode < 2; mode++ { @@ -892,6 +1063,64 @@ func TestChdirAndGetwd(t *testing.T) { fd.Close() } +// Test that Chdir+Getwd is program-wide. +func TestProgWideChdir(t *testing.T) { + const N = 10 + c := make(chan bool) + cpwd := make(chan string) + for i := 0; i < N; i++ { + go func(i int) { + // Lock half the goroutines in their own operating system + // thread to exercise more scheduler possibilities. + if i%2 == 1 { + // On Plan 9, after calling LockOSThread, the goroutines + // run on different processes which don't share the working + // directory. This used to be an issue because Go expects + // the working directory to be program-wide. + // See issue 9428. + runtime.LockOSThread() + } + <-c + pwd, err := Getwd() + if err != nil { + t.Errorf("Getwd on goroutine %d: %v", i, err) + return + } + cpwd <- pwd + }(i) + } + oldwd, err := Getwd() + if err != nil { + t.Fatalf("Getwd: %v", err) + } + d, err := ioutil.TempDir("", "test") + if err != nil { + t.Fatalf("TempDir: %v", err) + } + defer func() { + if err := Chdir(oldwd); err != nil { + t.Fatalf("Chdir: %v", err) + } + RemoveAll(d) + }() + if err := Chdir(d); err != nil { + t.Fatalf("Chdir: %v", err) + } + // OS X sets TMPDIR to a symbolic link. + // So we resolve our working directory again before the test. + d, err = Getwd() + if err != nil { + t.Fatalf("Getwd: %v", err) + } + close(c) + for i := 0; i < N; i++ { + pwd := <-cpwd + if pwd != d { + t.Errorf("Getwd returned %q; want %q", pwd, d) + } + } +} + func TestSeek(t *testing.T) { f := newFile("TestSeek", t) defer Remove(f.Name()) @@ -920,7 +1149,7 @@ func TestSeek(t *testing.T) { if off != tt.out || err != nil { if e, ok := err.(*PathError); ok && e.Err == syscall.EINVAL && tt.out > 1<<32 { // Reiserfs rejects the big seeks. - // http://code.google.com/p/go/issues/detail?id=91 + // https://golang.org/issue/91 break } t.Errorf("#%d: Seek(%v, %v) = %v, %v want %v, nil", i, tt.in, tt.whence, off, err, tt.out) @@ -1033,14 +1262,35 @@ func run(t *testing.T, cmd []string) string { return output } +func testWindowsHostname(t *testing.T) { + hostname, err := Hostname() + if err != nil { + t.Fatal(err) + } + cmd := osexec.Command("hostname") + out, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("Failed to execute hostname command: %v %s", err, out) + } + want := strings.Trim(string(out), "\r\n") + if hostname != want { + t.Fatalf("Hostname() = %q, want %q", hostname, want) + } +} + func TestHostname(t *testing.T) { // There is no other way to fetch hostname on windows, but via winapi. // On Plan 9 it can be taken from #c/sysname as Hostname() does. switch runtime.GOOS { - case "android", "nacl", "plan9", "windows": - t.Skipf("skipping on %s", runtime.GOOS) + case "android", "plan9": + t.Skipf("%s doesn't have /bin/hostname", runtime.GOOS) + case "windows": + testWindowsHostname(t) + return } + testenv.MustHaveExec(t) + // Check internal Hostname() against the output of /bin/hostname. // Allow that the internal Hostname returns a Fully Qualified Domain Name // and the /bin/hostname only returns the first component @@ -1115,6 +1365,7 @@ func writeFile(t *testing.T, fname string, flag int, text string) string { } func TestAppend(t *testing.T) { + defer chtmpdir(t)() const f = "append.txt" defer Remove(f) s := writeFile(t, f, O_CREATE|O_TRUNC|O_RDWR, "new") @@ -1178,6 +1429,7 @@ func TestNilProcessStateString(t *testing.T) { } func TestSameFile(t *testing.T) { + defer chtmpdir(t)() fa, err := Create("a") if err != nil { t.Fatalf("Create(a): %v", err) @@ -1297,45 +1549,11 @@ func TestReadAtEOF(t *testing.T) { } func testKillProcess(t *testing.T, processKiller func(p *Process)) { - t.Skip("gccgo does not have a go command") - switch runtime.GOOS { - case "android", "nacl": - t.Skipf("skipping on %s", runtime.GOOS) - } - - dir, err := ioutil.TempDir("", "go-build") - if err != nil { - t.Fatalf("Failed to create temp directory: %v", err) - } - defer RemoveAll(dir) - - src := filepath.Join(dir, "main.go") - f, err := Create(src) - if err != nil { - t.Fatalf("Failed to create %v: %v", src, err) - } - st := template.Must(template.New("source").Parse(` -package main -import "time" -func main() { - time.Sleep(time.Second) -} -`)) - err = st.Execute(f, nil) - if err != nil { - f.Close() - t.Fatalf("Failed to execute template: %v", err) - } - f.Close() - - exe := filepath.Join(dir, "main.exe") - output, err := osexec.Command("go", "build", "-o", exe, src).CombinedOutput() - if err != nil { - t.Fatalf("Failed to build exe %v: %v %v", exe, err, string(output)) - } + testenv.MustHaveExec(t) - cmd := osexec.Command(exe) - err = cmd.Start() + // Re-exec the test binary itself to emulate "sleep 1". + cmd := osexec.Command(Args[0], "-test.run", "TestSleep") + err := cmd.Start() if err != nil { t.Fatalf("Failed to start test process: %v", err) } @@ -1349,6 +1567,15 @@ func main() { } } +// TestSleep emulates "sleep 1". It is a helper for testKillProcess, so we +// don't have to rely on an external "sleep" command being available. +func TestSleep(t *testing.T) { + if testing.Short() { + t.Skip("Skipping in short mode") + } + time.Sleep(time.Second) +} + func TestKillStartProcess(t *testing.T) { testKillProcess(t, func(p *Process) { err := p.Kill() @@ -1359,14 +1586,13 @@ func TestKillStartProcess(t *testing.T) { } func TestGetppid(t *testing.T) { - switch runtime.GOOS { - case "nacl": - t.Skip("skipping on nacl") - case "plan9": + if runtime.GOOS == "plan9" { // TODO: golang.org/issue/8206 t.Skipf("skipping test on plan9; see issue 8206") } + testenv.MustHaveExec(t) + if Getenv("GO_WANT_HELPER_PROCESS") == "1" { fmt.Print(Getppid()) Exit(0) diff --git a/libgo/go/os/os_unix_test.go b/libgo/go/os/os_unix_test.go index 21d40ccaf84..2adc3b50e72 100644 --- a/libgo/go/os/os_unix_test.go +++ b/libgo/go/os/os_unix_test.go @@ -13,6 +13,10 @@ import ( "testing" ) +func init() { + isReadonlyError = func(err error) bool { return err == syscall.EROFS } +} + func checkUidGid(t *testing.T, path string, uid, gid int) { dir, err := Stat(path) if err != nil { @@ -28,10 +32,10 @@ func checkUidGid(t *testing.T, path string, uid, gid int) { } func TestChown(t *testing.T) { - // Chown is not supported under windows os Plan 9. + // Chown is not supported under windows or Plan 9. // Plan9 provides a native ChownPlan9 version instead. if runtime.GOOS == "windows" || runtime.GOOS == "plan9" { - return + t.Skipf("%s does not support syscall.Chown", runtime.GOOS) } // Use TempDir() to make sure we're on a local file system, // so that the group ids returned by Getgroups will be allowed @@ -74,3 +78,109 @@ func TestChown(t *testing.T) { checkUidGid(t, f.Name(), int(sys.Uid), gid) } } + +func TestFileChown(t *testing.T) { + // Fchown is not supported under windows or Plan 9. + if runtime.GOOS == "windows" || runtime.GOOS == "plan9" { + t.Skipf("%s does not support syscall.Fchown", runtime.GOOS) + } + // Use TempDir() to make sure we're on a local file system, + // so that the group ids returned by Getgroups will be allowed + // on the file. On NFS, the Getgroups groups are + // basically useless. + f := newFile("TestFileChown", t) + defer Remove(f.Name()) + defer f.Close() + dir, err := f.Stat() + if err != nil { + t.Fatalf("stat %s: %s", f.Name(), err) + } + + // Can't change uid unless root, but can try + // changing the group id. First try our current group. + gid := Getgid() + t.Log("gid:", gid) + if err = f.Chown(-1, gid); err != nil { + t.Fatalf("fchown %s -1 %d: %s", f.Name(), gid, err) + } + sys := dir.Sys().(*syscall.Stat_t) + checkUidGid(t, f.Name(), int(sys.Uid), gid) + + // Then try all the auxiliary groups. + groups, err := Getgroups() + if err != nil { + t.Fatalf("getgroups: %s", err) + } + t.Log("groups: ", groups) + for _, g := range groups { + if err = f.Chown(-1, g); err != nil { + t.Fatalf("fchown %s -1 %d: %s", f.Name(), g, err) + } + checkUidGid(t, f.Name(), int(sys.Uid), g) + + // change back to gid to test fd.Chown + if err = f.Chown(-1, gid); err != nil { + t.Fatalf("fchown %s -1 %d: %s", f.Name(), gid, err) + } + checkUidGid(t, f.Name(), int(sys.Uid), gid) + } +} + +func TestLchown(t *testing.T) { + // Lchown is not supported under windows or Plan 9. + if runtime.GOOS == "windows" || runtime.GOOS == "plan9" { + t.Skipf("%s does not support syscall.Lchown", runtime.GOOS) + } + // Use TempDir() to make sure we're on a local file system, + // so that the group ids returned by Getgroups will be allowed + // on the file. On NFS, the Getgroups groups are + // basically useless. + f := newFile("TestLchown", t) + defer Remove(f.Name()) + defer f.Close() + dir, err := f.Stat() + if err != nil { + t.Fatalf("stat %s: %s", f.Name(), err) + } + + linkname := f.Name() + "2" + if err := Link(f.Name(), linkname); err != nil { + t.Fatalf("link %s -> %s: %v", f.Name(), linkname, err) + } + defer Remove(linkname) + + f2, err := Open(linkname) + if err != nil { + t.Fatalf("open %s: %v", linkname, err) + } + defer f2.Close() + + // Can't change uid unless root, but can try + // changing the group id. First try our current group. + gid := Getgid() + t.Log("gid:", gid) + if err = Lchown(linkname, -1, gid); err != nil { + t.Fatalf("lchown %s -1 %d: %s", linkname, gid, err) + } + sys := dir.Sys().(*syscall.Stat_t) + checkUidGid(t, linkname, int(sys.Uid), gid) + + // Then try all the auxiliary groups. + groups, err := Getgroups() + if err != nil { + t.Fatalf("getgroups: %s", err) + } + t.Log("groups: ", groups) + for _, g := range groups { + if err = Lchown(linkname, -1, g); err != nil { + t.Fatalf("lchown %s -1 %d: %s", linkname, g, err) + } + checkUidGid(t, linkname, int(sys.Uid), g) + + // change back to gid to test fd.Chown + if err = f2.Chown(-1, gid); err != nil { + t.Fatalf("fchown %s -1 %d: %s", linkname, gid, err) + } + checkUidGid(t, linkname, int(sys.Uid), gid) + } +} diff --git a/libgo/go/os/path_plan9.go b/libgo/go/os/path_plan9.go index 64bad500a67..b09b53a3d82 100644 --- a/libgo/go/os/path_plan9.go +++ b/libgo/go/os/path_plan9.go @@ -9,7 +9,7 @@ const ( PathListSeparator = '\000' // OS-specific path list separator ) -// IsPathSeparator returns true if c is a directory separator character. +// IsPathSeparator reports whether c is a directory separator character. func IsPathSeparator(c uint8) bool { return PathSeparator == c } diff --git a/libgo/go/os/path_test.go b/libgo/go/os/path_test.go index 6f24a43132a..f9853810c6f 100644 --- a/libgo/go/os/path_test.go +++ b/libgo/go/os/path_test.go @@ -13,6 +13,8 @@ import ( "testing" ) +var isReadonlyError = func(error) bool { return false } + func TestMkdirAll(t *testing.T) { tmpDir := TempDir() path := tmpDir + "/_TestMkdirAll_/dir/./dir2" @@ -205,16 +207,22 @@ func TestMkdirAllAtSlash(t *testing.T) { switch runtime.GOOS { case "android", "plan9", "windows": t.Skipf("skipping on %s", runtime.GOOS) + case "darwin": + switch runtime.GOARCH { + case "arm", "arm64": + t.Skipf("skipping on darwin/%s, mkdir returns EPERM", runtime.GOARCH) + } } RemoveAll("/_go_os_test") - err := MkdirAll("/_go_os_test/dir", 0777) + const dir = "/_go_os_test/dir" + err := MkdirAll(dir, 0777) if err != nil { pathErr, ok := err.(*PathError) // common for users not to be able to write to / - if ok && pathErr.Err == syscall.EACCES { - return + if ok && (pathErr.Err == syscall.EACCES || isReadonlyError(pathErr.Err)) { + t.Skipf("could not create %v: %v", dir, err) } - t.Fatalf(`MkdirAll "/_go_os_test/dir": %v`, err) + t.Fatalf(`MkdirAll "/_go_os_test/dir": %v, %s`, err, pathErr.Err) } RemoveAll("/_go_os_test") } diff --git a/libgo/go/os/path_unix.go b/libgo/go/os/path_unix.go index 0211107ddfc..36f8e61bf92 100644 --- a/libgo/go/os/path_unix.go +++ b/libgo/go/os/path_unix.go @@ -11,7 +11,7 @@ const ( PathListSeparator = ':' // OS-specific path list separator ) -// IsPathSeparator returns true if c is a directory separator character. +// IsPathSeparator reports whether c is a directory separator character. func IsPathSeparator(c uint8) bool { return PathSeparator == c } diff --git a/libgo/go/os/path_windows.go b/libgo/go/os/path_windows.go index 61f2ca59ff4..c96f1376860 100644 --- a/libgo/go/os/path_windows.go +++ b/libgo/go/os/path_windows.go @@ -9,7 +9,7 @@ const ( PathListSeparator = ';' // OS-specific path list separator ) -// IsPathSeparator returns true if c is a directory separator character. +// IsPathSeparator reports whether c is a directory separator character. func IsPathSeparator(c uint8) bool { // NOTE: Windows accept / as path separator. return c == '\\' || c == '/' diff --git a/libgo/go/os/proc.go b/libgo/go/os/proc.go index 774f09900ec..33a8b26f78d 100644 --- a/libgo/go/os/proc.go +++ b/libgo/go/os/proc.go @@ -44,6 +44,14 @@ func Getgroups() ([]int, error) { // Exit causes the current program to exit with the given status code. // Conventionally, code zero indicates success, non-zero an error. -// The program terminates immediately; deferred functions are -// not run. -func Exit(code int) { syscall.Exit(code) } +// The program terminates immediately; deferred functions are not run. +func Exit(code int) { + if code == 0 { + // Give race detector a chance to fail the program. + // Racy programs do not have the right to finish successfully. + runtime_beforeExit() + } + syscall.Exit(code) +} + +func runtime_beforeExit() // implemented in runtime diff --git a/libgo/go/os/signal/signal.go b/libgo/go/os/signal/signal.go index 30042754953..1625786d490 100644 --- a/libgo/go/os/signal/signal.go +++ b/libgo/go/os/signal/signal.go @@ -5,8 +5,6 @@ // Package signal implements access to incoming signals. package signal -// BUG(rsc): This package is not yet implemented on Plan 9. - import ( "os" "sync" @@ -30,9 +28,55 @@ func (h *handler) set(sig int) { h.mask[sig/32] |= 1 << uint(sig&31) } +func (h *handler) clear(sig int) { + h.mask[sig/32] &^= 1 << uint(sig&31) +} + +// Stop relaying the signals, sigs, to any channels previously registered to +// receive them and either reset the signal handlers to their original values +// (action=disableSignal) or ignore the signals (action=ignoreSignal). +func cancel(sigs []os.Signal, action func(int)) { + handlers.Lock() + defer handlers.Unlock() + + remove := func(n int) { + var zerohandler handler + + for c, h := range handlers.m { + if h.want(n) { + handlers.ref[n]-- + h.clear(n) + if h.mask == zerohandler.mask { + delete(handlers.m, c) + } + } + } + + action(n) + } + + if len(sigs) == 0 { + for n := 0; n < numSig; n++ { + remove(n) + } + } else { + for _, s := range sigs { + remove(signum(s)) + } + } +} + +// Ignore causes the provided signals to be ignored. If they are received by +// the program, nothing will happen. Ignore undoes the effect of any prior +// calls to Notify for the provided signals. +// If no signals are provided, all incoming signals will be ignored. +func Ignore(sig ...os.Signal) { + cancel(sig, ignoreSignal) +} + // Notify causes package signal to relay incoming signals to c. -// If no signals are listed, all incoming signals will be relayed to c. -// Otherwise, just the listed signals will. +// If no signals are provided, all incoming signals will be relayed to c. +// Otherwise, just the provided signals will. // // Package signal will not block sending to c: the caller must ensure // that c has sufficient buffer space to keep up with the expected @@ -87,6 +131,13 @@ func Notify(c chan<- os.Signal, sig ...os.Signal) { } } +// Reset undoes the effect of any prior calls to Notify for the provided +// signals. +// If no signals are provided, all signal handlers will be reset. +func Reset(sig ...os.Signal) { + cancel(sig, disableSignal) +} + // Stop causes package signal to stop relaying incoming signals to c. // It undoes the effect of all prior calls to Notify using c. // When Stop returns, it is guaranteed that c will receive no more signals. diff --git a/libgo/go/os/signal/signal_plan9.go b/libgo/go/os/signal/signal_plan9.go new file mode 100644 index 00000000000..b065ae520d7 --- /dev/null +++ b/libgo/go/os/signal/signal_plan9.go @@ -0,0 +1,60 @@ +// 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 signal + +import ( + "os" + "syscall" +) + +var sigtab = make(map[os.Signal]int) + +// In sig.s; jumps to runtime. +func signal_disable(uint32) +func signal_enable(uint32) +func signal_ignore(uint32) +func signal_recv() string + +func init() { + signal_enable(0) // first call - initialize + go loop() +} + +func loop() { + for { + process(syscall.Note(signal_recv())) + } +} + +const numSig = 256 + +func signum(sig os.Signal) int { + switch sig := sig.(type) { + case syscall.Note: + n, ok := sigtab[sig] + if !ok { + n = len(sigtab) + 1 + if n > numSig { + return -1 + } + sigtab[sig] = n + } + return n + default: + return -1 + } +} + +func enableSignal(sig int) { + signal_enable(uint32(sig)) +} + +func disableSignal(sig int) { + signal_disable(uint32(sig)) +} + +func ignoreSignal(sig int) { + signal_ignore(uint32(sig)) +} diff --git a/libgo/go/os/signal/signal_plan9_test.go b/libgo/go/os/signal/signal_plan9_test.go new file mode 100644 index 00000000000..10bfdc3ff10 --- /dev/null +++ b/libgo/go/os/signal/signal_plan9_test.go @@ -0,0 +1,181 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package signal + +import ( + "os" + "runtime" + "syscall" + "testing" + "time" +) + +func waitSig(t *testing.T, c <-chan os.Signal, sig os.Signal) { + select { + case s := <-c: + if s != sig { + t.Fatalf("signal was %v, want %v", s, sig) + } + case <-time.After(1 * time.Second): + t.Fatalf("timeout waiting for %v", sig) + } +} + +// Test that basic signal handling works. +func TestSignal(t *testing.T) { + // Ask for hangup + c := make(chan os.Signal, 1) + Notify(c, syscall.Note("hangup")) + defer Stop(c) + + // Send this process a hangup + t.Logf("hangup...") + postNote(syscall.Getpid(), "hangup") + waitSig(t, c, syscall.Note("hangup")) + + // Ask for everything we can get. + c1 := make(chan os.Signal, 1) + Notify(c1) + + // Send this process an alarm + t.Logf("alarm...") + postNote(syscall.Getpid(), "alarm") + waitSig(t, c1, syscall.Note("alarm")) + + // Send two more hangups, to make sure that + // they get delivered on c1 and that not reading + // from c does not block everything. + t.Logf("hangup...") + postNote(syscall.Getpid(), "hangup") + waitSig(t, c1, syscall.Note("hangup")) + t.Logf("hangup...") + postNote(syscall.Getpid(), "hangup") + waitSig(t, c1, syscall.Note("hangup")) + + // The first SIGHUP should be waiting for us on c. + waitSig(t, c, syscall.Note("hangup")) +} + +func TestStress(t *testing.T) { + dur := 3 * time.Second + if testing.Short() { + dur = 100 * time.Millisecond + } + defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4)) + done := make(chan bool) + finished := make(chan bool) + go func() { + sig := make(chan os.Signal, 1) + Notify(sig, syscall.Note("alarm")) + defer Stop(sig) + Loop: + for { + select { + case <-sig: + case <-done: + break Loop + } + } + finished <- true + }() + go func() { + Loop: + for { + select { + case <-done: + break Loop + default: + postNote(syscall.Getpid(), "alarm") + runtime.Gosched() + } + } + finished <- true + }() + time.Sleep(dur) + close(done) + <-finished + <-finished + // When run with 'go test -cpu=1,2,4' alarm from this test can slip + // into subsequent TestSignal() causing failure. + // Sleep for a while to reduce the possibility of the failure. + time.Sleep(10 * time.Millisecond) +} + +// Test that Stop cancels the channel's registrations. +func TestStop(t *testing.T) { + if testing.Short() { + t.Skip("skipping in short mode") + } + sigs := []string{ + "alarm", + "hangup", + } + + for _, sig := range sigs { + // Send the signal. + // If it's alarm, we should not see it. + // If it's hangup, maybe we'll die. Let the flag tell us what to do. + if sig != "hangup" { + postNote(syscall.Getpid(), sig) + } + time.Sleep(100 * time.Millisecond) + + // Ask for signal + c := make(chan os.Signal, 1) + Notify(c, syscall.Note(sig)) + defer Stop(c) + + // Send this process that signal + postNote(syscall.Getpid(), sig) + waitSig(t, c, syscall.Note(sig)) + + Stop(c) + select { + case s := <-c: + t.Fatalf("unexpected signal %v", s) + case <-time.After(100 * time.Millisecond): + // nothing to read - good + } + + // Send the signal. + // If it's alarm, we should not see it. + // If it's hangup, maybe we'll die. Let the flag tell us what to do. + if sig != "hangup" { + postNote(syscall.Getpid(), sig) + } + + select { + case s := <-c: + t.Fatalf("unexpected signal %v", s) + case <-time.After(100 * time.Millisecond): + // nothing to read - good + } + } +} + +func itoa(val int) string { + if val < 0 { + return "-" + itoa(-val) + } + var buf [32]byte // big enough for int64 + i := len(buf) - 1 + for val >= 10 { + buf[i] = byte(val%10 + '0') + i-- + val /= 10 + } + buf[i] = byte(val + '0') + return string(buf[i:]) +} + +func postNote(pid int, note string) error { + f, err := os.OpenFile("/proc/"+itoa(pid)+"/note", os.O_WRONLY, 0) + if err != nil { + return err + } + defer f.Close() + _, err = f.Write([]byte(note)) + return err +} diff --git a/libgo/go/os/signal/signal_stub.go b/libgo/go/os/signal/signal_stub.go deleted file mode 100644 index d0a6935ff2c..00000000000 --- a/libgo/go/os/signal/signal_stub.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build plan9 - -package signal - -import "os" - -const numSig = 0 - -func signum(sig os.Signal) int { return -1 } - -func disableSignal(int) {} - -func enableSignal(int) {} diff --git a/libgo/go/os/signal/signal_test.go b/libgo/go/os/signal/signal_test.go index 22337a72d4b..a71633c8907 100644 --- a/libgo/go/os/signal/signal_test.go +++ b/libgo/go/os/signal/signal_test.go @@ -109,6 +109,72 @@ func TestStress(t *testing.T) { time.Sleep(10 * time.Millisecond) } +func testCancel(t *testing.T, ignore bool) { + // Send SIGWINCH. By default this signal should be ignored. + syscall.Kill(syscall.Getpid(), syscall.SIGWINCH) + time.Sleep(100 * time.Millisecond) + + // Ask to be notified on c1 when a SIGWINCH is received. + c1 := make(chan os.Signal, 1) + Notify(c1, syscall.SIGWINCH) + defer Stop(c1) + + // Ask to be notified on c2 when a SIGHUP is received. + c2 := make(chan os.Signal, 1) + Notify(c2, syscall.SIGHUP) + defer Stop(c2) + + // Send this process a SIGWINCH and wait for notification on c1. + syscall.Kill(syscall.Getpid(), syscall.SIGWINCH) + waitSig(t, c1, syscall.SIGWINCH) + + // Send this process a SIGHUP and wait for notification on c2. + syscall.Kill(syscall.Getpid(), syscall.SIGHUP) + waitSig(t, c2, syscall.SIGHUP) + + // Ignore, or reset the signal handlers for, SIGWINCH and SIGHUP. + if ignore { + Ignore(syscall.SIGWINCH, syscall.SIGHUP) + } else { + Reset(syscall.SIGWINCH, syscall.SIGHUP) + } + + // Send this process a SIGWINCH. It should be ignored. + syscall.Kill(syscall.Getpid(), syscall.SIGWINCH) + + // If ignoring, Send this process a SIGHUP. It should be ignored. + if ignore { + syscall.Kill(syscall.Getpid(), syscall.SIGHUP) + } + + select { + case s := <-c1: + t.Fatalf("unexpected signal %v", s) + case <-time.After(100 * time.Millisecond): + // nothing to read - good + } + + select { + case s := <-c2: + t.Fatalf("unexpected signal %v", s) + case <-time.After(100 * time.Millisecond): + // nothing to read - good + } + + // Reset the signal handlers for all signals. + Reset() +} + +// Test that Reset cancels registration for listed signals on all channels. +func TestReset(t *testing.T) { + testCancel(t, false) +} + +// Test that Ignore cancels registration for listed signals on all channels. +func TestIgnore(t *testing.T) { + testCancel(t, true) +} + var sendUncaughtSighup = flag.Int("send_uncaught_sighup", 0, "send uncaught SIGHUP during TestStop") // Test that Stop cancels the channel's registrations. diff --git a/libgo/go/os/signal/signal_unix.go b/libgo/go/os/signal/signal_unix.go index 94b8ab3ddbf..1bdf1d72718 100644 --- a/libgo/go/os/signal/signal_unix.go +++ b/libgo/go/os/signal/signal_unix.go @@ -14,6 +14,7 @@ import ( // In assembly. func signal_disable(uint32) func signal_enable(uint32) +func signal_ignore(uint32) func signal_recv() uint32 func loop() { @@ -51,3 +52,7 @@ func enableSignal(sig int) { func disableSignal(sig int) { signal_disable(uint32(sig)) } + +func ignoreSignal(sig int) { + signal_ignore(uint32(sig)) +} diff --git a/libgo/go/os/stat_plan9.go b/libgo/go/os/stat_plan9.go index 25c9a8c14b3..fa4bd83aefb 100644 --- a/libgo/go/os/stat_plan9.go +++ b/libgo/go/os/stat_plan9.go @@ -9,6 +9,8 @@ import ( "time" ) +const _BIT16SZ = 2 + func sameFile(fs1, fs2 *fileStat) bool { a := fs1.sys.(*syscall.Dir) b := fs2.sys.(*syscall.Dir) @@ -41,16 +43,14 @@ func fileInfoFromStat(d *syscall.Dir) FileInfo { // arg is an open *File or a path string. func dirstat(arg interface{}) (*syscall.Dir, error) { var name string + var err error - // This is big enough for most stat messages - // and rounded to a multiple of 128 bytes. - size := (syscall.STATFIXLEN + 16*4 + 128) &^ 128 + size := syscall.STATFIXLEN + 16*4 for i := 0; i < 2; i++ { - buf := make([]byte, size) + buf := make([]byte, _BIT16SZ+size) var n int - var err error switch a := arg.(type) { case *File: name = a.name @@ -61,34 +61,36 @@ func dirstat(arg interface{}) (*syscall.Dir, error) { default: panic("phase error in dirstat") } - if err != nil { + + if n < _BIT16SZ { return nil, &PathError{"stat", name, err} } - if n < syscall.STATFIXLEN { - return nil, &PathError{"stat", name, syscall.ErrShortStat} - } // Pull the real size out of the stat message. size = int(uint16(buf[0]) | uint16(buf[1])<<8) // If the stat message is larger than our buffer we will // go around the loop and allocate one that is big enough. - if size > n { - continue + if size <= n { + d, err := syscall.UnmarshalDir(buf[:n]) + if err != nil { + return nil, &PathError{"stat", name, err} + } + return d, nil } - d, err := syscall.UnmarshalDir(buf[:n]) - if err != nil { - return nil, &PathError{"stat", name, err} - } - return d, nil } - return nil, &PathError{"stat", name, syscall.ErrBadStat} + + if err == nil { + err = syscall.ErrBadStat + } + + return nil, &PathError{"stat", name, err} } // Stat returns a FileInfo describing the named file. // If there is an error, it will be of type *PathError. -func Stat(name string) (fi FileInfo, err error) { +func Stat(name string) (FileInfo, error) { d, err := dirstat(name) if err != nil { return nil, err @@ -100,7 +102,7 @@ func Stat(name string) (fi FileInfo, err error) { // If the file is a symbolic link, the returned FileInfo // describes the symbolic link. Lstat makes no attempt to follow the link. // If there is an error, it will be of type *PathError. -func Lstat(name string) (fi FileInfo, err error) { +func Lstat(name string) (FileInfo, error) { return Stat(name) } diff --git a/libgo/go/os/sticky_bsd.go b/libgo/go/os/sticky_bsd.go new file mode 100644 index 00000000000..6b54c758c70 --- /dev/null +++ b/libgo/go/os/sticky_bsd.go @@ -0,0 +1,11 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd netbsd openbsd solaris + +package os + +// According to sticky(8), neither open(2) nor mkdir(2) will create +// a file with the sticky bit set. +const supportsCreateWithStickyBit = false diff --git a/libgo/go/os/sticky_notbsd.go b/libgo/go/os/sticky_notbsd.go new file mode 100644 index 00000000000..834e79b0b59 --- /dev/null +++ b/libgo/go/os/sticky_notbsd.go @@ -0,0 +1,14 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build !darwin +// +build !dragonfly +// +build !freebsd +// +build !netbsd +// +build !openbsd +// +build !solaris + +package os + +const supportsCreateWithStickyBit = true diff --git a/libgo/go/os/str.go b/libgo/go/os/str.go index e3606b61eb4..d3e03e98495 100644 --- a/libgo/go/os/str.go +++ b/libgo/go/os/str.go @@ -2,21 +2,32 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build plan9 +// Simple converions to avoid depending on strconv. package os -func itoa(val int) string { // do it here rather than with fmt to avoid dependency +// Convert integer to decimal string +func itoa(val int) string { if val < 0 { - return "-" + itoa(-val) + return "-" + uitoa(uint(-val)) } - var buf [32]byte // big enough for int64 + return uitoa(uint(val)) +} + +// Convert unsigned integer to decimal string +func uitoa(val uint) string { + if val == 0 { // avoid string allocation + return "0" + } + var buf [20]byte // big enough for 64bit value base 10 i := len(buf) - 1 for val >= 10 { - buf[i] = byte(val%10 + '0') + q := val / 10 + buf[i] = byte('0' + val - q*10) i-- - val /= 10 + val = q } - buf[i] = byte(val + '0') + // val < 10 + buf[i] = byte('0' + val) return string(buf[i:]) } diff --git a/libgo/go/os/types.go b/libgo/go/os/types.go index 473d431d4d2..9d6f8e13d6f 100644 --- a/libgo/go/os/types.go +++ b/libgo/go/os/types.go @@ -53,7 +53,7 @@ const ( // Mask for the type bits. For regular files, none will be set. ModeType = ModeDir | ModeSymlink | ModeNamedPipe | ModeSocket | ModeDevice - ModePerm FileMode = 0777 // permission bits + ModePerm FileMode = 0777 // Unix permission bits ) func (m FileMode) String() string { diff --git a/libgo/go/os/user/lookup_unix.go b/libgo/go/os/user/lookup_unix.go index 64f4576f69e..bebb9e8f2b0 100644 --- a/libgo/go/os/user/lookup_unix.go +++ b/libgo/go/os/user/lookup_unix.go @@ -16,6 +16,7 @@ import ( ) /* +#cgo solaris CFLAGS: -D_POSIX_PTHREAD_SEMANTICS #include #include #include @@ -23,7 +24,12 @@ import ( static int mygetpwuid_r(int uid, struct passwd *pwd, char *buf, size_t buflen, struct passwd **result) { - return getpwuid_r(uid, pwd, buf, buflen, result); + return getpwuid_r(uid, pwd, buf, buflen, result); +} + +static int mygetpwnam_r(const char *name, struct passwd *pwd, + char *buf, size_t buflen, struct passwd **result) { + return getpwnam_r(name, pwd, buf, buflen, result); } */ @@ -62,9 +68,9 @@ func lookupUnix(uid int, username string, lookupByName bool) (*User, error) { const bufSize = 1024 buf := make([]byte, bufSize) if lookupByName { - p := syscall.StringBytePtr(username) + nameC := syscall.StringBytePtr(username) syscall.Entersyscall() - rv := libc_getpwnam_r(p, + rv := libc_getpwnam_r(nameC, &pwd, &buf[0], bufSize, diff --git a/libgo/go/path/filepath/example_unix_test.go b/libgo/go/path/filepath/example_unix_test.go index f3fe076c3c7..27d85d15c6c 100644 --- a/libgo/go/path/filepath/example_unix_test.go +++ b/libgo/go/path/filepath/example_unix_test.go @@ -37,3 +37,31 @@ func ExampleRel() { // "/b/c": "../b/c" // "./b/c": "" Rel: can't make b/c relative to /a } + +func ExampleSplit() { + paths := []string{ + "/home/arnie/amelia.jpg", + "/mnt/photos/", + "rabbit.jpg", + "/usr/local//go", + } + fmt.Println("On Unix:") + for _, p := range paths { + dir, file := filepath.Split(p) + fmt.Printf("input: %q\n\tdir: %q\n\tfile: %q\n", p, dir, file) + } + // Output: + // On Unix: + // input: "/home/arnie/amelia.jpg" + // dir: "/home/arnie/" + // file: "amelia.jpg" + // input: "/mnt/photos/" + // dir: "/mnt/photos/" + // file: "" + // input: "rabbit.jpg" + // dir: "" + // file: "rabbit.jpg" + // input: "/usr/local//go" + // dir: "/usr/local//" + // file: "go" +} diff --git a/libgo/go/path/filepath/match.go b/libgo/go/path/filepath/match.go index ecc07aa5dac..89f16de355e 100644 --- a/libgo/go/path/filepath/match.go +++ b/libgo/go/path/filepath/match.go @@ -16,7 +16,7 @@ import ( // ErrBadPattern indicates a globbing pattern was malformed. var ErrBadPattern = errors.New("syntax error in pattern") -// Match returns true if name matches the shell file name pattern. +// Match reports whether name matches the shell file name pattern. // The pattern syntax is: // // pattern: @@ -301,7 +301,7 @@ func glob(dir, pattern string, matches []string) (m []string, e error) { return } -// hasMeta returns true if path contains any of the magic characters +// hasMeta reports whether path contains any of the magic characters // recognized by Match. func hasMeta(path string) bool { // TODO(niemeyer): Should other magic characters be added here? diff --git a/libgo/go/path/filepath/path.go b/libgo/go/path/filepath/path.go index d37fc9dfc89..5dc5cfd49e7 100644 --- a/libgo/go/path/filepath/path.go +++ b/libgo/go/path/filepath/path.go @@ -4,6 +4,9 @@ // Package filepath implements utility routines for manipulating filename paths // in a way compatible with the target operating system-defined file paths. +// +// Functions in this package replace any occurrences of the slash ('/') character +// with os.PathSeparator when returning paths unless otherwise specified. package filepath import ( @@ -174,7 +177,8 @@ func FromSlash(path string) string { // SplitList splits a list of paths joined by the OS-specific ListSeparator, // usually found in PATH or GOPATH environment variables. -// Unlike strings.Split, SplitList returns an empty slice when passed an empty string. +// Unlike strings.Split, SplitList returns an empty slice when passed an empty +// string. SplitList does not replace slash characters in the returned paths. func SplitList(path string) []string { return splitList(path) } @@ -196,13 +200,10 @@ func Split(path string) (dir, file string) { // Join joins any number of path elements into a single path, adding // a Separator if necessary. The result is Cleaned, in particular // all empty strings are ignored. +// On Windows, the result is a UNC path if and only if the first path +// element is a UNC path. func Join(elem ...string) string { - for i, e := range elem { - if e != "" { - return Clean(strings.Join(elem[i:], string(Separator))) - } - } - return "" + return join(elem) } // Ext returns the file name extension used by path. @@ -334,10 +335,11 @@ var SkipDir = errors.New("skip this directory") // If there was a problem walking to the file or directory named by path, the // incoming error will describe the problem and the function can decide how // to handle that error (and Walk will not descend into that directory). If -// an error is returned, processing stops. The sole exception is that if path -// is a directory and the function returns the special value SkipDir, the -// contents of the directory are skipped and processing continues as usual on -// the next file. +// an error is returned, processing stops. The sole exception is when the function +// returns the special value SkipDir. If the function returns SkipDir when invoked +// on a directory, Walk skips the directory's contents entirely. +// If the function returns SkipDir when invoked on a non-directory file, +// Walk skips the remaining files in the containing directory. type WalkFunc func(path string, info os.FileInfo, err error) error var lstat = os.Lstat // for testing @@ -456,9 +458,9 @@ func Dir(path string) string { } // VolumeName returns leading volume name. -// Given "C:\foo\bar" it returns "C:" under windows. +// Given "C:\foo\bar" it returns "C:" on Windows. // Given "\\host\share\foo" it returns "\\host\share". // On other platforms it returns "". -func VolumeName(path string) (v string) { +func VolumeName(path string) string { return path[:volumeNameLen(path)] } diff --git a/libgo/go/path/filepath/path_plan9.go b/libgo/go/path/filepath/path_plan9.go index ee8912d58e1..962774efd5d 100644 --- a/libgo/go/path/filepath/path_plan9.go +++ b/libgo/go/path/filepath/path_plan9.go @@ -6,7 +6,7 @@ package filepath import "strings" -// IsAbs returns true if the path is absolute. +// IsAbs reports whether the path is absolute. func IsAbs(path string) bool { return strings.HasPrefix(path, "/") || strings.HasPrefix(path, "#") } @@ -32,3 +32,13 @@ func splitList(path string) []string { func abs(path string) (string, error) { return unixAbs(path) } + +func join(elem []string) string { + // If there's a bug here, fix the logic in ./path_unix.go too. + for i, e := range elem { + if e != "" { + return Clean(strings.Join(elem[i:], string(Separator))) + } + } + return "" +} diff --git a/libgo/go/path/filepath/path_test.go b/libgo/go/path/filepath/path_test.go index c3ee0cb86b8..b2536cb77a4 100644 --- a/libgo/go/path/filepath/path_test.go +++ b/libgo/go/path/filepath/path_test.go @@ -245,6 +245,7 @@ var jointests = []JoinTest{ // one parameter {[]string{""}, ""}, + {[]string{"/"}, "/"}, {[]string{"a"}, "a"}, // two parameters @@ -252,10 +253,16 @@ var jointests = []JoinTest{ {[]string{"a", ""}, "a"}, {[]string{"", "b"}, "b"}, {[]string{"/", "a"}, "/a"}, + {[]string{"/", "a/b"}, "/a/b"}, {[]string{"/", ""}, "/"}, + {[]string{"//", "a"}, "/a"}, + {[]string{"/a", "b"}, "/a/b"}, {[]string{"a/", "b"}, "a/b"}, {[]string{"a/", ""}, "a"}, {[]string{"", ""}, ""}, + + // three parameters + {[]string{"/", "a", "b"}, "/a/b"}, } var winjointests = []JoinTest{ @@ -265,13 +272,17 @@ var winjointests = []JoinTest{ {[]string{`C:\`, `Windows`}, `C:\Windows`}, {[]string{`C:`, `Windows`}, `C:\Windows`}, {[]string{`\\host\share`, `foo`}, `\\host\share\foo`}, + {[]string{`\\host\share\foo`}, `\\host\share\foo`}, {[]string{`//host/share`, `foo/bar`}, `\\host\share\foo\bar`}, -} - -// join takes a []string and passes it to Join. -func join(elem []string, args ...string) string { - args = elem - return filepath.Join(args...) + {[]string{`\`}, `\`}, + {[]string{`\`, ``}, `\`}, + {[]string{`\`, `a`}, `\a`}, + {[]string{`\\`, `a`}, `\a`}, + {[]string{`\`, `a`, `b`}, `\a\b`}, + {[]string{`\\`, `a`, `b`}, `\a\b`}, + {[]string{`\`, `\\a\b`, `c`}, `\a\b\c`}, + {[]string{`\\a`, `b`, `c`}, `\a\b\c`}, + {[]string{`\\a\`, `b`, `c`}, `\a\b\c`}, } func TestJoin(t *testing.T) { @@ -279,8 +290,9 @@ func TestJoin(t *testing.T) { jointests = append(jointests, winjointests...) } for _, test := range jointests { - if p := join(test.elem); p != filepath.FromSlash(test.path) { - t.Errorf("join(%q) = %q, want %q", test.elem, p, test.path) + expected := filepath.FromSlash(test.path) + if p := filepath.Join(test.elem...); p != expected { + t.Errorf("join(%q) = %q, want %q", test.elem, p, expected) } } } @@ -390,7 +402,34 @@ func mark(path string, info os.FileInfo, err error, errors *[]error, clear bool) return nil } +func chtmpdir(t *testing.T) (restore func()) { + oldwd, err := os.Getwd() + if err != nil { + t.Fatal("chtmpdir: %v", err) + } + d, err := ioutil.TempDir("", "test") + if err != nil { + t.Fatal("chtmpdir: %v", err) + } + if err := os.Chdir(d); err != nil { + t.Fatal("chtmpdir: %v", err) + } + return func() { + if err := os.Chdir(oldwd); err != nil { + t.Fatal("chtmpdir: %v", err) + } + os.RemoveAll(d) + } +} + func TestWalk(t *testing.T) { + if runtime.GOOS == "darwin" { + switch runtime.GOARCH { + case "arm", "arm64": + restore := chtmpdir(t) + defer restore() + } + } makeTree(t) errors := make([]error, 0, 10) clear := true @@ -474,6 +513,35 @@ func touch(t *testing.T, name string) { } } +func TestWalkSkipDirOnFile(t *testing.T) { + td, err := ioutil.TempDir("", "walktest") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(td) + + if err := os.MkdirAll(filepath.Join(td, "dir"), 0755); err != nil { + t.Fatal(err) + } + touch(t, filepath.Join(td, "dir/foo1")) + touch(t, filepath.Join(td, "dir/foo2")) + + sawFoo2 := false + filepath.Walk(td, func(path string, info os.FileInfo, err error) error { + if strings.HasSuffix(path, "foo2") { + sawFoo2 = true + } + if strings.HasSuffix(path, "foo1") { + return filepath.SkipDir + } + return nil + }) + + if sawFoo2 { + t.Errorf("SkipDir on file foo1 did not block processing of foo2") + } +} + func TestWalkFileError(t *testing.T) { td, err := ioutil.TempDir("", "walktest") if err != nil { @@ -999,10 +1067,14 @@ func TestDriveLetterInEvalSymlinks(t *testing.T) { } } -/* This test does not work gccgo, since the sources are arranged - differently. - -func TestBug3486(t *testing.T) { // http://code.google.com/p/go/issues/detail?id=3486 +func TestBug3486(t *testing.T) { // https://golang.org/issue/3486 + t.Skip("skipping test because gccgo sources are arranged differently.") + if runtime.GOOS == "darwin" { + switch runtime.GOARCH { + case "arm", "arm64": + t.Skipf("skipping on %s/%s", runtime.GOOS, runtime.GOARCH) + } + } root, err := filepath.EvalSymlinks(runtime.GOROOT() + "/test") if err != nil { t.Fatal(err) @@ -1032,5 +1104,3 @@ func TestBug3486(t *testing.T) { // http://code.google.com/p/go/issues/detail?id t.Fatalf("%q not seen", ken) } } - -*/ diff --git a/libgo/go/path/filepath/path_unix.go b/libgo/go/path/filepath/path_unix.go index 4e7d0d1b422..d241d78fa78 100644 --- a/libgo/go/path/filepath/path_unix.go +++ b/libgo/go/path/filepath/path_unix.go @@ -8,7 +8,7 @@ package filepath import "strings" -// IsAbs returns true if the path is absolute. +// IsAbs reports whether the path is absolute. func IsAbs(path string) bool { return strings.HasPrefix(path, "/") } @@ -34,3 +34,13 @@ func splitList(path string) []string { func abs(path string) (string, error) { return unixAbs(path) } + +func join(elem []string) string { + // If there's a bug here, fix the logic in ./path_plan9.go too. + for i, e := range elem { + if e != "" { + return Clean(strings.Join(elem[i:], string(Separator))) + } + } + return "" +} diff --git a/libgo/go/path/filepath/path_windows.go b/libgo/go/path/filepath/path_windows.go index ec50f6b264f..bcfe0a34b0a 100644 --- a/libgo/go/path/filepath/path_windows.go +++ b/libgo/go/path/filepath/path_windows.go @@ -13,7 +13,7 @@ func isSlash(c uint8) bool { return c == '\\' || c == '/' } -// IsAbs returns true if the path is absolute. +// IsAbs reports whether the path is absolute. func IsAbs(path string) (b bool) { l := volumeNameLen(path) if l == 0 { @@ -108,3 +108,40 @@ func splitList(path string) []string { func abs(path string) (string, error) { return syscall.FullPath(path) } + +func join(elem []string) string { + for i, e := range elem { + if e != "" { + return joinNonEmpty(elem[i:]) + } + } + return "" +} + +// joinNonEmpty is like join, but it assumes that the first element is non-empty. +func joinNonEmpty(elem []string) string { + // The following logic prevents Join from inadvertently creating a + // UNC path on Windows. Unless the first element is a UNC path, Join + // shouldn't create a UNC path. See golang.org/issue/9167. + p := Clean(strings.Join(elem, string(Separator))) + if !isUNC(p) { + return p + } + // p == UNC only allowed when the first element is a UNC path. + head := Clean(elem[0]) + if isUNC(head) { + return p + } + // head + tail == UNC, but joining two non-UNC paths should not result + // in a UNC path. Undo creation of UNC path. + tail := Clean(strings.Join(elem[1:], string(Separator))) + if head[len(head)-1] == Separator { + return head + tail + } + return head + string(Separator) + tail +} + +// isUNC reports whether path is a UNC path. +func isUNC(path string) bool { + return volumeNameLen(path) > 2 +} diff --git a/libgo/go/path/filepath/symlink_windows.go b/libgo/go/path/filepath/symlink_windows.go index 327c2c89a37..4b38f6fac3f 100644 --- a/libgo/go/path/filepath/symlink_windows.go +++ b/libgo/go/path/filepath/symlink_windows.go @@ -14,18 +14,17 @@ func toShort(path string) (string, error) { return "", err } b := p // GetShortPathName says we can reuse buffer - n, err := syscall.GetShortPathName(&p[0], &b[0], uint32(len(b))) - if err != nil { - return "", err - } - if n > uint32(len(b)) { - b = make([]uint16, n) + n := uint32(len(b)) + for { n, err = syscall.GetShortPathName(&p[0], &b[0], uint32(len(b))) if err != nil { return "", err } + if n <= uint32(len(b)) { + return syscall.UTF16ToString(b[:n]), nil + } + b = make([]uint16, n) } - return syscall.UTF16ToString(b), nil } func toLong(path string) (string, error) { @@ -34,19 +33,17 @@ func toLong(path string) (string, error) { return "", err } 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 := uint32(len(b)) + for { n, err = syscall.GetLongPathName(&p[0], &b[0], uint32(len(b))) if err != nil { return "", err } + if n <= uint32(len(b)) { + return syscall.UTF16ToString(b[:n]), nil + } + b = make([]uint16, n) } - b = b[:n] - return syscall.UTF16ToString(b), nil } func evalSymlinks(path string) (string, error) { diff --git a/libgo/go/path/match.go b/libgo/go/path/match.go index 8154bf60251..75dd3b38e7c 100644 --- a/libgo/go/path/match.go +++ b/libgo/go/path/match.go @@ -13,7 +13,7 @@ import ( // ErrBadPattern indicates a globbing pattern was malformed. var ErrBadPattern = errors.New("syntax error in pattern") -// Match returns true if name matches the shell file name pattern. +// Match reports whether name matches the shell file name pattern. // The pattern syntax is: // // pattern: diff --git a/libgo/go/path/path.go b/libgo/go/path/path.go index 98a6d529229..77f2185eaec 100644 --- a/libgo/go/path/path.go +++ b/libgo/go/path/path.go @@ -134,7 +134,7 @@ func Clean(path string) string { return out.string() } -// Split splits path immediately following the final slash. +// Split splits path immediately following the final slash, // separating it into a directory and file name component. // If there is no slash path, Split returns an empty dir and // file set to path. @@ -192,7 +192,7 @@ func Base(path string) string { return path } -// IsAbs returns true if the path is absolute. +// IsAbs reports whether the path is absolute. func IsAbs(path string) bool { return len(path) > 0 && path[0] == '/' } diff --git a/libgo/go/reflect/all_test.go b/libgo/go/reflect/all_test.go index bda87867c74..33ee9ed83cc 100644 --- a/libgo/go/reflect/all_test.go +++ b/libgo/go/reflect/all_test.go @@ -15,6 +15,7 @@ import ( . "reflect" "runtime" "sort" + "strconv" "strings" "sync" "testing" @@ -1052,6 +1053,11 @@ func TestChan(t *testing.T) { ok = cv.TrySend(ValueOf(6)) if !ok { t.Errorf("TrySend on empty chan failed") + select { + case x := <-c: + t.Errorf("TrySend failed but it did send %d", x) + default: + } } else { if i = <-c; i != 6 { t.Errorf("TrySend 6, recv %d", i) @@ -1376,7 +1382,7 @@ func selectWatcher() { for { time.Sleep(1 * time.Second) selectWatch.Lock() - if selectWatch.info != nil && time.Since(selectWatch.now) > 1*time.Second { + if selectWatch.info != nil && time.Since(selectWatch.now) > 10*time.Second { fmt.Fprintf(os.Stderr, "TestSelect:\n%s blocked indefinitely\n", fmtSelect(selectWatch.info)) panic("select stuck") } @@ -1501,6 +1507,17 @@ func TestCallWithStruct(t *testing.T) { } } +func BenchmarkCall(b *testing.B) { + fv := ValueOf(func(a, b string) {}) + b.ReportAllocs() + b.RunParallel(func(pb *testing.PB) { + args := []Value{ValueOf("a"), ValueOf("b")} + for pb.Next() { + fv.Call(args) + } + }) +} + func TestMakeFunc(t *testing.T) { f := dummy fv := MakeFunc(TypeOf(f), func(in []Value) []Value { return in }) @@ -2726,6 +2743,8 @@ var tagGetTests = []struct { {`protobuf:"PB(1,2)"`, `rotobuf`, ``}, {`protobuf:"PB(1,2)" json:"name"`, `json`, `name`}, {`protobuf:"PB(1,2)" json:"name"`, `protobuf`, `PB(1,2)`}, + {`k0:"values contain spaces" k1:"and\ttabs"`, "k0", "values contain spaces"}, + {`k0:"values contain spaces" k1:"and\ttabs"`, "k1", "and\ttabs"}, } func TestTagGet(t *testing.T) { @@ -3377,26 +3396,243 @@ func checkSameType(t *testing.T, x, y interface{}) { } func TestArrayOf(t *testing.T) { - // TODO(rsc): Finish ArrayOf and enable-test. - t.Skip("ArrayOf is not finished (and not exported)") - // check construction and use of type not in binary - type T int - at := ArrayOf(10, TypeOf(T(1))) - v := New(at).Elem() - for i := 0; i < v.Len(); i++ { - v.Index(i).Set(ValueOf(T(i))) - } - s := fmt.Sprint(v.Interface()) - want := "[0 1 2 3 4 5 6 7 8 9]" - if s != want { - t.Errorf("constructed array = %s, want %s", s, want) + for _, table := range []struct { + n int + value func(i int) interface{} + comparable bool + want string + }{ + { + n: 0, + value: func(i int) interface{} { type Tint int; return Tint(i) }, + comparable: true, + want: "[]", + }, + { + n: 10, + value: func(i int) interface{} { type Tint int; return Tint(i) }, + comparable: true, + want: "[0 1 2 3 4 5 6 7 8 9]", + }, + { + n: 10, + value: func(i int) interface{} { type Tfloat float64; return Tfloat(i) }, + comparable: true, + want: "[0 1 2 3 4 5 6 7 8 9]", + }, + { + n: 10, + value: func(i int) interface{} { type Tstring string; return Tstring(strconv.Itoa(i)) }, + comparable: true, + want: "[0 1 2 3 4 5 6 7 8 9]", + }, + { + n: 10, + value: func(i int) interface{} { type Tstruct struct{ V int }; return Tstruct{i} }, + comparable: true, + want: "[{0} {1} {2} {3} {4} {5} {6} {7} {8} {9}]", + }, + { + n: 10, + value: func(i int) interface{} { type Tint int; return []Tint{Tint(i)} }, + comparable: false, + want: "[[0] [1] [2] [3] [4] [5] [6] [7] [8] [9]]", + }, + { + n: 10, + value: func(i int) interface{} { type Tint int; return [1]Tint{Tint(i)} }, + comparable: true, + want: "[[0] [1] [2] [3] [4] [5] [6] [7] [8] [9]]", + }, + { + n: 10, + value: func(i int) interface{} { type Tstruct struct{ V [1]int }; return Tstruct{[1]int{i}} }, + comparable: true, + want: "[{[0]} {[1]} {[2]} {[3]} {[4]} {[5]} {[6]} {[7]} {[8]} {[9]}]", + }, + { + n: 10, + value: func(i int) interface{} { type Tstruct struct{ V []int }; return Tstruct{[]int{i}} }, + comparable: false, + want: "[{[0]} {[1]} {[2]} {[3]} {[4]} {[5]} {[6]} {[7]} {[8]} {[9]}]", + }, + { + n: 10, + value: func(i int) interface{} { type TstructUV struct{ U, V int }; return TstructUV{i, i} }, + comparable: true, + want: "[{0 0} {1 1} {2 2} {3 3} {4 4} {5 5} {6 6} {7 7} {8 8} {9 9}]", + }, + { + n: 10, + value: func(i int) interface{} { + type TstructUV struct { + U int + V float64 + } + return TstructUV{i, float64(i)} + }, + comparable: true, + want: "[{0 0} {1 1} {2 2} {3 3} {4 4} {5 5} {6 6} {7 7} {8 8} {9 9}]", + }, + } { + at := ArrayOf(table.n, TypeOf(table.value(0))) + v := New(at).Elem() + vok := New(at).Elem() + vnot := New(at).Elem() + for i := 0; i < v.Len(); i++ { + v.Index(i).Set(ValueOf(table.value(i))) + vok.Index(i).Set(ValueOf(table.value(i))) + j := i + if i+1 == v.Len() { + j = i + 1 + } + vnot.Index(i).Set(ValueOf(table.value(j))) // make it differ only by last element + } + s := fmt.Sprint(v.Interface()) + if s != table.want { + t.Errorf("constructed array = %s, want %s", s, table.want) + } + + if table.comparable != at.Comparable() { + t.Errorf("constructed array (%#v) is comparable=%v, want=%v", v.Interface(), at.Comparable(), table.comparable) + } + if table.comparable { + if table.n > 0 { + if DeepEqual(vnot.Interface(), v.Interface()) { + t.Errorf( + "arrays (%#v) compare ok (but should not)", + v.Interface(), + ) + } + } + if !DeepEqual(vok.Interface(), v.Interface()) { + t.Errorf( + "arrays (%#v) compare NOT-ok (but should)", + v.Interface(), + ) + } + } } // check that type already in binary is found + type T int checkSameType(t, Zero(ArrayOf(5, TypeOf(T(1)))).Interface(), [5]T{}) } +func TestArrayOfGC(t *testing.T) { + type T *uintptr + tt := TypeOf(T(nil)) + const n = 100 + var x []interface{} + for i := 0; i < n; i++ { + v := New(ArrayOf(n, tt)).Elem() + for j := 0; j < v.Len(); j++ { + p := new(uintptr) + *p = uintptr(i*n + j) + v.Index(j).Set(ValueOf(p).Convert(tt)) + } + x = append(x, v.Interface()) + } + runtime.GC() + + for i, xi := range x { + v := ValueOf(xi) + for j := 0; j < v.Len(); j++ { + k := v.Index(j).Elem().Interface() + if k != uintptr(i*n+j) { + t.Errorf("lost x[%d][%d] = %d, want %d", i, j, k, i*n+j) + } + } + } +} + +func TestArrayOfAlg(t *testing.T) { + at := ArrayOf(6, TypeOf(byte(0))) + v1 := New(at).Elem() + v2 := New(at).Elem() + if v1.Interface() != v1.Interface() { + t.Errorf("constructed array %v not equal to itself", v1.Interface()) + } + v1.Index(5).Set(ValueOf(byte(1))) + if i1, i2 := v1.Interface(), v2.Interface(); i1 == i2 { + t.Errorf("constructed arrays %v and %v should not be equal", i1, i2) + } + + at = ArrayOf(6, TypeOf([]int(nil))) + v1 = New(at).Elem() + shouldPanic(func() { _ = v1.Interface() == v1.Interface() }) +} + +func TestArrayOfGenericAlg(t *testing.T) { + at1 := ArrayOf(5, TypeOf(string(""))) + at := ArrayOf(6, at1) + v1 := New(at).Elem() + v2 := New(at).Elem() + if v1.Interface() != v1.Interface() { + t.Errorf("constructed array %v not equal to itself", v1.Interface()) + } + + v1.Index(0).Index(0).Set(ValueOf("abc")) + v2.Index(0).Index(0).Set(ValueOf("efg")) + if i1, i2 := v1.Interface(), v2.Interface(); i1 == i2 { + t.Errorf("constructed arrays %v and %v should not be equal", i1, i2) + } + + v1.Index(0).Index(0).Set(ValueOf("abc")) + v2.Index(0).Index(0).Set(ValueOf((v1.Index(0).Index(0).String() + " ")[:3])) + if i1, i2 := v1.Interface(), v2.Interface(); i1 != i2 { + t.Errorf("constructed arrays %v and %v should be equal", i1, i2) + } + + // Test hash + m := MakeMap(MapOf(at, TypeOf(int(0)))) + m.SetMapIndex(v1, ValueOf(1)) + if i1, i2 := v1.Interface(), v2.Interface(); !m.MapIndex(v2).IsValid() { + t.Errorf("constructed arrays %v and %v have different hashes", i1, i2) + } +} + +func TestArrayOfDirectIface(t *testing.T) { + t.Skip("skipping test because gccgo uses a different directiface value") + { + type T [1]*byte + i1 := Zero(TypeOf(T{})).Interface() + v1 := ValueOf(&i1).Elem() + p1 := v1.InterfaceData()[1] + + i2 := Zero(ArrayOf(1, PtrTo(TypeOf(int8(0))))).Interface() + v2 := ValueOf(&i2).Elem() + p2 := v2.InterfaceData()[1] + + if p1 != 0 { + t.Errorf("got p1=%v. want=%v", p1, nil) + } + + if p2 != 0 { + t.Errorf("got p2=%v. want=%v", p2, nil) + } + } + { + type T [0]*byte + i1 := Zero(TypeOf(T{})).Interface() + v1 := ValueOf(&i1).Elem() + p1 := v1.InterfaceData()[1] + + i2 := Zero(ArrayOf(0, PtrTo(TypeOf(int8(0))))).Interface() + v2 := ValueOf(&i2).Elem() + p2 := v2.InterfaceData()[1] + + if p1 == 0 { + t.Errorf("got p1=%v. want=not-%v", p1, nil) + } + + if p2 == 0 { + t.Errorf("got p2=%v. want=not-%v", p2, nil) + } + } +} + func TestSliceOf(t *testing.T) { // check construction and use of type not in binary type T int @@ -3489,6 +3725,26 @@ func TestChanOf(t *testing.T) { checkSameType(t, Zero(ChanOf(BothDir, TypeOf(T1(1)))).Interface(), (chan T1)(nil)) } +func TestChanOfDir(t *testing.T) { + // check construction and use of type not in binary + type T string + crt := ChanOf(RecvDir, TypeOf(T(""))) + cst := ChanOf(SendDir, TypeOf(T(""))) + + // check that type already in binary is found + type T1 int + checkSameType(t, Zero(ChanOf(RecvDir, TypeOf(T1(1)))).Interface(), (<-chan T1)(nil)) + checkSameType(t, Zero(ChanOf(SendDir, TypeOf(T1(1)))).Interface(), (chan<- T1)(nil)) + + // check String form of ChanDir + if crt.ChanDir().String() != "<-chan" { + t.Errorf("chan dir: have %q, want %q", crt.ChanDir().String(), "<-chan") + } + if cst.ChanDir().String() != "chan<-" { + t.Errorf("chan dir: have %q, want %q", cst.ChanDir().String(), "chan<-") + } +} + func TestChanOfGC(t *testing.T) { done := make(chan bool, 1) go func() { @@ -3632,6 +3888,67 @@ func TestMapOfGCValues(t *testing.T) { } } +func TestTypelinksSorted(t *testing.T) { + var last string + for i, n := range TypeLinks() { + if n < last { + t.Errorf("typelinks not sorted: %q [%d] > %q [%d]", last, i-1, n, i) + } + last = n + } +} + +func TestFuncOf(t *testing.T) { + // check construction and use of type not in binary + type K string + type V float64 + + fn := func(args []Value) []Value { + if len(args) != 1 { + t.Errorf("args == %v, want exactly one arg", args) + } else if args[0].Type() != TypeOf(K("")) { + t.Errorf("args[0] is type %v, want %v", args[0].Type, TypeOf(K(""))) + } else if args[0].String() != "gopher" { + t.Errorf("args[0] = %q, want %q", args[0].String(), "gopher") + } + return []Value{ValueOf(V(3.14))} + } + v := MakeFunc(FuncOf([]Type{TypeOf(K(""))}, []Type{TypeOf(V(0))}, false), fn) + + outs := v.Call([]Value{ValueOf(K("gopher"))}) + if len(outs) != 1 { + t.Fatalf("v.Call returned %v, want exactly one result", outs) + } else if outs[0].Type() != TypeOf(V(0)) { + t.Fatalf("c.Call[0] is type %v, want %v", outs[0].Type, TypeOf(V(0))) + } + f := outs[0].Float() + if f != 3.14 { + t.Errorf("constructed func returned %f, want %f", f, 3.14) + } + + // check that types already in binary are found + type T1 int + testCases := []struct { + in, out []Type + variadic bool + want interface{} + }{ + {in: []Type{TypeOf(T1(0))}, want: (func(T1))(nil)}, + {in: []Type{TypeOf(int(0))}, want: (func(int))(nil)}, + {in: []Type{SliceOf(TypeOf(int(0)))}, variadic: true, want: (func(...int))(nil)}, + {in: []Type{TypeOf(int(0))}, out: []Type{TypeOf(false)}, want: (func(int) bool)(nil)}, + {in: []Type{TypeOf(int(0))}, out: []Type{TypeOf(false), TypeOf("")}, want: (func(int) (bool, string))(nil)}, + } + for _, tt := range testCases { + checkSameType(t, Zero(FuncOf(tt.in, tt.out, tt.variadic)).Interface(), tt.want) + } + + // check that variadic requires last element be a slice. + FuncOf([]Type{TypeOf(1), TypeOf(""), SliceOf(TypeOf(false))}, nil, true) + shouldPanic(func() { FuncOf([]Type{TypeOf(0), TypeOf(""), TypeOf(false)}, nil, true) }) + shouldPanic(func() { FuncOf(nil, nil, true) }) +} + type B1 struct { X int Y int @@ -4077,15 +4394,16 @@ func TestCallGC(t *testing.T) { } type funcLayoutTest struct { - rcvr, t Type - argsize, retOffset uintptr - stack []byte + rcvr, t Type + size, argsize, retOffset uintptr + stack []byte // pointer bitmap: 1 is pointer, 0 is scalar (or uninitialized) + gc []byte } var funcLayoutTests []funcLayoutTest func init() { - var argAlign = PtrSize + var argAlign uintptr = PtrSize if runtime.GOARCH == "amd64p32" { argAlign = 2 * PtrSize } @@ -4097,24 +4415,28 @@ func init() { funcLayoutTest{ nil, ValueOf(func(a, b string) string { return "" }).Type(), + 6 * PtrSize, 4 * PtrSize, 4 * PtrSize, - []byte{BitsPointer, BitsScalar, BitsPointer}, + []byte{1, 0, 1}, + []byte{1, 0, 1, 0, 1}, }) var r []byte if PtrSize == 4 { - r = []byte{BitsScalar, BitsScalar, BitsScalar, BitsPointer} + r = []byte{0, 0, 0, 1} } else { - r = []byte{BitsScalar, BitsScalar, BitsPointer} + r = []byte{0, 0, 1} } funcLayoutTests = append(funcLayoutTests, funcLayoutTest{ nil, ValueOf(func(a, b, c uint32, p *byte, d uint16) {}).Type(), + roundup(roundup(3*4, PtrSize)+PtrSize+2, argAlign), roundup(3*4, PtrSize) + PtrSize + 2, roundup(roundup(3*4, PtrSize)+PtrSize+2, argAlign), r, + r, }) funcLayoutTests = append(funcLayoutTests, @@ -4123,7 +4445,9 @@ func init() { ValueOf(func(a map[int]int, b uintptr, c interface{}) {}).Type(), 4 * PtrSize, 4 * PtrSize, - []byte{BitsPointer, BitsScalar, BitsPointer, BitsPointer}, + 4 * PtrSize, + []byte{1, 0, 1, 1}, + []byte{1, 0, 1, 1}, }) type S struct { @@ -4136,23 +4460,66 @@ func init() { ValueOf(func(a S) {}).Type(), 4 * PtrSize, 4 * PtrSize, - []byte{BitsScalar, BitsScalar, BitsPointer, BitsPointer}, + 4 * PtrSize, + []byte{0, 0, 1, 1}, + []byte{0, 0, 1, 1}, }) funcLayoutTests = append(funcLayoutTests, funcLayoutTest{ ValueOf((*byte)(nil)).Type(), ValueOf(func(a uintptr, b *int) {}).Type(), + roundup(3*PtrSize, argAlign), 3 * PtrSize, roundup(3*PtrSize, argAlign), - []byte{BitsPointer, BitsScalar, BitsPointer}, + []byte{1, 0, 1}, + []byte{1, 0, 1}, + }) + + funcLayoutTests = append(funcLayoutTests, + funcLayoutTest{ + nil, + ValueOf(func(a uintptr) {}).Type(), + roundup(PtrSize, argAlign), + PtrSize, + roundup(PtrSize, argAlign), + []byte{}, + []byte{}, + }) + + funcLayoutTests = append(funcLayoutTests, + funcLayoutTest{ + nil, + ValueOf(func() uintptr { return 0 }).Type(), + PtrSize, + 0, + 0, + []byte{}, + []byte{}, + }) + + funcLayoutTests = append(funcLayoutTests, + funcLayoutTest{ + ValueOf(uintptr(0)).Type(), + ValueOf(func(a uintptr) {}).Type(), + 2 * PtrSize, + 2 * PtrSize, + 2 * PtrSize, + []byte{1}, + []byte{1}, + // Note: this one is tricky, as the receiver is not a pointer. But we + // pass the receiver by reference to the autogenerated pointer-receiver + // version of the function. }) } func TestFuncLayout(t *testing.T) { t.Skip("gccgo does not use funcLayout") for _, lt := range funcLayoutTests { - _, argsize, retOffset, stack := FuncLayout(lt.t, lt.rcvr) + typ, argsize, retOffset, stack, gc, ptrs := FuncLayout(lt.t, lt.rcvr) + if typ.Size() != lt.size { + t.Errorf("funcLayout(%v, %v).size=%d, want %d", lt.t, lt.rcvr, typ.Size(), lt.size) + } if argsize != lt.argsize { t.Errorf("funcLayout(%v, %v).argsize=%d, want %d", lt.t, lt.rcvr, argsize, lt.argsize) } @@ -4162,5 +4529,260 @@ func TestFuncLayout(t *testing.T) { if !bytes.Equal(stack, lt.stack) { t.Errorf("funcLayout(%v, %v).stack=%v, want %v", lt.t, lt.rcvr, stack, lt.stack) } + if !bytes.Equal(gc, lt.gc) { + t.Errorf("funcLayout(%v, %v).gc=%v, want %v", lt.t, lt.rcvr, gc, lt.gc) + } + if ptrs && len(stack) == 0 || !ptrs && len(stack) > 0 { + t.Errorf("funcLayout(%v, %v) pointers flag=%v, want %v", lt.t, lt.rcvr, ptrs, !ptrs) + } + } +} + +func verifyGCBits(t *testing.T, typ Type, bits []byte) { + heapBits := GCBits(New(typ).Interface()) + if !bytes.Equal(heapBits, bits) { + t.Errorf("heapBits incorrect for %v\nhave %v\nwant %v", typ, heapBits, bits) + } +} + +func verifyGCBitsSlice(t *testing.T, typ Type, cap int, bits []byte) { + // Creating a slice causes the runtime to repeat a bitmap, + // which exercises a different path from making the compiler + // repeat a bitmap for a small array or executing a repeat in + // a GC program. + val := MakeSlice(typ, 0, cap) + data := NewAt(ArrayOf(cap, typ), unsafe.Pointer(val.Pointer())) + heapBits := GCBits(data.Interface()) + // Repeat the bitmap for the slice size, trimming scalars in + // the last element. + bits = rep(cap, bits) + for len(bits) > 2 && bits[len(bits)-1] == 0 { + bits = bits[:len(bits)-1] + } + if !bytes.Equal(heapBits, bits) { + t.Errorf("heapBits incorrect for make(%v, 0, %v)\nhave %v\nwant %v", typ, cap, heapBits, bits) + } +} + +func TestGCBits(t *testing.T) { + t.Skip("gccgo does not use gcbits yet") + + verifyGCBits(t, TypeOf((*byte)(nil)), []byte{1}) + + // Building blocks for types seen by the compiler (like [2]Xscalar). + // The compiler will create the type structures for the derived types, + // including their GC metadata. + type Xscalar struct{ x uintptr } + type Xptr struct{ x *byte } + type Xptrscalar struct { + *byte + uintptr + } + type Xscalarptr struct { + uintptr + *byte + } + type Xbigptrscalar struct { + _ [100]*byte + _ [100]uintptr + } + + var Tscalar, Tint64, Tptr, Tscalarptr, Tptrscalar, Tbigptrscalar Type + { + // Building blocks for types constructed by reflect. + // This code is in a separate block so that code below + // cannot accidentally refer to these. + // The compiler must NOT see types derived from these + // (for example, [2]Scalar must NOT appear in the program), + // or else reflect will use it instead of having to construct one. + // The goal is to test the construction. + type Scalar struct{ x uintptr } + type Ptr struct{ x *byte } + type Ptrscalar struct { + *byte + uintptr + } + type Scalarptr struct { + uintptr + *byte + } + type Bigptrscalar struct { + _ [100]*byte + _ [100]uintptr + } + type Int64 int64 + Tscalar = TypeOf(Scalar{}) + Tint64 = TypeOf(Int64(0)) + Tptr = TypeOf(Ptr{}) + Tscalarptr = TypeOf(Scalarptr{}) + Tptrscalar = TypeOf(Ptrscalar{}) + Tbigptrscalar = TypeOf(Bigptrscalar{}) + } + + empty := []byte{} + + verifyGCBits(t, TypeOf(Xscalar{}), empty) + verifyGCBits(t, Tscalar, empty) + verifyGCBits(t, TypeOf(Xptr{}), lit(1)) + verifyGCBits(t, Tptr, lit(1)) + verifyGCBits(t, TypeOf(Xscalarptr{}), lit(0, 1)) + verifyGCBits(t, Tscalarptr, lit(0, 1)) + verifyGCBits(t, TypeOf(Xptrscalar{}), lit(1)) + verifyGCBits(t, Tptrscalar, lit(1)) + + verifyGCBits(t, TypeOf([0]Xptr{}), empty) + verifyGCBits(t, ArrayOf(0, Tptr), empty) + verifyGCBits(t, TypeOf([1]Xptrscalar{}), lit(1)) + verifyGCBits(t, ArrayOf(1, Tptrscalar), lit(1)) + verifyGCBits(t, TypeOf([2]Xscalar{}), empty) + verifyGCBits(t, ArrayOf(2, Tscalar), empty) + verifyGCBits(t, TypeOf([10000]Xscalar{}), empty) + verifyGCBits(t, ArrayOf(10000, Tscalar), empty) + verifyGCBits(t, TypeOf([2]Xptr{}), lit(1, 1)) + verifyGCBits(t, ArrayOf(2, Tptr), lit(1, 1)) + verifyGCBits(t, TypeOf([10000]Xptr{}), rep(10000, lit(1))) + verifyGCBits(t, ArrayOf(10000, Tptr), rep(10000, lit(1))) + verifyGCBits(t, TypeOf([2]Xscalarptr{}), lit(0, 1, 0, 1)) + verifyGCBits(t, ArrayOf(2, Tscalarptr), lit(0, 1, 0, 1)) + verifyGCBits(t, TypeOf([10000]Xscalarptr{}), rep(10000, lit(0, 1))) + verifyGCBits(t, ArrayOf(10000, Tscalarptr), rep(10000, lit(0, 1))) + verifyGCBits(t, TypeOf([2]Xptrscalar{}), lit(1, 0, 1)) + verifyGCBits(t, ArrayOf(2, Tptrscalar), lit(1, 0, 1)) + verifyGCBits(t, TypeOf([10000]Xptrscalar{}), rep(10000, lit(1, 0))) + verifyGCBits(t, ArrayOf(10000, Tptrscalar), rep(10000, lit(1, 0))) + verifyGCBits(t, TypeOf([1][10000]Xptrscalar{}), rep(10000, lit(1, 0))) + verifyGCBits(t, ArrayOf(1, ArrayOf(10000, Tptrscalar)), rep(10000, lit(1, 0))) + verifyGCBits(t, TypeOf([2][10000]Xptrscalar{}), rep(2*10000, lit(1, 0))) + verifyGCBits(t, ArrayOf(2, ArrayOf(10000, Tptrscalar)), rep(2*10000, lit(1, 0))) + verifyGCBits(t, TypeOf([4]Xbigptrscalar{}), join(rep(3, join(rep(100, lit(1)), rep(100, lit(0)))), rep(100, lit(1)))) + verifyGCBits(t, ArrayOf(4, Tbigptrscalar), join(rep(3, join(rep(100, lit(1)), rep(100, lit(0)))), rep(100, lit(1)))) + + verifyGCBitsSlice(t, TypeOf([]Xptr{}), 0, empty) + verifyGCBitsSlice(t, SliceOf(Tptr), 0, empty) + verifyGCBitsSlice(t, TypeOf([]Xptrscalar{}), 1, lit(1)) + verifyGCBitsSlice(t, SliceOf(Tptrscalar), 1, lit(1)) + verifyGCBitsSlice(t, TypeOf([]Xscalar{}), 2, lit(0)) + verifyGCBitsSlice(t, SliceOf(Tscalar), 2, lit(0)) + verifyGCBitsSlice(t, TypeOf([]Xscalar{}), 10000, lit(0)) + verifyGCBitsSlice(t, SliceOf(Tscalar), 10000, lit(0)) + verifyGCBitsSlice(t, TypeOf([]Xptr{}), 2, lit(1)) + verifyGCBitsSlice(t, SliceOf(Tptr), 2, lit(1)) + verifyGCBitsSlice(t, TypeOf([]Xptr{}), 10000, lit(1)) + verifyGCBitsSlice(t, SliceOf(Tptr), 10000, lit(1)) + verifyGCBitsSlice(t, TypeOf([]Xscalarptr{}), 2, lit(0, 1)) + verifyGCBitsSlice(t, SliceOf(Tscalarptr), 2, lit(0, 1)) + verifyGCBitsSlice(t, TypeOf([]Xscalarptr{}), 10000, lit(0, 1)) + verifyGCBitsSlice(t, SliceOf(Tscalarptr), 10000, lit(0, 1)) + verifyGCBitsSlice(t, TypeOf([]Xptrscalar{}), 2, lit(1, 0)) + verifyGCBitsSlice(t, SliceOf(Tptrscalar), 2, lit(1, 0)) + verifyGCBitsSlice(t, TypeOf([]Xptrscalar{}), 10000, lit(1, 0)) + verifyGCBitsSlice(t, SliceOf(Tptrscalar), 10000, lit(1, 0)) + verifyGCBitsSlice(t, TypeOf([][10000]Xptrscalar{}), 1, rep(10000, lit(1, 0))) + verifyGCBitsSlice(t, SliceOf(ArrayOf(10000, Tptrscalar)), 1, rep(10000, lit(1, 0))) + verifyGCBitsSlice(t, TypeOf([][10000]Xptrscalar{}), 2, rep(10000, lit(1, 0))) + verifyGCBitsSlice(t, SliceOf(ArrayOf(10000, Tptrscalar)), 2, rep(10000, lit(1, 0))) + verifyGCBitsSlice(t, TypeOf([]Xbigptrscalar{}), 4, join(rep(100, lit(1)), rep(100, lit(0)))) + verifyGCBitsSlice(t, SliceOf(Tbigptrscalar), 4, join(rep(100, lit(1)), rep(100, lit(0)))) + + verifyGCBits(t, TypeOf((chan [100]Xscalar)(nil)), lit(1)) + verifyGCBits(t, ChanOf(BothDir, ArrayOf(100, Tscalar)), lit(1)) + + verifyGCBits(t, TypeOf((func([10000]Xscalarptr))(nil)), lit(1)) + verifyGCBits(t, FuncOf([]Type{ArrayOf(10000, Tscalarptr)}, nil, false), lit(1)) + + verifyGCBits(t, TypeOf((map[[10000]Xscalarptr]Xscalar)(nil)), lit(1)) + verifyGCBits(t, MapOf(ArrayOf(10000, Tscalarptr), Tscalar), lit(1)) + + verifyGCBits(t, TypeOf((*[10000]Xscalar)(nil)), lit(1)) + verifyGCBits(t, PtrTo(ArrayOf(10000, Tscalar)), lit(1)) + + verifyGCBits(t, TypeOf(([][10000]Xscalar)(nil)), lit(1)) + verifyGCBits(t, SliceOf(ArrayOf(10000, Tscalar)), lit(1)) + + hdr := make([]byte, 8/PtrSize) + + verifyMapBucket := func(t *testing.T, k, e Type, m interface{}, want []byte) { + verifyGCBits(t, MapBucketOf(k, e), want) + verifyGCBits(t, CachedBucketOf(TypeOf(m)), want) + } + verifyMapBucket(t, + Tscalar, Tptr, + map[Xscalar]Xptr(nil), + join(hdr, rep(8, lit(0)), rep(8, lit(1)), lit(1))) + verifyMapBucket(t, + Tscalarptr, Tptr, + map[Xscalarptr]Xptr(nil), + join(hdr, rep(8, lit(0, 1)), rep(8, lit(1)), lit(1))) + verifyMapBucket(t, Tint64, Tptr, + map[int64]Xptr(nil), + join(hdr, rep(8, rep(8/PtrSize, lit(0))), rep(8, lit(1)), naclpad(), lit(1))) + verifyMapBucket(t, + Tscalar, Tscalar, + map[Xscalar]Xscalar(nil), + empty) + verifyMapBucket(t, + ArrayOf(2, Tscalarptr), ArrayOf(3, Tptrscalar), + map[[2]Xscalarptr][3]Xptrscalar(nil), + join(hdr, rep(8*2, lit(0, 1)), rep(8*3, lit(1, 0)), lit(1))) + verifyMapBucket(t, + ArrayOf(64/PtrSize, Tscalarptr), ArrayOf(64/PtrSize, Tptrscalar), + map[[64 / PtrSize]Xscalarptr][64 / PtrSize]Xptrscalar(nil), + join(hdr, rep(8*64/PtrSize, lit(0, 1)), rep(8*64/PtrSize, lit(1, 0)), lit(1))) + verifyMapBucket(t, + ArrayOf(64/PtrSize+1, Tscalarptr), ArrayOf(64/PtrSize, Tptrscalar), + map[[64/PtrSize + 1]Xscalarptr][64 / PtrSize]Xptrscalar(nil), + join(hdr, rep(8, lit(1)), rep(8*64/PtrSize, lit(1, 0)), lit(1))) + verifyMapBucket(t, + ArrayOf(64/PtrSize, Tscalarptr), ArrayOf(64/PtrSize+1, Tptrscalar), + map[[64 / PtrSize]Xscalarptr][64/PtrSize + 1]Xptrscalar(nil), + join(hdr, rep(8*64/PtrSize, lit(0, 1)), rep(8, lit(1)), lit(1))) + verifyMapBucket(t, + ArrayOf(64/PtrSize+1, Tscalarptr), ArrayOf(64/PtrSize+1, Tptrscalar), + map[[64/PtrSize + 1]Xscalarptr][64/PtrSize + 1]Xptrscalar(nil), + join(hdr, rep(8, lit(1)), rep(8, lit(1)), lit(1))) +} + +func naclpad() []byte { + if runtime.GOARCH == "amd64p32" { + return lit(0) + } + return nil +} + +func rep(n int, b []byte) []byte { return bytes.Repeat(b, n) } +func join(b ...[]byte) []byte { return bytes.Join(b, nil) } +func lit(x ...byte) []byte { return x } + +func TestTypeOfTypeOf(t *testing.T) { + // Check that all the type constructors return concrete *rtype implementations. + // It's difficult to test directly because the reflect package is only at arm's length. + // The easiest thing to do is just call a function that crashes if it doesn't get an *rtype. + check := func(name string, typ Type) { + if underlying := TypeOf(typ).String(); underlying != "*reflect.rtype" { + t.Errorf("%v returned %v, not *reflect.rtype", name, underlying) + } + } + + type T struct{ int } + check("TypeOf", TypeOf(T{})) + + check("ArrayOf", ArrayOf(10, TypeOf(T{}))) + check("ChanOf", ChanOf(BothDir, TypeOf(T{}))) + check("FuncOf", FuncOf([]Type{TypeOf(T{})}, nil, false)) + check("MapOf", MapOf(TypeOf(T{}), TypeOf(T{}))) + check("PtrTo", PtrTo(TypeOf(T{}))) + check("SliceOf", SliceOf(TypeOf(T{}))) +} + +type XM struct{} + +func (*XM) String() string { return "" } + +func TestPtrToMethods(t *testing.T) { + var y struct{ XM } + yp := New(TypeOf(y)).Interface() + _, ok := yp.(fmt.Stringer) + if !ok { + t.Fatal("does not implement Stringer, but should") } } diff --git a/libgo/go/reflect/example_test.go b/libgo/go/reflect/example_test.go index cca28eeece8..8ebf9765b8d 100644 --- a/libgo/go/reflect/example_test.go +++ b/libgo/go/reflect/example_test.go @@ -6,6 +6,8 @@ package reflect_test import ( "fmt" + "io" + "os" "reflect" ) @@ -64,3 +66,16 @@ func ExampleStructTag() { // Output: // blue gopher } + +func ExampleTypeOf() { + // As interface types are only used for static typing, a + // common idiom to find the reflection Type for an interface + // type Foo is to use a *Foo value. + writerType := reflect.TypeOf((*io.Writer)(nil)).Elem() + + fileType := reflect.TypeOf((*os.File)(nil)) + fmt.Println(fileType.Implements(writerType)) + + // Output: + // true +} diff --git a/libgo/go/reflect/export_test.go b/libgo/go/reflect/export_test.go index 49c45e82b2e..89473d352a7 100644 --- a/libgo/go/reflect/export_test.go +++ b/libgo/go/reflect/export_test.go @@ -15,13 +15,29 @@ func IsRO(v Value) bool { return v.flag&flagRO != 0 } -var ArrayOf = arrayOf var CallGC = &callGC const PtrSize = ptrSize -const BitsPointer = bitsPointer -const BitsScalar = bitsScalar -func FuncLayout(t Type, rcvr Type) (frametype Type, argSize, retOffset uintptr, stack []byte) { +func FuncLayout(t Type, rcvr Type) (frametype Type, argSize, retOffset uintptr, stack []byte, gc []byte, ptrs bool) { return } + +func TypeLinks() []string { + return nil +} + +var GCBits = gcbits + +// Will be provided by runtime eventually. +func gcbits(interface{}) []byte { + return nil +} + +func MapBucketOf(x, y Type) Type { + return nil +} + +func CachedBucketOf(m Type) Type { + return nil +} diff --git a/libgo/go/reflect/type.go b/libgo/go/reflect/type.go index 5cdfba55648..e488938a13f 100644 --- a/libgo/go/reflect/type.go +++ b/libgo/go/reflect/type.go @@ -12,7 +12,7 @@ // for that type. // // See "The Laws of Reflection" for an introduction to reflection in Go: -// http://golang.org/doc/articles/laws_of_reflection.html +// https://golang.org/doc/articles/laws_of_reflection.html package reflect import ( @@ -90,16 +90,16 @@ type Type interface { // Kind returns the specific kind of this type. Kind() Kind - // Implements returns true if the type implements the interface type u. + // Implements reports whether the type implements the interface type u. Implements(u Type) bool - // AssignableTo returns true if a value of the type is assignable to type u. + // AssignableTo reports whether a value of the type is assignable to type u. AssignableTo(u Type) bool - // ConvertibleTo returns true if a value of the type is convertible to type u. + // ConvertibleTo reports whether a value of the type is convertible to type u. ConvertibleTo(u Type) bool - // Comparable returns true if values of this type are comparable. + // Comparable reports whether values of this type are comparable. Comparable() bool // Methods applicable only to some types, depending on Kind. @@ -123,7 +123,7 @@ type Type interface { // It panics if the type's Kind is not Chan. ChanDir() ChanDir - // IsVariadic returns true if a function type's final input parameter + // IsVariadic reports whether a function type's final input parameter // is a "..." parameter. If so, t.In(t.NumIn() - 1) returns the parameter's // implicit actual type []T. // @@ -204,9 +204,9 @@ type Type interface { // See golang.org/issue/4876 for more details. /* - * These data structures are known to the compiler (../../cmd/gc/reflect.c). + * These data structures are known to the compiler (../../cmd/internal/gc/reflect.go). * A few are known to ../runtime/type.go to convey to debuggers. - * They are also known to ../runtime/type.h. + * They are also known to ../runtime/type.go. */ // A Kind represents the specific kind of type that a Type represents. @@ -255,8 +255,8 @@ type rtype struct { size uintptr hash uint32 // hash of type; avoids computation in hash tables - hashfn func(unsafe.Pointer, uintptr) // hash function - equalfn func(unsafe.Pointer, unsafe.Pointer, uintptr) // equality function + hashfn func(unsafe.Pointer, uintptr) uintptr // hash function + equalfn func(unsafe.Pointer, unsafe.Pointer, uintptr) bool // equality function gc unsafe.Pointer // garbage collection data string *string // string form; unnecessary but undeniably useful @@ -392,7 +392,7 @@ type Method struct { // 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 + // See https://golang.org/ref/spec#Uniqueness_of_identifiers Name string PkgPath string @@ -548,7 +548,7 @@ func (t *uncommonType) MethodByName(name string) (m Method, ok bool) { return } -// TODO(rsc): 6g supplies these, but they are not +// TODO(rsc): gc supplies these, but they are not // as efficient as they could be: they have commonType // as the receiver instead of *rtype. func (t *rtype) NumMethod() int { @@ -758,7 +758,7 @@ type StructField struct { // 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 + // See https://golang.org/ref/spec#Uniqueness_of_identifiers Name string PkgPath string @@ -784,8 +784,11 @@ type StructTag string // If the tag does not have the conventional format, the value // returned by Get is unspecified. func (tag StructTag) Get(key string) string { + // When modifying this code, also update the validateStructTag code + // in golang.org/x/tools/cmd/vet/structtag.go. + for tag != "" { - // skip leading space + // Skip leading space. i := 0 for i < len(tag) && tag[i] == ' ' { i++ @@ -795,19 +798,21 @@ func (tag StructTag) Get(key string) string { break } - // scan to colon. - // a space or a quote is a syntax error + // Scan to colon. A space, a quote or a control character is a syntax error. + // Strictly speaking, control chars include the range [0x7f, 0x9f], not just + // [0x00, 0x1f], but in practice, we ignore the multi-byte control characters + // as it is simpler to inspect the tag's bytes than the tag's runes. i = 0 - for i < len(tag) && tag[i] != ' ' && tag[i] != ':' && tag[i] != '"' { + for i < len(tag) && tag[i] > ' ' && tag[i] != ':' && tag[i] != '"' && tag[i] != 0x7f { i++ } - if i+1 >= len(tag) || tag[i] != ':' || tag[i+1] != '"' { + if i == 0 || i+1 >= len(tag) || tag[i] != ':' || tag[i+1] != '"' { break } name := string(tag[:i]) tag = tag[i+1:] - // scan quoted string to find value + // Scan quoted string to find value. i = 1 for i < len(tag) && tag[i] != '"' { if tag[i] == '\\' { @@ -822,7 +827,10 @@ func (tag StructTag) Get(key string) string { tag = tag[i+1:] if key == name { - value, _ := strconv.Unquote(qvalue) + value, err := strconv.Unquote(qvalue) + if err != nil { + break + } return value } } @@ -1024,8 +1032,8 @@ func (t *structType) FieldByName(name string) (f StructField, present bool) { return t.FieldByNameFunc(func(s string) bool { return s == name }) } -// TypeOf returns the reflection Type of the value in the interface{}. -// TypeOf(nil) returns nil. +// TypeOf returns the reflection Type that represents the dynamic type of i. +// If i is a nil interface value, TypeOf returns nil. func TypeOf(i interface{}) Type { eface := *(*emptyInterface)(unsafe.Pointer(&i)) return toType(eface.typ) @@ -1109,7 +1117,8 @@ func (t *rtype) ptrTo() *rtype { return r.(*rtype) } - // initialize p using *byte's ptrType as a prototype. + // Create a new ptrType starting with the description + // of an *unsafe.Pointer. p = new(ptrType) var iptr interface{} = (*unsafe.Pointer)(nil) prototype := *(**ptrType)(unsafe.Pointer(&iptr)) @@ -1145,6 +1154,7 @@ func (t *rtype) ptrTo() *rtype { q := canonicalize(&p.rtype) p = (*ptrType)(unsafe.Pointer(q.(*rtype))) + ptrMap.m[t] = p ptrMap.Unlock() return &p.rtype } @@ -1211,7 +1221,7 @@ func (t *rtype) Comparable() bool { } } -// implements returns true if the type V implements the interface type T. +// implements reports whether the type V implements the interface type T. func implements(T, V *rtype) bool { if T.Kind() != Interface { return false @@ -1232,7 +1242,7 @@ func implements(T, V *rtype) bool { // methods along the way, or else V does not implement T. // This lets us run the scan in overall linear time instead of // the quadratic time a naive search would require. - // See also ../runtime/iface.c. + // See also ../runtime/iface.go. if V.Kind() == Interface { v := (*interfaceType)(unsafe.Pointer(V)) i := 0 @@ -1265,9 +1275,9 @@ func implements(T, V *rtype) bool { return false } -// directlyAssignable returns true if a value x of type V can be directly +// directlyAssignable reports whether a value x of type V can be directly // assigned (using memmove) to a value of type T. -// http://golang.org/doc/go_spec.html#Assignability +// https://golang.org/doc/go_spec.html#Assignability // Ignoring the interface rules (implemented elsewhere) // and the ideal constant rules (no ideal constants at run time). func directlyAssignable(T, V *rtype) bool { @@ -1445,6 +1455,14 @@ type chanGC struct { end uintptr // _GC_END } +// The funcLookupCache caches FuncOf lookups. +// FuncOf does not share the common lookupCache since cacheKey is not +// sufficient to represent functions unambiguously. +var funcLookupCache struct { + sync.RWMutex + m map[uint32][]*rtype // keyed by hash calculated in FuncOf +} + // ChanOf returns the channel type with the given direction and element type. // For example, if t represents int, ChanOf(RecvDir, t) represents <-chan int. // @@ -1485,6 +1503,7 @@ func ChanOf(dir ChanDir, t Type) Type { prototype := *(**chanType)(unsafe.Pointer(&ichan)) ch := new(chanType) *ch = *prototype + ch.dir = uintptr(dir) ch.string = &s // gccgo uses a different hash. @@ -1545,9 +1564,8 @@ func MapOf(key, elem Type) Type { // Make a map type. var imap interface{} = (map[unsafe.Pointer]unsafe.Pointer)(nil) - prototype := *(**mapType)(unsafe.Pointer(&imap)) mt := new(mapType) - *mt = *prototype + *mt = **(**mapType)(unsafe.Pointer(&imap)) mt.string = &s // gccgo uses a different hash @@ -1576,154 +1594,243 @@ func MapOf(key, elem Type) Type { return cachePut(ckey, &mt.rtype) } -// gcProg is a helper type for generatation of GC pointer info. -type gcProg struct { - gc []byte - size uintptr // size of type in bytes - hasPtr bool -} +// FuncOf returns the function type with the given argument and result types. +// For example if k represents int and e represents string, +// FuncOf([]Type{k}, []Type{e}, false) represents func(int) string. +// +// The variadic argument controls whether the function is variadic. FuncOf +// panics if the in[len(in)-1] does not represent a slice and variadic is +// true. +func FuncOf(in, out []Type, variadic bool) Type { + if variadic && (len(in) == 0 || in[len(in)-1].Kind() != Slice) { + panic("reflect.FuncOf: last arg of variadic func must be slice") + } + + // Make a func type. + var ifunc interface{} = (func())(nil) + prototype := *(**funcType)(unsafe.Pointer(&ifunc)) + ft := new(funcType) + *ft = *prototype + + // Build a hash and minimally populate ft. + var hash uint32 = 8 + var fin, fout []*rtype + shift := uint(1) + for _, in := range in { + t := in.(*rtype) + fin = append(fin, t) + hash += t.hash << shift + shift++ + } + shift = 2 + for _, out := range out { + t := out.(*rtype) + fout = append(fout, t) + hash += t.hash << shift + shift++ + } + if variadic { + hash++ + } + hash <<= 4 + ft.hash = hash + ft.in = fin + ft.out = fout + ft.dotdotdot = variadic -func (gc *gcProg) append(v byte) { - gc.align(unsafe.Sizeof(uintptr(0))) - gc.appendWord(v) -} + // Look in cache. + funcLookupCache.RLock() + for _, t := range funcLookupCache.m[hash] { + if haveIdenticalUnderlyingType(&ft.rtype, t) { + funcLookupCache.RUnlock() + return t + } + } + funcLookupCache.RUnlock() -// Appends t's type info to the current program. -func (gc *gcProg) appendProg(t *rtype) { - gc.align(uintptr(t.align)) - if !t.pointers() { - gc.size += t.size - return + // Not in cache, lock and retry. + funcLookupCache.Lock() + defer funcLookupCache.Unlock() + if funcLookupCache.m == nil { + funcLookupCache.m = make(map[uint32][]*rtype) } - switch t.Kind() { - default: - panic("reflect: non-pointer type marked as having pointers") - case Ptr, UnsafePointer, Chan, Func, Map: - gc.appendWord(bitsPointer) - case Slice: - gc.appendWord(bitsPointer) - gc.appendWord(bitsScalar) - gc.appendWord(bitsScalar) - case String: - gc.appendWord(bitsPointer) - gc.appendWord(bitsScalar) - case Array: - c := t.Len() - e := t.Elem().common() - for i := 0; i < c; i++ { - gc.appendProg(e) + for _, t := range funcLookupCache.m[hash] { + if haveIdenticalUnderlyingType(&ft.rtype, t) { + return t } - case Interface: - gc.appendWord(bitsMultiWord) - if t.NumMethod() == 0 { - gc.appendWord(bitsEface) - } else { - gc.appendWord(bitsIface) - } - case Struct: - c := t.NumField() - for i := 0; i < c; i++ { - gc.appendProg(t.Field(i).Type.common()) - } - gc.align(uintptr(t.align)) } + + str := funcStr(ft) + + // Populate the remaining fields of ft and store in cache. + ft.string = &str + ft.uncommonType = nil + ft.ptrToThis = nil + + // TODO(cmang): Generate GC data for funcs. + ft.gc = unsafe.Pointer(&ptrDataGCProg) + + funcLookupCache.m[hash] = append(funcLookupCache.m[hash], &ft.rtype) + + return toType(&ft.rtype) } -func (gc *gcProg) appendWord(v byte) { - ptrsize := unsafe.Sizeof(uintptr(0)) - if gc.size%ptrsize != 0 { - panic("reflect: unaligned GC program") +// funcStr builds a string representation of a funcType. +func funcStr(ft *funcType) string { + repr := make([]byte, 0, 64) + repr = append(repr, "func("...) + for i, t := range ft.in { + if i > 0 { + repr = append(repr, ", "...) + } + if ft.dotdotdot && i == len(ft.in)-1 { + repr = append(repr, "..."...) + repr = append(repr, *(*sliceType)(unsafe.Pointer(t)).elem.string...) + } else { + repr = append(repr, *t.string...) + } } - nptr := gc.size / ptrsize - for uintptr(len(gc.gc)) < nptr/2+1 { - gc.gc = append(gc.gc, 0x44) // BitsScalar + repr = append(repr, ')') + if l := len(ft.out); l == 1 { + repr = append(repr, ' ') + } else if l > 1 { + repr = append(repr, " ("...) } - gc.gc[nptr/2] &= ^(3 << ((nptr%2)*4 + 2)) - gc.gc[nptr/2] |= v << ((nptr%2)*4 + 2) - gc.size += ptrsize - if v == bitsPointer { - gc.hasPtr = true + for i, t := range ft.out { + if i > 0 { + repr = append(repr, ", "...) + } + repr = append(repr, *t.string...) } + if len(ft.out) > 1 { + repr = append(repr, ')') + } + return string(repr) } -func (gc *gcProg) finalize() (unsafe.Pointer, bool) { - if gc.size == 0 { - return nil, false - } - ptrsize := unsafe.Sizeof(uintptr(0)) - gc.align(ptrsize) - nptr := gc.size / ptrsize - for uintptr(len(gc.gc)) < nptr/2+1 { - gc.gc = append(gc.gc, 0x44) // BitsScalar - } - // If number of words is odd, repeat the mask twice. - // Compiler does the same. - if nptr%2 != 0 { - for i := uintptr(0); i < nptr; i++ { - gc.appendWord(extractGCWord(gc.gc, i)) +// isReflexive reports whether the == operation on the type is reflexive. +// That is, x == x for all values x of type t. +func isReflexive(t *rtype) bool { + switch t.Kind() { + case Bool, Int, Int8, Int16, Int32, Int64, Uint, Uint8, Uint16, Uint32, Uint64, Uintptr, Chan, Ptr, String, UnsafePointer: + return true + case Float32, Float64, Complex64, Complex128, Interface: + return false + case Array: + tt := (*arrayType)(unsafe.Pointer(t)) + return isReflexive(tt.elem) + case Struct: + tt := (*structType)(unsafe.Pointer(t)) + for _, f := range tt.fields { + if !isReflexive(f.typ) { + return false + } } + return true + default: + // Func, Map, Slice, Invalid + panic("isReflexive called on non-key type " + t.String()) } - return unsafe.Pointer(&gc.gc[0]), gc.hasPtr -} - -func extractGCWord(gc []byte, i uintptr) byte { - return (gc[i/2] >> ((i%2)*4 + 2)) & 3 -} - -func (gc *gcProg) align(a uintptr) { - gc.size = align(gc.size, a) } -// These constants must stay in sync with ../runtime/mgc0.h. -const ( - bitsScalar = 1 - bitsPointer = 2 - bitsMultiWord = 3 - - bitsIface = 2 - bitsEface = 3 -) - // Make sure these routines stay in sync with ../../runtime/hashmap.go! // These types exist only for GC, so we only fill out GC relevant info. // Currently, that's just size and the GC program. We also fill in string // for possible debugging use. const ( - bucketSize = 8 - maxKeySize = 128 - maxValSize = 128 + bucketSize uintptr = 8 + maxKeySize uintptr = 128 + maxValSize uintptr = 128 ) func bucketOf(ktyp, etyp *rtype) *rtype { + // See comment on hmap.overflow in ../runtime/hashmap.go. + var kind uint8 + if ktyp.kind&kindNoPointers != 0 && etyp.kind&kindNoPointers != 0 && + ktyp.size <= maxKeySize && etyp.size <= maxValSize { + kind = kindNoPointers + } + if ktyp.size > maxKeySize { ktyp = PtrTo(ktyp).(*rtype) } if etyp.size > maxValSize { etyp = PtrTo(etyp).(*rtype) } - ptrsize := unsafe.Sizeof(uintptr(0)) - var gc gcProg - // topbits - for i := 0; i < int(bucketSize*unsafe.Sizeof(uint8(0))/ptrsize); i++ { - gc.append(bitsScalar) - } - // keys - for i := 0; i < bucketSize; i++ { - gc.appendProg(ktyp) - } - // values - for i := 0; i < bucketSize; i++ { - gc.appendProg(etyp) - } - // overflow - gc.append(bitsPointer) - if runtime.GOARCH == "amd64p32" { - gc.append(bitsScalar) + // Prepare GC data if any. + // A bucket is at most bucketSize*(1+maxKeySize+maxValSize)+2*ptrSize bytes, + // or 2072 bytes, or 259 pointer-size words, or 33 bytes of pointer bitmap. + // Normally the enforced limit on pointer maps is 16 bytes, + // but larger ones are acceptable, 33 bytes isn't too too big, + // and it's easier to generate a pointer bitmap than a GC program. + // Note that since the key and value are known to be <= 128 bytes, + // they're guaranteed to have bitmaps instead of GC programs. + // var gcdata *byte + var ptrdata uintptr + var overflowPad uintptr + + // On NaCl, pad if needed to make overflow end at the proper struct alignment. + // On other systems, align > ptrSize is not possible. + if runtime.GOARCH == "amd64p32" && (ktyp.align > ptrSize || etyp.align > ptrSize) { + overflowPad = ptrSize + } + size := bucketSize*(1+ktyp.size+etyp.size) + overflowPad + ptrSize + if size&uintptr(ktyp.align-1) != 0 || size&uintptr(etyp.align-1) != 0 { + panic("reflect: bad size computation in MapOf") + } + + if kind != kindNoPointers { + nptr := (bucketSize*(1+ktyp.size+etyp.size) + ptrSize) / ptrSize + mask := make([]byte, (nptr+7)/8) + base := bucketSize / ptrSize + + if ktyp.kind&kindNoPointers == 0 { + if ktyp.kind&kindGCProg != 0 { + panic("reflect: unexpected GC program in MapOf") + } + kmask := (*[16]byte)(unsafe.Pointer( /*ktyp.gcdata*/ nil)) + for i := uintptr(0); i < ktyp.size/ptrSize; i++ { + if (kmask[i/8]>>(i%8))&1 != 0 { + for j := uintptr(0); j < bucketSize; j++ { + word := base + j*ktyp.size/ptrSize + i + mask[word/8] |= 1 << (word % 8) + } + } + } + } + base += bucketSize * ktyp.size / ptrSize + + if etyp.kind&kindNoPointers == 0 { + if etyp.kind&kindGCProg != 0 { + panic("reflect: unexpected GC program in MapOf") + } + emask := (*[16]byte)(unsafe.Pointer( /*etyp.gcdata*/ nil)) + for i := uintptr(0); i < etyp.size/ptrSize; i++ { + if (emask[i/8]>>(i%8))&1 != 0 { + for j := uintptr(0); j < bucketSize; j++ { + word := base + j*etyp.size/ptrSize + i + mask[word/8] |= 1 << (word % 8) + } + } + } + } + base += bucketSize * etyp.size / ptrSize + base += overflowPad / ptrSize + + word := base + mask[word/8] |= 1 << (word % 8) + // gcdata = &mask[0] + ptrdata = (word + 1) * ptrSize + + // overflow word must be last + if ptrdata != size { + panic("reflect: bad layout computation in MapOf") + } } b := new(rtype) - b.size = gc.size + // b.size = gc.size // b.gc[0], _ = gc.finalize() b.kind |= kindGCProg s := "bucket(" + *ktyp.string + "," + *etyp.string + ")" @@ -1863,24 +1970,25 @@ func SliceOf(t Type) Type { return cachePut(ckey, &slice.rtype) } +// See cmd/compile/internal/gc/reflect.go for derivation of constant. +const maxPtrmaskBytes = 2048 + // ArrayOf returns the array type with the given count and element type. // For example, if t represents int, ArrayOf(5, t) represents [5]int. // // If the resulting type would be larger than the available address space, // ArrayOf panics. -// -// TODO(rsc): Unexported for now. Export once the alg field is set correctly -// for the type. This may require significant work. -// -// TODO(rsc): TestArrayOf is also disabled. Re-enable. -func arrayOf(count int, elem Type) Type { +func ArrayOf(count int, elem Type) Type { typ := elem.(*rtype) + // call SliceOf here as it calls cacheGet/cachePut. + // ArrayOf also calls cacheGet/cachePut and thus may modify the state of + // the lookupCache mutex. slice := SliceOf(elem) // Look in cache. ckey := cacheKey{Array, typ, nil, uintptr(count)} - if slice := cacheGet(ckey); slice != nil { - return slice + if array := cacheGet(ckey); array != nil { + return array } // Look in known types. @@ -1891,7 +1999,6 @@ func arrayOf(count int, elem Type) Type { prototype := *(**arrayType)(unsafe.Pointer(&iarray)) array := new(arrayType) *array = *prototype - // TODO: Set extra kind bits correctly. array.string = &s // gccgo uses a different hash. @@ -1908,19 +2015,70 @@ func arrayOf(count int, elem Type) Type { panic("reflect.ArrayOf: array size would exceed virtual address space") } array.size = typ.size * uintptr(count) + // if count > 0 && typ.ptrdata != 0 { + // array.ptrdata = typ.size*uintptr(count-1) + typ.ptrdata + // } array.align = typ.align array.fieldAlign = typ.fieldAlign - // TODO: array.alg - // TODO: array.gc - // TODO: array.uncommonType = nil array.ptrToThis = nil array.len = uintptr(count) array.slice = slice.(*rtype) + array.kind &^= kindNoPointers + switch { + case typ.kind&kindNoPointers != 0 || array.size == 0: + // No pointers. + array.kind |= kindNoPointers + gc := [...]uintptr{array.size, _GC_END} + array.gc = unsafe.Pointer(&gc[0]) + + case count == 1: + // In memory, 1-element array looks just like the element. + array.kind |= typ.kind & kindGCProg + array.gc = typ.gc + + default: + gc := []uintptr{array.size, _GC_ARRAY_START, 0, uintptr(count), typ.size} + gc = appendGCProgram(gc, typ) + gc = append(gc, _GC_ARRAY_NEXT, _GC_END) + array.gc = unsafe.Pointer(&gc[0]) + } + + array.kind &^= kindDirectIface + + array.hashfn = func(p unsafe.Pointer, size uintptr) uintptr { + ret := uintptr(0) + for i := 0; i < count; i++ { + ret *= 33 + ret += typ.hashfn(p, typ.size) + p = unsafe.Pointer(uintptr(p) + typ.size) + } + return ret + } + + array.equalfn = func(p1, p2 unsafe.Pointer, size uintptr) bool { + for i := 0; i < count; i++ { + if !typ.equalfn(p1, p2, typ.size) { + return false + } + p1 = unsafe.Pointer(uintptr(p1) + typ.size) + p2 = unsafe.Pointer(uintptr(p2) + typ.size) + } + return true + } + return cachePut(ckey, &array.rtype) } +func appendVarint(x []byte, v uintptr) []byte { + for ; v >= 0x80; v >>= 7 { + x = append(x, byte(v|0x80)) + } + x = append(x, byte(v)) + return x +} + // toType converts from a *rtype to a Type that can be returned // to the client of package reflect. In gc, the only concern is that // a nil *rtype must be replaced by a nil Type, but in gccgo this @@ -1969,56 +2127,49 @@ type bitVector struct { data []byte } -// append a bit pair to the bitmap. -func (bv *bitVector) append2(bits uint8) { - // assume bv.n is a multiple of 2, since append2 is the only operation. +// append a bit to the bitmap. +func (bv *bitVector) append(bit uint8) { if bv.n%8 == 0 { bv.data = append(bv.data, 0) } - bv.data[bv.n/8] |= bits << (bv.n % 8) - bv.n += 2 + bv.data[bv.n/8] |= bit << (bv.n % 8) + bv.n++ } -func addTypeBits(bv *bitVector, offset *uintptr, t *rtype) { - *offset = align(*offset, uintptr(t.align)) +func addTypeBits(bv *bitVector, offset uintptr, t *rtype) { if t.kind&kindNoPointers != 0 { - *offset += t.size return } switch Kind(t.kind & kindMask) { case Chan, Func, Map, Ptr, Slice, String, UnsafePointer: // 1 pointer at start of representation - for bv.n < 2*uint32(*offset/uintptr(ptrSize)) { - bv.append2(bitsScalar) + for bv.n < uint32(offset/uintptr(ptrSize)) { + bv.append(0) } - bv.append2(bitsPointer) + bv.append(1) case Interface: // 2 pointers - for bv.n < 2*uint32(*offset/uintptr(ptrSize)) { - bv.append2(bitsScalar) + for bv.n < uint32(offset/uintptr(ptrSize)) { + bv.append(0) } - bv.append2(bitsPointer) - bv.append2(bitsPointer) + bv.append(1) + bv.append(1) case Array: // repeat inner type tt := (*arrayType)(unsafe.Pointer(t)) for i := 0; i < int(tt.len); i++ { - addTypeBits(bv, offset, tt.elem) + addTypeBits(bv, offset+uintptr(i)*tt.elem.size, tt.elem) } case Struct: // apply fields tt := (*structType)(unsafe.Pointer(t)) - start := *offset for i := range tt.fields { f := &tt.fields[i] - off := start + f.offset - addTypeBits(bv, &off, f.typ) + addTypeBits(bv, offset+f.offset, f.typ) } } - - *offset += t.size } diff --git a/libgo/go/reflect/value.go b/libgo/go/reflect/value.go index 7cc4f7f8bfd..a924d8639a2 100644 --- a/libgo/go/reflect/value.go +++ b/libgo/go/reflect/value.go @@ -10,7 +10,7 @@ import ( "unsafe" ) -const ptrSize = unsafe.Sizeof((*byte)(nil)) +const ptrSize = 4 << (^uintptr(0) >> 63) // unsafe.Sizeof(uintptr(0)) but an ideal const const cannotSet = "cannot set value obtained from unexported struct field" // Value is the reflection interface to a Go value. @@ -30,6 +30,10 @@ const cannotSet = "cannot set value obtained from unexported struct field" // A Value can be used concurrently by multiple goroutines provided that // the underlying Go value can be used concurrently for the equivalent // direct operations. +// +// Using == on two Values does not compare the underlying values +// they represent, but rather the contents of the Value structs. +// To compare two Values, compare the results of the Interface method. type Value struct { // typ holds the type of the value represented by a Value. typ *rtype @@ -104,7 +108,7 @@ func packEface(v Value) interface{} { // TODO: pass safe boolean from valueInterface so // we don't need to copy if safe==true? c := unsafe_New(t) - memmove(c, ptr, t.size) + typedmemmove(t, c, ptr) ptr = c } e.word = ptr @@ -173,7 +177,7 @@ type emptyInterface struct { // nonEmptyInterface is the header for a interface value with methods. type nonEmptyInterface struct { - // see ../runtime/iface.c:/Itab + // see ../runtime/iface.go:/Itab itab *struct { typ *rtype // dynamic concrete type fun [100000]unsafe.Pointer // method table @@ -261,7 +265,7 @@ func (v Value) runes() []rune { return *(*[]rune)(v.ptr) } -// CanAddr returns true if the value's address can be obtained with Addr. +// CanAddr reports whether the value's address can be obtained with Addr. // Such values are called addressable. A value is addressable if it is // an element of a slice, an element of an addressable array, // a field of an addressable struct, or the result of dereferencing a pointer. @@ -270,11 +274,11 @@ func (v Value) CanAddr() bool { return v.flag&flagAddr != 0 } -// CanSet returns true if the value of v can be changed. +// CanSet reports whether the value of v can be changed. // A Value can be changed only if it is addressable and was not // obtained by the use of unexported struct fields. // If CanSet returns false, calling Set or any type-specific -// setter (e.g., SetBool, SetInt64) will panic. +// setter (e.g., SetBool, SetInt) will panic. func (v Value) CanSet() bool { return v.flag&(flagAddr|flagRO) == flagAddr } @@ -295,8 +299,8 @@ func (v Value) Call(in []Value) []Value { // CallSlice calls the variadic function v with the input arguments in, // assigning the slice in[len(in)-1] to v's final variadic argument. -// For example, if len(in) == 3, v.Call(in) represents the Go call v(in[0], in[1], in[2]...). -// Call panics if v's Kind is not Func or if v is not variadic. +// For example, if len(in) == 3, v.CallSlice(in) represents the Go call v(in[0], in[1], in[2]...). +// CallSlice panics if v's Kind is not Func or if v is not variadic. // It returns the output results as Values. // As in Go, each input argument must be assignable to the // type of the function's corresponding input parameter. @@ -622,7 +626,7 @@ func (v Value) Field(i int) Value { // Either flagIndir is set and v.ptr points at struct, // or flagIndir is not set and v.ptr is the actual struct data. // In the former case, we want v.ptr + offset. - // In the latter case, we must be have field.offset = 0, + // In the latter case, we must have field.offset = 0, // so v.ptr + field.offset is still okay. ptr := unsafe.Pointer(uintptr(v.ptr) + field.offset) return Value{typ, ptr, fl} @@ -716,7 +720,7 @@ func (v Value) Index(i int) Value { } tt := (*sliceType)(unsafe.Pointer(v.typ)) typ := tt.elem - val := unsafe.Pointer(uintptr(s.Data) + uintptr(i)*typ.size) + val := arrayAt(s.Data, i, typ.size) fl := flagAddr | flagIndir | v.flag&flagRO | flag(typ.Kind()) return Value{typ, val, fl} @@ -725,7 +729,7 @@ func (v Value) Index(i int) Value { if uint(i) >= uint(s.Len) { panic("reflect: string index out of range") } - p := unsafe.Pointer(uintptr(s.Data) + uintptr(i)) + p := arrayAt(s.Data, i, 1) fl := v.flag&flagRO | flag(Uint8) | flagIndir return Value{uint8Type, p, fl} } @@ -752,7 +756,7 @@ func (v Value) Int() int64 { panic(&ValueError{"reflect.Value.Int", v.kind()}) } -// CanInterface returns true if Interface can be used without panicking. +// CanInterface reports whether Interface can be used without panicking. func (v Value) CanInterface() bool { if v.flag == 0 { panic(&ValueError{"reflect.Value.CanInterface", Invalid}) @@ -849,7 +853,7 @@ func (v Value) IsNil() bool { panic(&ValueError{"reflect.Value.IsNil", v.kind()}) } -// IsValid returns true if v represents a value. +// IsValid reports whether v represents a value. // It returns false if v is the zero Value. // If IsValid returns false, all other methods except String panic. // Most functions and methods never return an invalid value. @@ -920,7 +924,7 @@ func (v Value) MapIndex(key Value) Value { // Copy result so future changes to the map // won't change the underlying value. c := unsafe_New(typ) - memmove(c, e, typ.size) + typedmemmove(typ, c, e) return Value{typ, c, fl | flagIndir} } else { return Value{typ, *(*unsafe.Pointer)(e), fl} @@ -958,7 +962,7 @@ func (v Value) MapKeys() []Value { // Copy result so future changes to the map // won't change the underlying value. c := unsafe_New(keyType) - memmove(c, key, keyType.size) + typedmemmove(keyType, c, key) a[i] = Value{keyType, c, fl | flagIndir} } else { a[i] = Value{keyType, *(*unsafe.Pointer)(key), fl} @@ -1026,7 +1030,7 @@ func (v Value) NumField() int { return len(tt.fields) } -// OverflowComplex returns true if the complex128 x cannot be represented by v's type. +// OverflowComplex reports whether the complex128 x cannot be represented by v's type. // It panics if v's Kind is not Complex64 or Complex128. func (v Value) OverflowComplex(x complex128) bool { k := v.kind() @@ -1039,7 +1043,7 @@ func (v Value) OverflowComplex(x complex128) bool { panic(&ValueError{"reflect.Value.OverflowComplex", v.kind()}) } -// OverflowFloat returns true if the float64 x cannot be represented by v's type. +// OverflowFloat reports whether the float64 x cannot be represented by v's type. // It panics if v's Kind is not Float32 or Float64. func (v Value) OverflowFloat(x float64) bool { k := v.kind() @@ -1059,7 +1063,7 @@ func overflowFloat32(x float64) bool { return math.MaxFloat32 < x && x <= math.MaxFloat64 } -// OverflowInt returns true if the int64 x cannot be represented by v's type. +// OverflowInt reports whether the int64 x cannot be represented by v's type. // It panics if v's Kind is not Int, Int8, int16, Int32, or Int64. func (v Value) OverflowInt(x int64) bool { k := v.kind() @@ -1072,7 +1076,7 @@ func (v Value) OverflowInt(x int64) bool { panic(&ValueError{"reflect.Value.OverflowInt", v.kind()}) } -// OverflowUint returns true if the uint64 x cannot be represented by v's type. +// OverflowUint reports whether the uint64 x cannot be represented by v's type. // It panics if v's Kind is not Uint, Uintptr, Uint8, Uint16, Uint32, or Uint64. func (v Value) OverflowUint(x uint64) bool { k := v.kind() @@ -1194,7 +1198,7 @@ func (v Value) Set(x Value) { } x = x.assignTo("reflect.Set", v.typ, target) if x.flag&flagIndir != 0 { - memmove(v.ptr, x.ptr, v.typ.size) + typedmemmove(v.typ, v.ptr, x.ptr) } else { *(*unsafe.Pointer)(v.ptr) = x.ptr } @@ -1408,7 +1412,7 @@ func (v Value) Slice(i, j int) Value { if i < 0 || j < i || j > s.Len { panic("reflect.Value.Slice: string slice index out of bounds") } - t := stringHeader{unsafe.Pointer(uintptr(s.Data) + uintptr(i)), j - i} + t := stringHeader{arrayAt(s.Data, i, 1), j - i} return Value{v.typ, unsafe.Pointer(&t), v.flag} } @@ -1424,7 +1428,7 @@ func (v Value) Slice(i, j int) Value { s.Len = j - i s.Cap = cap - i if cap-i > 0 { - s.Data = unsafe.Pointer(uintptr(base) + uintptr(i)*typ.elem.Size()) + s.Data = arrayAt(base, i, typ.elem.Size()) } else { // do not advance pointer, to avoid pointing beyond end of slice s.Data = base @@ -1476,7 +1480,7 @@ func (v Value) Slice3(i, j, k int) Value { s.Len = j - i s.Cap = k - i if k-i > 0 { - s.Data = unsafe.Pointer(uintptr(base) + uintptr(i)*typ.elem.Size()) + s.Data = arrayAt(base, i, typ.elem.Size()) } else { // do not advance pointer, to avoid pointing beyond end of slice s.Data = base @@ -1490,6 +1494,8 @@ func (v Value) Slice3(i, j, k int) Value { // String is a special case because of Go's String method convention. // Unlike the other getters, it does not panic if v's Kind is not String. // Instead, it returns a string of the form "" where T is v's type. +// The fmt package treats Values specially. It does not call their String +// method implicitly but instead prints the concrete values they hold. func (v Value) String() string { switch k := v.kind(); k { case Invalid: @@ -1515,7 +1521,7 @@ func (v Value) TryRecv() (x Value, ok bool) { // TrySend attempts to send x on the channel v but will not block. // It panics if v's Kind is not Chan. -// It returns true if the value was sent, false otherwise. +// It reports whether the value was sent. // As in Go, x's value must be assignable to the channel's element type. func (v Value) TrySend(x Value) bool { v.mustBe(Chan) @@ -1633,6 +1639,12 @@ func typesMustMatch(what string, t1, t2 Type) { } } +// arrayAt returns the i-th element of p, a C-array whose elements are +// eltSize wide (in bytes). +func arrayAt(p unsafe.Pointer, i int, eltSize uintptr) unsafe.Pointer { + return unsafe.Pointer(uintptr(p) + uintptr(i)*eltSize) +} + // grow grows the slice s so that it can hold extra more values, allocating // more capacity if needed. It also returns the old and new slice lengths. func grow(s Value, extra int) (Value, int, int) { @@ -1708,27 +1720,23 @@ func Copy(dst, src Value) int { se := src.typ.Elem() typesMustMatch("reflect.Copy", de, se) - n := dst.Len() - if sn := src.Len(); n > sn { - n = sn - } - - // Copy via memmove. - var da, sa unsafe.Pointer + var ds, ss sliceHeader if dk == Array { - da = dst.ptr + ds.Data = dst.ptr + ds.Len = dst.Len() + ds.Cap = ds.Len } else { - da = (*sliceHeader)(dst.ptr).Data + ds = *(*sliceHeader)(dst.ptr) } - if src.flag&flagIndir == 0 { - sa = unsafe.Pointer(&src.ptr) - } else if sk == Array { - sa = src.ptr + if sk == Array { + ss.Data = src.ptr + ss.Len = src.Len() + ss.Cap = ss.Len } else { - sa = (*sliceHeader)(src.ptr).Data + ss = *(*sliceHeader)(src.ptr) } - memmove(da, sa, uintptr(n)*de.Size()) - return n + + return typedslicecopy(de.common(), ds, ss) } // A runtimeSelect is a single case passed to rselect. @@ -2269,7 +2277,7 @@ func cvtDirect(v Value, typ Type) Value { if f&flagAddr != 0 { // indirect, mutable word - make a copy c := unsafe_New(t) - memmove(c, ptr, t.size) + typedmemmove(t, c, ptr) ptr = c f &^= flagAddr } @@ -2311,17 +2319,41 @@ func chansend(t *rtype, ch unsafe.Pointer, val unsafe.Pointer, nb bool) bool func makechan(typ *rtype, size uint64) (ch unsafe.Pointer) func makemap(t *rtype) (m unsafe.Pointer) + +//go:noescape func mapaccess(t *rtype, m unsafe.Pointer, key unsafe.Pointer) (val unsafe.Pointer) + func mapassign(t *rtype, m unsafe.Pointer, key, val unsafe.Pointer) + +//go:noescape func mapdelete(t *rtype, m unsafe.Pointer, key unsafe.Pointer) + +// m escapes into the return value, but the caller of mapiterinit +// doesn't let the return value escape. +//go:noescape func mapiterinit(t *rtype, m unsafe.Pointer) unsafe.Pointer + +//go:noescape func mapiterkey(it unsafe.Pointer) (key unsafe.Pointer) + +//go:noescape func mapiternext(it unsafe.Pointer) + +//go:noescape func maplen(m unsafe.Pointer) int func call(typ *rtype, fnaddr unsafe.Pointer, isInterface bool, isMethod bool, params *unsafe.Pointer, results *unsafe.Pointer) func ifaceE2I(t *rtype, src interface{}, dst unsafe.Pointer) +// typedmemmove copies a value of type t to dst from src. +//go:noescape +func typedmemmove(t *rtype, dst, src unsafe.Pointer) + +// typedslicecopy copies a slice of elemType values from src to dst, +// returning the number of elements copied. +//go:noescape +func typedslicecopy(elemType *rtype, dst, src sliceHeader) int + //go:noescape //extern memmove func memmove(adst, asrc unsafe.Pointer, n uintptr) diff --git a/libgo/go/regexp/all_test.go b/libgo/go/regexp/all_test.go index 01ea3742a8b..d78ae6a4cde 100644 --- a/libgo/go/regexp/all_test.go +++ b/libgo/go/regexp/all_test.go @@ -489,6 +489,17 @@ func TestOnePassCutoff(t *testing.T) { } } +// Check that the same machine can be used with the standard matcher +// and then the backtracker when there are no captures. +func TestSwitchBacktrack(t *testing.T) { + re := MustCompile(`a|b`) + long := make([]byte, maxBacktrackVector+1) + + // The following sequence of Match calls used to panic. See issue #10319. + re.Match(long) // triggers standard matcher + re.Match(long[:1]) // triggers backtracker +} + func BenchmarkLiteral(b *testing.B) { x := strings.Repeat("x", 50) + "y" b.StopTimer() diff --git a/libgo/go/regexp/backtrack.go b/libgo/go/regexp/backtrack.go new file mode 100644 index 00000000000..fd95604fe44 --- /dev/null +++ b/libgo/go/regexp/backtrack.go @@ -0,0 +1,366 @@ +// Copyright 2015 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. + +// backtrack is a regular expression search with submatch +// tracking for small regular expressions and texts. It allocates +// a bit vector with (length of input) * (length of prog) bits, +// to make sure it never explores the same (character position, instruction) +// state multiple times. This limits the search to run in time linear in +// the length of the test. +// +// backtrack is a fast replacement for the NFA code on small +// regexps when onepass cannot be used. + +package regexp + +import "regexp/syntax" + +// A job is an entry on the backtracker's job stack. It holds +// the instruction pc and the position in the input. +type job struct { + pc uint32 + arg int + pos int +} + +const ( + visitedBits = 32 + maxBacktrackProg = 500 // len(prog.Inst) <= max + maxBacktrackVector = 256 * 1024 // bit vector size <= max (bits) +) + +// bitState holds state for the backtracker. +type bitState struct { + prog *syntax.Prog + + end int + cap []int + input input + jobs []job + visited []uint32 +} + +var notBacktrack *bitState = nil + +// maxBitStateLen returns the maximum length of a string to search with +// the backtracker using prog. +func maxBitStateLen(prog *syntax.Prog) int { + if !shouldBacktrack(prog) { + return 0 + } + return maxBacktrackVector / len(prog.Inst) +} + +// newBitState returns a new bitState for the given prog, +// or notBacktrack if the size of the prog exceeds the maximum size that +// the backtracker will be run for. +func newBitState(prog *syntax.Prog) *bitState { + if !shouldBacktrack(prog) { + return notBacktrack + } + return &bitState{ + prog: prog, + } +} + +// shouldBacktrack reports whether the program is too +// long for the backtracker to run. +func shouldBacktrack(prog *syntax.Prog) bool { + return len(prog.Inst) <= maxBacktrackProg +} + +// reset resets the state of the backtracker. +// end is the end position in the input. +// ncap is the number of captures. +func (b *bitState) reset(end int, ncap int) { + b.end = end + + if cap(b.jobs) == 0 { + b.jobs = make([]job, 0, 256) + } else { + b.jobs = b.jobs[:0] + } + + visitedSize := (len(b.prog.Inst)*(end+1) + visitedBits - 1) / visitedBits + if cap(b.visited) < visitedSize { + b.visited = make([]uint32, visitedSize, maxBacktrackVector/visitedBits) + } else { + b.visited = b.visited[:visitedSize] + for i := range b.visited { + b.visited[i] = 0 + } + } + + if cap(b.cap) < ncap { + b.cap = make([]int, ncap) + } else { + b.cap = b.cap[:ncap] + } + for i := range b.cap { + b.cap[i] = -1 + } +} + +// shouldVisit reports whether the combination of (pc, pos) has not +// been visited yet. +func (b *bitState) shouldVisit(pc uint32, pos int) bool { + n := uint(int(pc)*(b.end+1) + pos) + if b.visited[n/visitedBits]&(1<<(n&(visitedBits-1))) != 0 { + return false + } + b.visited[n/visitedBits] |= 1 << (n & (visitedBits - 1)) + return true +} + +// push pushes (pc, pos, arg) onto the job stack if it should be +// visited. +func (b *bitState) push(pc uint32, pos int, arg int) { + if b.prog.Inst[pc].Op == syntax.InstFail { + return + } + + // Only check shouldVisit when arg == 0. + // When arg > 0, we are continuing a previous visit. + if arg == 0 && !b.shouldVisit(pc, pos) { + return + } + + b.jobs = append(b.jobs, job{pc: pc, arg: arg, pos: pos}) +} + +// tryBacktrack runs a backtracking search starting at pos. +func (m *machine) tryBacktrack(b *bitState, i input, pc uint32, pos int) bool { + longest := m.re.longest + m.matched = false + + b.push(pc, pos, 0) + for len(b.jobs) > 0 { + l := len(b.jobs) - 1 + // Pop job off the stack. + pc := b.jobs[l].pc + pos := b.jobs[l].pos + arg := b.jobs[l].arg + b.jobs = b.jobs[:l] + + // Optimization: rather than push and pop, + // code that is going to Push and continue + // the loop simply updates ip, p, and arg + // and jumps to CheckAndLoop. We have to + // do the ShouldVisit check that Push + // would have, but we avoid the stack + // manipulation. + goto Skip + CheckAndLoop: + if !b.shouldVisit(pc, pos) { + continue + } + Skip: + + inst := b.prog.Inst[pc] + + switch inst.Op { + default: + panic("bad inst") + case syntax.InstFail: + panic("unexpected InstFail") + case syntax.InstAlt: + // Cannot just + // b.push(inst.Out, pos, 0) + // b.push(inst.Arg, pos, 0) + // If during the processing of inst.Out, we encounter + // inst.Arg via another path, we want to process it then. + // Pushing it here will inhibit that. Instead, re-push + // inst with arg==1 as a reminder to push inst.Arg out + // later. + switch arg { + case 0: + b.push(pc, pos, 1) + pc = inst.Out + goto CheckAndLoop + case 1: + // Finished inst.Out; try inst.Arg. + arg = 0 + pc = inst.Arg + goto CheckAndLoop + } + panic("bad arg in InstAlt") + + case syntax.InstAltMatch: + // One opcode consumes runes; the other leads to match. + switch b.prog.Inst[inst.Out].Op { + case syntax.InstRune, syntax.InstRune1, syntax.InstRuneAny, syntax.InstRuneAnyNotNL: + // inst.Arg is the match. + b.push(inst.Arg, pos, 0) + pc = inst.Arg + pos = b.end + goto CheckAndLoop + } + // inst.Out is the match - non-greedy + b.push(inst.Out, b.end, 0) + pc = inst.Out + goto CheckAndLoop + + case syntax.InstRune: + r, width := i.step(pos) + if !inst.MatchRune(r) { + continue + } + pos += width + pc = inst.Out + goto CheckAndLoop + + case syntax.InstRune1: + r, width := i.step(pos) + if r != inst.Rune[0] { + continue + } + pos += width + pc = inst.Out + goto CheckAndLoop + + case syntax.InstRuneAnyNotNL: + r, width := i.step(pos) + if r == '\n' || r == endOfText { + continue + } + pos += width + pc = inst.Out + goto CheckAndLoop + + case syntax.InstRuneAny: + r, width := i.step(pos) + if r == endOfText { + continue + } + pos += width + pc = inst.Out + goto CheckAndLoop + + case syntax.InstCapture: + switch arg { + case 0: + if 0 <= inst.Arg && inst.Arg < uint32(len(b.cap)) { + // Capture pos to register, but save old value. + b.push(pc, b.cap[inst.Arg], 1) // come back when we're done. + b.cap[inst.Arg] = pos + } + pc = inst.Out + goto CheckAndLoop + case 1: + // Finished inst.Out; restore the old value. + b.cap[inst.Arg] = pos + continue + + } + panic("bad arg in InstCapture") + continue + + case syntax.InstEmptyWidth: + if syntax.EmptyOp(inst.Arg)&^i.context(pos) != 0 { + continue + } + pc = inst.Out + goto CheckAndLoop + + case syntax.InstNop: + pc = inst.Out + goto CheckAndLoop + + case syntax.InstMatch: + // We found a match. If the caller doesn't care + // where the match is, no point going further. + if len(b.cap) == 0 { + m.matched = true + return m.matched + } + + // Record best match so far. + // Only need to check end point, because this entire + // call is only considering one start position. + if len(b.cap) > 1 { + b.cap[1] = pos + } + if !m.matched || (longest && pos > 0 && pos > m.matchcap[1]) { + copy(m.matchcap, b.cap) + } + m.matched = true + + // If going for first match, we're done. + if !longest { + return m.matched + } + + // If we used the entire text, no longer match is possible. + if pos == b.end { + return m.matched + } + + // Otherwise, continue on in hope of a longer match. + continue + } + panic("unreachable") + } + + return m.matched +} + +// backtrack runs a backtracking search of prog on the input starting at pos. +func (m *machine) backtrack(i input, pos int, end int, ncap int) bool { + if !i.canCheckPrefix() { + panic("backtrack called for a RuneReader") + } + + startCond := m.re.cond + if startCond == ^syntax.EmptyOp(0) { // impossible + return false + } + if startCond&syntax.EmptyBeginText != 0 && pos != 0 { + // Anchored match, past beginning of text. + return false + } + + b := m.b + b.reset(end, ncap) + + m.matchcap = m.matchcap[:ncap] + for i := range m.matchcap { + m.matchcap[i] = -1 + } + + // Anchored search must start at the beginning of the input + if startCond&syntax.EmptyBeginText != 0 { + if len(b.cap) > 0 { + b.cap[0] = pos + } + return m.tryBacktrack(b, i, uint32(m.p.Start), pos) + } + + // Unanchored search, starting from each possible text position. + // Notice that we have to try the empty string at the end of + // the text, so the loop condition is pos <= end, not pos < end. + // This looks like it's quadratic in the size of the text, + // but we are not clearing visited between calls to TrySearch, + // so no work is duplicated and it ends up still being linear. + width := -1 + for ; pos <= end && width != 0; pos += width { + if len(m.re.prefix) > 0 { + // Match requires literal prefix; fast search for it. + advance := i.index(m.re, pos) + if advance < 0 { + return false + } + pos += advance + } + + if len(b.cap) > 0 { + b.cap[0] = pos + } + if m.tryBacktrack(b, i, uint32(m.p.Start), pos) { + // Match must be leftmost; done. + return true + } + _, width = i.step(pos) + } + return false +} diff --git a/libgo/go/regexp/exec.go b/libgo/go/regexp/exec.go index c4cb201f642..518272092ae 100644 --- a/libgo/go/regexp/exec.go +++ b/libgo/go/regexp/exec.go @@ -35,13 +35,15 @@ type thread struct { // A machine holds all the state during an NFA simulation for p. type machine struct { - re *Regexp // corresponding Regexp - p *syntax.Prog // compiled program - op *onePassProg // compiled onepass program, or notOnePass - q0, q1 queue // two queues for runq, nextq - pool []*thread // pool of available threads - matched bool // whether a match was found - matchcap []int // capture information for the match + re *Regexp // corresponding Regexp + p *syntax.Prog // compiled program + op *onePassProg // compiled onepass program, or notOnePass + maxBitStateLen int // max length of string to search with bitstate + b *bitState // state for backtracker, allocated lazily + q0, q1 queue // two queues for runq, nextq + pool []*thread // pool of available threads + matched bool // whether a match was found + matchcap []int // capture information for the match // cached inputs, to avoid allocation inputBytes inputBytes @@ -76,6 +78,9 @@ func progMachine(p *syntax.Prog, op *onePassProg) *machine { if ncap < 2 { ncap = 2 } + if op == notOnePass { + m.maxBitStateLen = maxBitStateLen(p) + } m.matchcap = make([]int, ncap) return m } @@ -422,18 +427,29 @@ var empty = make([]int, 0) func (re *Regexp) doExecute(r io.RuneReader, b []byte, s string, pos int, ncap int) []int { m := re.get() var i input + var size int if r != nil { i = m.newInputReader(r) } else if b != nil { i = m.newInputBytes(b) + size = len(b) } else { i = m.newInputString(s) + size = len(s) } if m.op != notOnePass { if !m.onepass(i, pos) { re.put(m) return nil } + } else if size < m.maxBitStateLen && r == nil { + if m.b == nil { + m.b = newBitState(m.p) + } + if !m.backtrack(i, pos, size, ncap) { + re.put(m) + return nil + } } else { m.init(ncap) if !m.match(i, pos) { diff --git a/libgo/go/regexp/exec_test.go b/libgo/go/regexp/exec_test.go index 70d069c0611..4872cb3def4 100644 --- a/libgo/go/regexp/exec_test.go +++ b/libgo/go/regexp/exec_test.go @@ -24,8 +24,8 @@ import ( // complexity, over all possible strings over a given alphabet, // up to a given size. Rather than try to link with RE2, we read a // log file containing the test cases and the expected matches. -// The log file, re2.txt, is generated by running 'make exhaustive-log' -// in the open source RE2 distribution. http://code.google.com/p/re2/ +// The log file, re2-exhaustive.txt, is generated by running 'make log' +// in the open source RE2 distribution https://github.com/google/re2/. // // The test file format is a sequence of stanzas like: // @@ -59,8 +59,8 @@ import ( // a capital letter are test names printed during RE2's test suite // and are echoed into t but otherwise ignored. // -// At time of writing, re2.txt is 32 MB but compresses to 760 kB, -// so we store re2.txt.gz in the repository and decompress it on the fly. +// At time of writing, re2-exhaustive.txt is 59 MB but compresses to 385 kB, +// so we store re2-exhaustive.txt.bz2 in the repository and decompress it on the fly. // func TestRE2Search(t *testing.T) { testRE2(t, "testdata/re2-search.txt") @@ -326,7 +326,7 @@ func same(x, y []int) bool { // TestFowler runs this package's regexp API against the // POSIX regular expression tests collected by Glenn Fowler -// at http://www2.research.att.com/~gsf/testregex/. +// at http://www2.research.att.com/~astopen/testregex/testregex.html. func TestFowler(t *testing.T) { files, err := filepath.Glob("testdata/*.dat") if err != nil { @@ -361,7 +361,7 @@ Reading: break Reading } - // http://www2.research.att.com/~gsf/man/man1/testregex.html + // http://www2.research.att.com/~astopen/man/man1/testregex.html // // INPUT FORMAT // Input lines may be blank, a comment beginning with #, or a test @@ -713,3 +713,15 @@ func TestLongest(t *testing.T) { t.Errorf("longest match was %q, want %q", g, w) } } + +// TestProgramTooLongForBacktrack tests that a regex which is too long +// for the backtracker still executes properly. +func TestProgramTooLongForBacktrack(t *testing.T) { + longRegex := MustCompile(`(one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve|thirteen|fourteen|fifteen|sixteen|seventeen|eighteen|nineteen|twenty|twentyone|twentytwo|twentythree|twentyfour|twentyfive|twentysix|twentyseven|twentyeight|twentynine|thirty|thirtyone|thirtytwo|thirtythree|thirtyfour|thirtyfive|thirtysix|thirtyseven|thirtyeight|thirtynine|forty|fortyone|fortytwo|fortythree|fortyfour|fortyfive|fortysix|fortyseven|fortyeight|fortynine|fifty|fiftyone|fiftytwo|fiftythree|fiftyfour|fiftyfive|fiftysix|fiftyseven|fiftyeight|fiftynine|sixty|sixtyone|sixtytwo|sixtythree|sixtyfour|sixtyfive|sixtysix|sixtyseven|sixtyeight|sixtynine|seventy|seventyone|seventytwo|seventythree|seventyfour|seventyfive|seventysix|seventyseven|seventyeight|seventynine|eighty|eightyone|eightytwo|eightythree|eightyfour|eightyfive|eightysix|eightyseven|eightyeight|eightynine|ninety|ninetyone|ninetytwo|ninetythree|ninetyfour|ninetyfive|ninetysix|ninetyseven|ninetyeight|ninetynine|onehundred)`) + if !longRegex.MatchString("two") { + t.Errorf("longRegex.MatchString(\"two\") was false, want true") + } + if longRegex.MatchString("xxx") { + t.Errorf("longRegex.MatchString(\"xxx\") was true, want false") + } +} diff --git a/libgo/go/regexp/regexp.go b/libgo/go/regexp/regexp.go index b615acdf0e5..4e4b41242a3 100644 --- a/libgo/go/regexp/regexp.go +++ b/libgo/go/regexp/regexp.go @@ -7,9 +7,9 @@ // The syntax of the regular expressions accepted is the same // general syntax used by Perl, Python, and other languages. // More precisely, it is the syntax accepted by RE2 and described at -// http://code.google.com/p/re2/wiki/Syntax, except for \C. +// https://golang.org/s/re2syntax, except for \C. // For an overview of the syntax, run -// godoc regexp/syntax +// go doc regexp/syntax // // The regexp implementation provided by this package is // guaranteed to run in time linear in the size of the input. @@ -83,7 +83,7 @@ type Regexp struct { // read-only after Compile expr string // as passed to Compile prog *syntax.Prog // compiled program - onepass *onePassProg // onpass program or nil + onepass *onePassProg // onepass program or nil prefix string // required prefix in unanchored matches prefixBytes []byte // prefix, as a []byte prefixComplete bool // prefix is the entire regexp diff --git a/libgo/go/regexp/syntax/prog.go b/libgo/go/regexp/syntax/prog.go index 29bd282d0d9..ae6db31a441 100644 --- a/libgo/go/regexp/syntax/prog.go +++ b/libgo/go/regexp/syntax/prog.go @@ -189,7 +189,7 @@ Loop: const noMatch = -1 -// MatchRune returns true if the instruction matches (and consumes) r. +// MatchRune reports whether the instruction matches (and consumes) r. // It should only be called when i.Op == InstRune. func (i *Inst) MatchRune(r rune) bool { return i.MatchRunePos(r) != noMatch @@ -256,7 +256,7 @@ func wordRune(r rune) bool { ('0' <= r && r <= '9') } -// MatchEmptyWidth returns true if the instruction matches +// MatchEmptyWidth reports whether the instruction matches // an empty string between the runes before and after. // It should only be called when i.Op == InstEmptyWidth. func (i *Inst) MatchEmptyWidth(before rune, after rune) bool { diff --git a/libgo/go/regexp/testdata/README b/libgo/go/regexp/testdata/README index b1b301be83f..58cec82f91e 100644 --- a/libgo/go/regexp/testdata/README +++ b/libgo/go/regexp/testdata/README @@ -19,5 +19,6 @@ Such changes are marked with 'RE2/Go'. RE2 Test Files re2-exhaustive.txt.bz2 and re2-search.txt are built by running -'make log' in the RE2 distribution. http://code.google.com/p/re2/. +'make log' in the RE2 distribution https://github.com/google/re2/ + The exhaustive file is compressed because it is huge. diff --git a/libgo/go/runtime/arch_386.go b/libgo/go/runtime/arch_386.go deleted file mode 100644 index 79d38c7ab1b..00000000000 --- a/libgo/go/runtime/arch_386.go +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -type uintreg uint32 -type intptr int32 // TODO(rsc): remove diff --git a/libgo/go/runtime/arch_amd64.go b/libgo/go/runtime/arch_amd64.go deleted file mode 100644 index 270cd7b9573..00000000000 --- a/libgo/go/runtime/arch_amd64.go +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -type uintreg uint64 -type intptr int64 // TODO(rsc): remove diff --git a/libgo/go/runtime/arch_amd64p32.go b/libgo/go/runtime/arch_amd64p32.go deleted file mode 100644 index 5c636aeab2f..00000000000 --- a/libgo/go/runtime/arch_amd64p32.go +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -type uintreg uint64 -type intptr int32 // TODO(rsc): remove diff --git a/libgo/go/runtime/arch_arm.go b/libgo/go/runtime/arch_arm.go deleted file mode 100644 index 79d38c7ab1b..00000000000 --- a/libgo/go/runtime/arch_arm.go +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -type uintreg uint32 -type intptr int32 // TODO(rsc): remove diff --git a/libgo/go/runtime/atomic.go b/libgo/go/runtime/atomic.go deleted file mode 100644 index 7e9d9b3aadc..00000000000 --- a/libgo/go/runtime/atomic.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build !arm - -package runtime - -import "unsafe" - -//go:noescape -func xadd(ptr *uint32, delta int32) uint32 - -//go:noescape -func xadd64(ptr *uint64, delta int64) uint64 - -//go:noescape -func xchg(ptr *uint32, new uint32) uint32 - -//go:noescape -func xchg64(ptr *uint64, new uint64) uint64 - -//go:noescape -func xchgp(ptr unsafe.Pointer, new unsafe.Pointer) unsafe.Pointer - -//go:noescape -func xchguintptr(ptr *uintptr, new uintptr) uintptr - -//go:noescape -func atomicload(ptr *uint32) uint32 - -//go:noescape -func atomicload64(ptr *uint64) uint64 - -//go:noescape -func atomicloadp(ptr unsafe.Pointer) unsafe.Pointer - -//go:noescape -func atomicor8(ptr *uint8, val uint8) - -//go:noescape -func cas64(ptr *uint64, old, new uint64) bool - -//go:noescape -func atomicstore(ptr *uint32, val uint32) - -//go:noescape -func atomicstore64(ptr *uint64, val uint64) - -//go:noescape -func atomicstorep(ptr unsafe.Pointer, val unsafe.Pointer) diff --git a/libgo/go/runtime/cgocall.go b/libgo/go/runtime/cgocall.go deleted file mode 100644 index 7fd91469eb1..00000000000 --- a/libgo/go/runtime/cgocall.go +++ /dev/null @@ -1,279 +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. - -// Cgo call and callback support. -// -// To call into the C function f from Go, the cgo-generated code calls -// runtime.cgocall(_cgo_Cfunc_f, frame), where _cgo_Cfunc_f is a -// gcc-compiled function written by cgo. -// -// runtime.cgocall (below) locks g to m, calls entersyscall -// so as not to block other goroutines or the garbage collector, -// and then calls runtime.asmcgocall(_cgo_Cfunc_f, frame). -// -// runtime.asmcgocall (in asm_$GOARCH.s) switches to the m->g0 stack -// (assumed to be an operating system-allocated stack, so safe to run -// gcc-compiled code on) and calls _cgo_Cfunc_f(frame). -// -// _cgo_Cfunc_f invokes the actual C function f with arguments -// taken from the frame structure, records the results in the frame, -// and returns to runtime.asmcgocall. -// -// After it regains control, runtime.asmcgocall switches back to the -// original g (m->curg)'s stack and returns to runtime.cgocall. -// -// After it regains control, runtime.cgocall calls exitsyscall, which blocks -// until this m can run Go code without violating the $GOMAXPROCS limit, -// and then unlocks g from m. -// -// The above description skipped over the possibility of the gcc-compiled -// function f calling back into Go. If that happens, we continue down -// the rabbit hole during the execution of f. -// -// To make it possible for gcc-compiled C code to call a Go function p.GoF, -// cgo writes a gcc-compiled function named GoF (not p.GoF, since gcc doesn't -// know about packages). The gcc-compiled C function f calls GoF. -// -// GoF calls crosscall2(_cgoexp_GoF, frame, framesize). Crosscall2 -// (in cgo/gcc_$GOARCH.S, a gcc-compiled assembly file) is a two-argument -// adapter from the gcc function call ABI to the 6c function call ABI. -// It is called from gcc to call 6c functions. In this case it calls -// _cgoexp_GoF(frame, framesize), still running on m->g0's stack -// and outside the $GOMAXPROCS limit. Thus, this code cannot yet -// call arbitrary Go code directly and must be careful not to allocate -// memory or use up m->g0's stack. -// -// _cgoexp_GoF calls runtime.cgocallback(p.GoF, frame, framesize). -// (The reason for having _cgoexp_GoF instead of writing a crosscall3 -// to make this call directly is that _cgoexp_GoF, because it is compiled -// with 6c instead of gcc, can refer to dotted names like -// runtime.cgocallback and p.GoF.) -// -// runtime.cgocallback (in asm_$GOARCH.s) switches from m->g0's -// stack to the original g (m->curg)'s stack, on which it calls -// runtime.cgocallbackg(p.GoF, frame, framesize). -// As part of the stack switch, runtime.cgocallback saves the current -// SP as m->g0->sched.sp, so that any use of m->g0's stack during the -// execution of the callback will be done below the existing stack frames. -// Before overwriting m->g0->sched.sp, it pushes the old value on the -// m->g0 stack, so that it can be restored later. -// -// runtime.cgocallbackg (below) is now running on a real goroutine -// stack (not an m->g0 stack). First it calls runtime.exitsyscall, which will -// block until the $GOMAXPROCS limit allows running this goroutine. -// Once exitsyscall has returned, it is safe to do things like call the memory -// allocator or invoke the Go callback function p.GoF. runtime.cgocallbackg -// first defers a function to unwind m->g0.sched.sp, so that if p.GoF -// panics, m->g0.sched.sp will be restored to its old value: the m->g0 stack -// and the m->curg stack will be unwound in lock step. -// Then it calls p.GoF. Finally it pops but does not execute the deferred -// function, calls runtime.entersyscall, and returns to runtime.cgocallback. -// -// After it regains control, runtime.cgocallback switches back to -// m->g0's stack (the pointer is still in m->g0.sched.sp), restores the old -// m->g0.sched.sp value from the stack, and returns to _cgoexp_GoF. -// -// _cgoexp_GoF immediately returns to crosscall2, which restores the -// callee-save registers for gcc and returns to GoF, which returns to f. - -package runtime - -import "unsafe" - -// Call from Go to C. -//go:nosplit -func cgocall(fn, arg unsafe.Pointer) { - cgocall_errno(fn, arg) -} - -//go:nosplit -func cgocall_errno(fn, arg unsafe.Pointer) int32 { - if !iscgo && GOOS != "solaris" && GOOS != "windows" { - gothrow("cgocall unavailable") - } - - if fn == nil { - gothrow("cgocall nil") - } - - if raceenabled { - racereleasemerge(unsafe.Pointer(&racecgosync)) - } - - // Create an extra M for callbacks on threads not created by Go on first cgo call. - if needextram == 1 && cas(&needextram, 1, 0) { - onM(newextram) - } - - /* - * Lock g to m to ensure we stay on the same stack if we do a - * cgo callback. Add entry to defer stack in case of panic. - */ - lockOSThread() - mp := getg().m - mp.ncgocall++ - mp.ncgo++ - defer endcgo(mp) - - /* - * Announce we are entering a system call - * so that the scheduler knows to create another - * M to run goroutines while we are in the - * foreign code. - * - * The call to asmcgocall is guaranteed not to - * split the stack and does not allocate memory, - * so it is safe to call while "in a system call", outside - * the $GOMAXPROCS accounting. - */ - entersyscall() - errno := asmcgocall_errno(fn, arg) - exitsyscall() - - return errno -} - -//go:nosplit -func endcgo(mp *m) { - mp.ncgo-- - if mp.ncgo == 0 { - // We are going back to Go and are not in a recursive - // call. Let the GC collect any memory allocated via - // _cgo_allocate that is no longer referenced. - mp.cgomal = nil - } - - if raceenabled { - raceacquire(unsafe.Pointer(&racecgosync)) - } - - unlockOSThread() // invalidates mp -} - -// Helper functions for cgo code. - -// Filled by schedinit from corresponding C variables, -// which are in turn filled in by dynamic linker when Cgo is available. -var cgoMalloc, cgoFree unsafe.Pointer - -func cmalloc(n uintptr) unsafe.Pointer { - var args struct { - n uint64 - ret unsafe.Pointer - } - args.n = uint64(n) - cgocall(cgoMalloc, unsafe.Pointer(&args)) - if args.ret == nil { - gothrow("C malloc failed") - } - return args.ret -} - -func cfree(p unsafe.Pointer) { - cgocall(cgoFree, p) -} - -// Call from C back to Go. -//go:nosplit -func cgocallbackg() { - gp := getg() - if gp != gp.m.curg { - println("runtime: bad g in cgocallback") - exit(2) - } - - // entersyscall saves the caller's SP to allow the GC to trace the Go - // stack. However, since we're returning to an earlier stack frame and - // need to pair with the entersyscall() call made by cgocall, we must - // save syscall* and let reentersyscall restore them. - savedsp := unsafe.Pointer(gp.syscallsp) - savedpc := gp.syscallpc - exitsyscall() // coming out of cgo call - cgocallbackg1() - // going back to cgo call - reentersyscall(savedpc, savedsp) -} - -func cgocallbackg1() { - gp := getg() - if gp.m.needextram { - gp.m.needextram = false - onM(newextram) - } - - // Add entry to defer stack in case of panic. - restore := true - defer unwindm(&restore) - - if raceenabled { - raceacquire(unsafe.Pointer(&racecgosync)) - } - - type args struct { - fn *funcval - arg unsafe.Pointer - argsize uintptr - } - var cb *args - - // Location of callback arguments depends on stack frame layout - // and size of stack frame of cgocallback_gofunc. - sp := gp.m.g0.sched.sp - switch GOARCH { - default: - gothrow("cgocallbackg is unimplemented on arch") - case "arm": - // On arm, stack frame is two words and there's a saved LR between - // SP and the stack frame and between the stack frame and the arguments. - cb = (*args)(unsafe.Pointer(sp + 4*ptrSize)) - case "amd64": - // On amd64, stack frame is one word, plus caller PC. - cb = (*args)(unsafe.Pointer(sp + 2*ptrSize)) - case "386": - // On 386, stack frame is three words, plus caller PC. - cb = (*args)(unsafe.Pointer(sp + 4*ptrSize)) - } - - // Invoke callback. - reflectcall(unsafe.Pointer(cb.fn), unsafe.Pointer(cb.arg), uint32(cb.argsize), 0) - - if raceenabled { - racereleasemerge(unsafe.Pointer(&racecgosync)) - } - - // Do not unwind m->g0->sched.sp. - // Our caller, cgocallback, will do that. - restore = false -} - -func unwindm(restore *bool) { - if !*restore { - return - } - // Restore sp saved by cgocallback during - // unwind of g's stack (see comment at top of file). - mp := acquirem() - sched := &mp.g0.sched - switch GOARCH { - default: - gothrow("unwindm not implemented") - case "386", "amd64": - sched.sp = *(*uintptr)(unsafe.Pointer(sched.sp)) - case "arm": - sched.sp = *(*uintptr)(unsafe.Pointer(sched.sp + 4)) - } - releasem(mp) -} - -// called from assembly -func badcgocallback() { - gothrow("misaligned stack in cgocallback") -} - -// called from (incomplete) assembly -func cgounimpl() { - gothrow("cgo not implemented") -} - -var racecgosync uint64 // represents possible synchronization in C code diff --git a/libgo/go/runtime/cgocallback.go b/libgo/go/runtime/cgocallback.go deleted file mode 100644 index 2c89143208a..00000000000 --- a/libgo/go/runtime/cgocallback.go +++ /dev/null @@ -1,40 +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 runtime - -import "unsafe" - -// These functions are called from C code via cgo/callbacks.c. - -// Allocate memory. This allocates the requested number of bytes in -// memory controlled by the Go runtime. The allocated memory will be -// zeroed. You are responsible for ensuring that the Go garbage -// collector can see a pointer to the allocated memory for as long as -// it is valid, e.g., by storing a pointer in a local variable in your -// C function, or in memory allocated by the Go runtime. If the only -// pointers are in a C global variable or in memory allocated via -// malloc, then the Go garbage collector may collect the memory. -// -// TODO(rsc,iant): This memory is untyped. -// Either we need to add types or we need to stop using it. - -func _cgo_allocate_internal(len uintptr) unsafe.Pointer { - if len == 0 { - len = 1 - } - ret := unsafe.Pointer(&make([]unsafe.Pointer, (len+ptrSize-1)/ptrSize)[0]) - c := new(cgomal) - c.alloc = ret - gp := getg() - c.next = gp.m.cgomal - gp.m.cgomal = c - return ret -} - -// Panic. - -func _cgo_panic_internal(p *byte) { - panic(gostringnocopy(p)) -} diff --git a/libgo/go/runtime/chan.go b/libgo/go/runtime/chan.go deleted file mode 100644 index 0eb87df74f7..00000000000 --- a/libgo/go/runtime/chan.go +++ /dev/null @@ -1,655 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -// This file contains the implementation of Go channels. - -import "unsafe" - -const ( - maxAlign = 8 - hchanSize = unsafe.Sizeof(hchan{}) + uintptr(-int(unsafe.Sizeof(hchan{}))&(maxAlign-1)) - debugChan = false -) - -// TODO(khr): make hchan.buf an unsafe.Pointer, not a *uint8 - -func makechan(t *chantype, size int64) *hchan { - elem := t.elem - - // compiler checks this but be safe. - if elem.size >= 1<<16 { - gothrow("makechan: invalid channel element type") - } - if hchanSize%maxAlign != 0 || elem.align > maxAlign { - gothrow("makechan: bad alignment") - } - if size < 0 || int64(uintptr(size)) != size || (elem.size > 0 && uintptr(size) > (maxmem-hchanSize)/uintptr(elem.size)) { - panic("makechan: size out of range") - } - - var c *hchan - if elem.kind&kindNoPointers != 0 || size == 0 { - // Allocate memory in one call. - // Hchan does not contain pointers interesting for GC in this case: - // buf points into the same allocation, elemtype is persistent. - // SudoG's are referenced from their owning thread so they can't be collected. - // TODO(dvyukov,rlh): Rethink when collector can move allocated objects. - c = (*hchan)(mallocgc(hchanSize+uintptr(size)*uintptr(elem.size), nil, flagNoScan)) - if size > 0 && elem.size != 0 { - c.buf = (*uint8)(add(unsafe.Pointer(c), hchanSize)) - } else { - c.buf = (*uint8)(unsafe.Pointer(c)) // race detector uses this location for synchronization - } - } else { - c = new(hchan) - c.buf = (*uint8)(newarray(elem, uintptr(size))) - } - c.elemsize = uint16(elem.size) - c.elemtype = elem - c.dataqsiz = uint(size) - - if debugChan { - print("makechan: chan=", c, "; elemsize=", elem.size, "; elemalg=", elem.alg, "; dataqsiz=", size, "\n") - } - return c -} - -// chanbuf(c, i) is pointer to the i'th slot in the buffer. -func chanbuf(c *hchan, i uint) unsafe.Pointer { - return add(unsafe.Pointer(c.buf), uintptr(i)*uintptr(c.elemsize)) -} - -// entry point for c <- x from compiled code -//go:nosplit -func chansend1(t *chantype, c *hchan, elem unsafe.Pointer) { - chansend(t, c, elem, true, getcallerpc(unsafe.Pointer(&t))) -} - -/* - * generic single channel send/recv - * If block is not nil, - * then the protocol will not - * sleep but return if it could - * not complete. - * - * sleep can wake up with g.param == nil - * when a channel involved in the sleep has - * been closed. it is easiest to loop and re-run - * the operation; we'll see that it's now closed. - */ -func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uintptr) bool { - if raceenabled { - raceReadObjectPC(t.elem, ep, callerpc, funcPC(chansend)) - } - - if c == nil { - if !block { - return false - } - gopark(nil, nil, "chan send (nil chan)") - gothrow("unreachable") - } - - if debugChan { - print("chansend: chan=", c, "\n") - } - - if raceenabled { - racereadpc(unsafe.Pointer(c), callerpc, funcPC(chansend)) - } - - // Fast path: check for failed non-blocking operation without acquiring the lock. - // - // After observing that the channel is not closed, we observe that the channel is - // not ready for sending. Each of these observations is a single word-sized read - // (first c.closed and second c.recvq.first or c.qcount depending on kind of channel). - // Because a closed channel cannot transition from 'ready for sending' to - // 'not ready for sending', even if the channel is closed between the two observations, - // they imply a moment between the two when the channel was both not yet closed - // and not ready for sending. We behave as if we observed the channel at that moment, - // and report that the send cannot proceed. - // - // It is okay if the reads are reordered here: if we observe that the channel is not - // ready for sending and then observe that it is not closed, that implies that the - // channel wasn't closed during the first observation. - if !block && c.closed == 0 && ((c.dataqsiz == 0 && c.recvq.first == nil) || - (c.dataqsiz > 0 && c.qcount == c.dataqsiz)) { - return false - } - - var t0 int64 - if blockprofilerate > 0 { - t0 = cputicks() - } - - lock(&c.lock) - if c.closed != 0 { - unlock(&c.lock) - panic("send on closed channel") - } - - if c.dataqsiz == 0 { // synchronous channel - sg := c.recvq.dequeue() - if sg != nil { // found a waiting receiver - if raceenabled { - racesync(c, sg) - } - unlock(&c.lock) - - recvg := sg.g - if sg.elem != nil { - memmove(unsafe.Pointer(sg.elem), ep, uintptr(c.elemsize)) - sg.elem = nil - } - recvg.param = unsafe.Pointer(sg) - if sg.releasetime != 0 { - sg.releasetime = cputicks() - } - goready(recvg) - return true - } - - if !block { - unlock(&c.lock) - return false - } - - // no receiver available: block on this channel. - gp := getg() - mysg := acquireSudog() - mysg.releasetime = 0 - if t0 != 0 { - mysg.releasetime = -1 - } - mysg.elem = ep - mysg.waitlink = nil - gp.waiting = mysg - mysg.g = gp - mysg.selectdone = nil - gp.param = nil - c.sendq.enqueue(mysg) - goparkunlock(&c.lock, "chan send") - - // someone woke us up. - if mysg != gp.waiting { - gothrow("G waiting list is corrupted!") - } - gp.waiting = nil - if gp.param == nil { - if c.closed == 0 { - gothrow("chansend: spurious wakeup") - } - panic("send on closed channel") - } - gp.param = nil - if mysg.releasetime > 0 { - blockevent(int64(mysg.releasetime)-t0, 2) - } - releaseSudog(mysg) - return true - } - - // asynchronous channel - // wait for some space to write our data - var t1 int64 - for c.qcount >= c.dataqsiz { - if !block { - unlock(&c.lock) - return false - } - gp := getg() - mysg := acquireSudog() - mysg.releasetime = 0 - if t0 != 0 { - mysg.releasetime = -1 - } - mysg.g = gp - mysg.elem = nil - mysg.selectdone = nil - c.sendq.enqueue(mysg) - goparkunlock(&c.lock, "chan send") - - // someone woke us up - try again - if mysg.releasetime > 0 { - t1 = mysg.releasetime - } - releaseSudog(mysg) - lock(&c.lock) - if c.closed != 0 { - unlock(&c.lock) - panic("send on closed channel") - } - } - - // write our data into the channel buffer - if raceenabled { - raceacquire(chanbuf(c, c.sendx)) - racerelease(chanbuf(c, c.sendx)) - } - memmove(chanbuf(c, c.sendx), ep, uintptr(c.elemsize)) - c.sendx++ - if c.sendx == c.dataqsiz { - c.sendx = 0 - } - c.qcount++ - - // wake up a waiting receiver - sg := c.recvq.dequeue() - if sg != nil { - recvg := sg.g - unlock(&c.lock) - if sg.releasetime != 0 { - sg.releasetime = cputicks() - } - goready(recvg) - } else { - unlock(&c.lock) - } - if t1 > 0 { - blockevent(t1-t0, 2) - } - return true -} - -func closechan(c *hchan) { - if c == nil { - panic("close of nil channel") - } - - lock(&c.lock) - if c.closed != 0 { - unlock(&c.lock) - panic("close of closed channel") - } - - if raceenabled { - callerpc := getcallerpc(unsafe.Pointer(&c)) - racewritepc(unsafe.Pointer(c), callerpc, funcPC(closechan)) - racerelease(unsafe.Pointer(c)) - } - - c.closed = 1 - - // release all readers - for { - sg := c.recvq.dequeue() - if sg == nil { - break - } - gp := sg.g - sg.elem = nil - gp.param = nil - if sg.releasetime != 0 { - sg.releasetime = cputicks() - } - goready(gp) - } - - // release all writers - for { - sg := c.sendq.dequeue() - if sg == nil { - break - } - gp := sg.g - sg.elem = nil - gp.param = nil - if sg.releasetime != 0 { - sg.releasetime = cputicks() - } - goready(gp) - } - unlock(&c.lock) -} - -// entry points for <- c from compiled code -//go:nosplit -func chanrecv1(t *chantype, c *hchan, elem unsafe.Pointer) { - chanrecv(t, c, elem, true) -} - -//go:nosplit -func chanrecv2(t *chantype, c *hchan, elem unsafe.Pointer) (received bool) { - _, received = chanrecv(t, c, elem, true) - return -} - -// chanrecv receives on channel c and writes the received data to ep. -// ep may be nil, in which case received data is ignored. -// If block == false and no elements are available, returns (false, false). -// Otherwise, if c is closed, zeros *ep and returns (true, false). -// Otherwise, fills in *ep with an element and returns (true, true). -func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, received bool) { - // raceenabled: don't need to check ep, as it is always on the stack. - - if debugChan { - print("chanrecv: chan=", c, "\n") - } - - if c == nil { - if !block { - return - } - gopark(nil, nil, "chan receive (nil chan)") - gothrow("unreachable") - } - - // Fast path: check for failed non-blocking operation without acquiring the lock. - // - // After observing that the channel is not ready for receiving, we observe that the - // channel is not closed. Each of these observations is a single word-sized read - // (first c.sendq.first or c.qcount, and second c.closed). - // Because a channel cannot be reopened, the later observation of the channel - // being not closed implies that it was also not closed at the moment of the - // first observation. We behave as if we observed the channel at that moment - // and report that the receive cannot proceed. - // - // The order of operations is important here: reversing the operations can lead to - // incorrect behavior when racing with a close. - if !block && (c.dataqsiz == 0 && c.sendq.first == nil || - c.dataqsiz > 0 && atomicloaduint(&c.qcount) == 0) && - atomicload(&c.closed) == 0 { - return - } - - var t0 int64 - if blockprofilerate > 0 { - t0 = cputicks() - } - - lock(&c.lock) - if c.dataqsiz == 0 { // synchronous channel - if c.closed != 0 { - return recvclosed(c, ep) - } - - sg := c.sendq.dequeue() - if sg != nil { - if raceenabled { - racesync(c, sg) - } - unlock(&c.lock) - - if ep != nil { - memmove(ep, sg.elem, uintptr(c.elemsize)) - } - sg.elem = nil - gp := sg.g - gp.param = unsafe.Pointer(sg) - if sg.releasetime != 0 { - sg.releasetime = cputicks() - } - goready(gp) - selected = true - received = true - return - } - - if !block { - unlock(&c.lock) - return - } - - // no sender available: block on this channel. - gp := getg() - mysg := acquireSudog() - mysg.releasetime = 0 - if t0 != 0 { - mysg.releasetime = -1 - } - mysg.elem = ep - mysg.waitlink = nil - gp.waiting = mysg - mysg.g = gp - mysg.selectdone = nil - gp.param = nil - c.recvq.enqueue(mysg) - goparkunlock(&c.lock, "chan receive") - - // someone woke us up - if mysg != gp.waiting { - gothrow("G waiting list is corrupted!") - } - gp.waiting = nil - if mysg.releasetime > 0 { - blockevent(mysg.releasetime-t0, 2) - } - haveData := gp.param != nil - gp.param = nil - releaseSudog(mysg) - - if haveData { - // a sender sent us some data. It already wrote to ep. - selected = true - received = true - return - } - - lock(&c.lock) - if c.closed == 0 { - gothrow("chanrecv: spurious wakeup") - } - return recvclosed(c, ep) - } - - // asynchronous channel - // wait for some data to appear - var t1 int64 - for c.qcount <= 0 { - if c.closed != 0 { - selected, received = recvclosed(c, ep) - if t1 > 0 { - blockevent(t1-t0, 2) - } - return - } - - if !block { - unlock(&c.lock) - return - } - - // wait for someone to send an element - gp := getg() - mysg := acquireSudog() - mysg.releasetime = 0 - if t0 != 0 { - mysg.releasetime = -1 - } - mysg.elem = nil - mysg.g = gp - mysg.selectdone = nil - - c.recvq.enqueue(mysg) - goparkunlock(&c.lock, "chan receive") - - // someone woke us up - try again - if mysg.releasetime > 0 { - t1 = mysg.releasetime - } - releaseSudog(mysg) - lock(&c.lock) - } - - if raceenabled { - raceacquire(chanbuf(c, c.recvx)) - racerelease(chanbuf(c, c.recvx)) - } - if ep != nil { - memmove(ep, chanbuf(c, c.recvx), uintptr(c.elemsize)) - } - memclr(chanbuf(c, c.recvx), uintptr(c.elemsize)) - - c.recvx++ - if c.recvx == c.dataqsiz { - c.recvx = 0 - } - c.qcount-- - - // ping a sender now that there is space - sg := c.sendq.dequeue() - if sg != nil { - gp := sg.g - unlock(&c.lock) - if sg.releasetime != 0 { - sg.releasetime = cputicks() - } - goready(gp) - } else { - unlock(&c.lock) - } - - if t1 > 0 { - blockevent(t1-t0, 2) - } - selected = true - received = true - return -} - -// recvclosed is a helper function for chanrecv. Handles cleanup -// when the receiver encounters a closed channel. -// Caller must hold c.lock, recvclosed will release the lock. -func recvclosed(c *hchan, ep unsafe.Pointer) (selected, recevied bool) { - if raceenabled { - raceacquire(unsafe.Pointer(c)) - } - unlock(&c.lock) - if ep != nil { - memclr(ep, uintptr(c.elemsize)) - } - return true, false -} - -// compiler implements -// -// select { -// case c <- v: -// ... foo -// default: -// ... bar -// } -// -// as -// -// if selectnbsend(c, v) { -// ... foo -// } else { -// ... bar -// } -// -func selectnbsend(t *chantype, c *hchan, elem unsafe.Pointer) (selected bool) { - return chansend(t, c, elem, false, getcallerpc(unsafe.Pointer(&t))) -} - -// compiler implements -// -// select { -// case v = <-c: -// ... foo -// default: -// ... bar -// } -// -// as -// -// if selectnbrecv(&v, c) { -// ... foo -// } else { -// ... bar -// } -// -func selectnbrecv(t *chantype, elem unsafe.Pointer, c *hchan) (selected bool) { - selected, _ = chanrecv(t, c, elem, false) - return -} - -// compiler implements -// -// select { -// case v, ok = <-c: -// ... foo -// default: -// ... bar -// } -// -// as -// -// if c != nil && selectnbrecv2(&v, &ok, c) { -// ... foo -// } else { -// ... bar -// } -// -func selectnbrecv2(t *chantype, elem unsafe.Pointer, received *bool, c *hchan) (selected bool) { - // TODO(khr): just return 2 values from this function, now that it is in Go. - selected, *received = chanrecv(t, c, elem, false) - return -} - -func reflect_chansend(t *chantype, c *hchan, elem unsafe.Pointer, nb bool) (selected bool) { - return chansend(t, c, elem, !nb, getcallerpc(unsafe.Pointer(&t))) -} - -func reflect_chanrecv(t *chantype, c *hchan, nb bool, elem unsafe.Pointer) (selected bool, received bool) { - return chanrecv(t, c, elem, !nb) -} - -func reflect_chanlen(c *hchan) int { - if c == nil { - return 0 - } - return int(c.qcount) -} - -func reflect_chancap(c *hchan) int { - if c == nil { - return 0 - } - return int(c.dataqsiz) -} - -func (q *waitq) enqueue(sgp *sudog) { - sgp.next = nil - if q.first == nil { - q.first = sgp - q.last = sgp - return - } - q.last.next = sgp - q.last = sgp -} - -func (q *waitq) dequeue() *sudog { - for { - sgp := q.first - if sgp == nil { - return nil - } - q.first = sgp.next - sgp.next = nil - if q.last == sgp { - q.last = nil - } - - // if sgp participates in a select and is already signaled, ignore it - if sgp.selectdone != nil { - // claim the right to signal - if *sgp.selectdone != 0 || !cas(sgp.selectdone, 0, 1) { - continue - } - } - - return sgp - } -} - -func racesync(c *hchan, sg *sudog) { - racerelease(chanbuf(c, 0)) - raceacquireg(sg.g, chanbuf(c, 0)) - racereleaseg(sg.g, chanbuf(c, 0)) - raceacquire(chanbuf(c, 0)) -} diff --git a/libgo/go/runtime/chan_test.go b/libgo/go/runtime/chan_test.go index 4fb305c8ae3..6553509457d 100644 --- a/libgo/go/runtime/chan_test.go +++ b/libgo/go/runtime/chan_test.go @@ -223,6 +223,81 @@ func TestNonblockRecvRace(t *testing.T) { } } +// This test checks that select acts on the state of the channels at one +// moment in the execution, not over a smeared time window. +// In the test, one goroutine does: +// create c1, c2 +// make c1 ready for receiving +// create second goroutine +// make c2 ready for receiving +// make c1 no longer ready for receiving (if possible) +// The second goroutine does a non-blocking select receiving from c1 and c2. +// From the time the second goroutine is created, at least one of c1 and c2 +// is always ready for receiving, so the select in the second goroutine must +// always receive from one or the other. It must never execute the default case. +func TestNonblockSelectRace(t *testing.T) { + n := 100000 + if testing.Short() { + n = 1000 + } + done := make(chan bool, 1) + for i := 0; i < n; i++ { + c1 := make(chan int, 1) + c2 := make(chan int, 1) + c1 <- 1 + go func() { + select { + case <-c1: + case <-c2: + default: + done <- false + return + } + done <- true + }() + c2 <- 1 + select { + case <-c1: + default: + } + if !<-done { + t.Fatal("no chan is ready") + } + } +} + +// Same as TestNonblockSelectRace, but close(c2) replaces c2 <- 1. +func TestNonblockSelectRace2(t *testing.T) { + n := 100000 + if testing.Short() { + n = 1000 + } + done := make(chan bool, 1) + for i := 0; i < n; i++ { + c1 := make(chan int, 1) + c2 := make(chan int) + c1 <- 1 + go func() { + select { + case <-c1: + case <-c2: + default: + done <- false + return + } + done <- true + }() + close(c2) + select { + case <-c1: + default: + } + if !<-done { + t.Fatal("no chan is ready") + } + } +} + func TestSelfSelect(t *testing.T) { // Ensure that send/recv on the same chan in select // does not crash nor deadlock. @@ -458,7 +533,7 @@ func TestMultiConsumer(t *testing.T) { func TestShrinkStackDuringBlockedSend(t *testing.T) { // make sure that channel operations still work when we are // blocked on a channel send and we shrink the stack. - // NOTE: this test probably won't fail unless stack.c:StackDebug + // NOTE: this test probably won't fail unless stack1.go:stackDebug // is set to >= 1. const n = 10 c := make(chan int) @@ -823,3 +898,30 @@ func BenchmarkChanSem(b *testing.B) { } }) } + +func BenchmarkChanPopular(b *testing.B) { + const n = 1000 + c := make(chan bool) + var a []chan bool + var wg sync.WaitGroup + wg.Add(n) + for j := 0; j < n; j++ { + d := make(chan bool) + a = append(a, d) + go func() { + for i := 0; i < b.N; i++ { + select { + case <-c: + case <-d: + } + } + wg.Done() + }() + } + for i := 0; i < b.N; i++ { + for _, d := range a { + d <- true + } + } + wg.Wait() +} diff --git a/libgo/go/runtime/chanbarrier_test.go b/libgo/go/runtime/chanbarrier_test.go new file mode 100644 index 00000000000..770b850f874 --- /dev/null +++ b/libgo/go/runtime/chanbarrier_test.go @@ -0,0 +1,83 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime_test + +import ( + "runtime" + "sync" + "testing" +) + +type response struct { +} + +type myError struct { +} + +func (myError) Error() string { return "" } + +func doRequest(useSelect bool) (*response, error) { + type async struct { + resp *response + err error + } + ch := make(chan *async, 0) + done := make(chan struct{}, 0) + + if useSelect { + go func() { + select { + case ch <- &async{resp: nil, err: myError{}}: + case <-done: + } + }() + } else { + go func() { + ch <- &async{resp: nil, err: myError{}} + }() + } + + r := <-ch + runtime.Gosched() + return r.resp, r.err +} + +func TestChanSendSelectBarrier(t *testing.T) { + testChanSendBarrier(true) +} + +func TestChanSendBarrier(t *testing.T) { + testChanSendBarrier(false) +} + +func testChanSendBarrier(useSelect bool) { + var wg sync.WaitGroup + var globalMu sync.Mutex + outer := 100 + inner := 100000 + if testing.Short() { + outer = 10 + inner = 1000 + } + for i := 0; i < outer; i++ { + wg.Add(1) + go func() { + defer wg.Done() + var garbage []byte + for j := 0; j < inner; j++ { + _, err := doRequest(useSelect) + _, ok := err.(myError) + if !ok { + panic(1) + } + garbage = make([]byte, 1<<10) + } + globalMu.Lock() + global = garbage + globalMu.Unlock() + }() + } + wg.Wait() +} diff --git a/libgo/go/runtime/compiler.go b/libgo/go/runtime/compiler.go index 0ed3b183fe2..b04be6181a7 100644 --- a/libgo/go/runtime/compiler.go +++ b/libgo/go/runtime/compiler.go @@ -7,7 +7,7 @@ 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. +// gc Also known as cmd/compile. // gccgo The gccgo front end, part of the GCC compiler suite. // const Compiler = "gccgo" diff --git a/libgo/go/runtime/complex.go b/libgo/go/runtime/complex.go deleted file mode 100644 index ec50f894709..00000000000 --- a/libgo/go/runtime/complex.go +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -func complex128div(n complex128, d complex128) complex128 { - // Special cases as in C99. - ninf := real(n) == posinf || real(n) == neginf || - imag(n) == posinf || imag(n) == neginf - dinf := real(d) == posinf || real(d) == neginf || - imag(d) == posinf || imag(d) == neginf - - nnan := !ninf && (real(n) != real(n) || imag(n) != imag(n)) - dnan := !dinf && (real(d) != real(d) || imag(d) != imag(d)) - - switch { - case nnan || dnan: - return complex(nan, nan) - case ninf && !dinf: - return complex(posinf, posinf) - case !ninf && dinf: - return complex(0, 0) - case real(d) == 0 && imag(d) == 0: - if real(n) == 0 && imag(n) == 0 { - return complex(nan, nan) - } else { - return complex(posinf, posinf) - } - default: - // Standard complex arithmetic, factored to avoid unnecessary overflow. - a := real(d) - if a < 0 { - a = -a - } - b := imag(d) - if b < 0 { - b = -b - } - if a <= b { - ratio := real(d) / imag(d) - denom := real(d)*ratio + imag(d) - return complex((real(n)*ratio+imag(n))/denom, - (imag(n)*ratio-real(n))/denom) - } else { - ratio := imag(d) / real(d) - denom := imag(d)*ratio + real(d) - return complex((imag(n)*ratio+real(n))/denom, - (imag(n)-real(n)*ratio)/denom) - } - } -} diff --git a/libgo/go/runtime/cpuprof.go b/libgo/go/runtime/cpuprof.go deleted file mode 100644 index 8b1c1c63275..00000000000 --- a/libgo/go/runtime/cpuprof.go +++ /dev/null @@ -1,425 +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. - -// CPU profiling. -// Based on algorithms and data structures used in -// http://code.google.com/p/google-perftools/. -// -// The main difference between this code and the google-perftools -// code is that this code is written to allow copying the profile data -// to an arbitrary io.Writer, while the google-perftools code always -// writes to an operating system file. -// -// The signal handler for the profiling clock tick adds a new stack trace -// to a hash table tracking counts for recent traces. Most clock ticks -// hit in the cache. In the event of a cache miss, an entry must be -// evicted from the hash table, copied to a log that will eventually be -// written as profile data. The google-perftools code flushed the -// log itself during the signal handler. This code cannot do that, because -// the io.Writer might block or need system calls or locks that are not -// safe to use from within the signal handler. Instead, we split the log -// into two halves and let the signal handler fill one half while a goroutine -// is writing out the other half. When the signal handler fills its half, it -// offers to swap with the goroutine. If the writer is not done with its half, -// we lose the stack trace for this clock tick (and record that loss). -// The goroutine interacts with the signal handler by calling getprofile() to -// get the next log piece to write, implicitly handing back the last log -// piece it obtained. -// -// The state of this dance between the signal handler and the goroutine -// is encoded in the Profile.handoff field. If handoff == 0, then the goroutine -// is not using either log half and is waiting (or will soon be waiting) for -// a new piece by calling notesleep(&p->wait). If the signal handler -// changes handoff from 0 to non-zero, it must call notewakeup(&p->wait) -// to wake the goroutine. The value indicates the number of entries in the -// log half being handed off. The goroutine leaves the non-zero value in -// place until it has finished processing the log half and then flips the number -// back to zero. Setting the high bit in handoff means that the profiling is over, -// and the goroutine is now in charge of flushing the data left in the hash table -// to the log and returning that data. -// -// The handoff field is manipulated using atomic operations. -// For the most part, the manipulation of handoff is orderly: if handoff == 0 -// then the signal handler owns it and can change it to non-zero. -// If handoff != 0 then the goroutine owns it and can change it to zero. -// If that were the end of the story then we would not need to manipulate -// handoff using atomic operations. The operations are needed, however, -// in order to let the log closer set the high bit to indicate "EOF" safely -// in the situation when normally the goroutine "owns" handoff. - -package runtime - -import "unsafe" - -const ( - numBuckets = 1 << 10 - logSize = 1 << 17 - assoc = 4 - maxCPUProfStack = 64 -) - -type cpuprofEntry struct { - count uintptr - depth uintptr - stack [maxCPUProfStack]uintptr -} - -type cpuProfile struct { - on bool // profiling is on - wait note // goroutine waits here - count uintptr // tick count - evicts uintptr // eviction count - lost uintptr // lost ticks that need to be logged - - // Active recent stack traces. - hash [numBuckets]struct { - entry [assoc]cpuprofEntry - } - - // Log of traces evicted from hash. - // Signal handler has filled log[toggle][:nlog]. - // Goroutine is writing log[1-toggle][:handoff]. - log [2][logSize / 2]uintptr - nlog uintptr - toggle int32 - handoff uint32 - - // Writer state. - // Writer maintains its own toggle to avoid races - // looking at signal handler's toggle. - wtoggle uint32 - wholding bool // holding & need to release a log half - flushing bool // flushing hash table - profile is over - eodSent bool // special end-of-data record sent; => flushing -} - -var ( - cpuprofLock mutex - cpuprof *cpuProfile - - eod = [3]uintptr{0, 1, 0} -) - -func setcpuprofilerate_m() // proc.c - -func setcpuprofilerate(hz int32) { - g := getg() - g.m.scalararg[0] = uintptr(hz) - onM(setcpuprofilerate_m) -} - -// lostProfileData is a no-op function used in profiles -// to mark the number of profiling stack traces that were -// discarded due to slow data writers. -func lostProfileData() {} - -// SetCPUProfileRate sets the CPU profiling rate to hz samples per second. -// If hz <= 0, SetCPUProfileRate turns off profiling. -// If the profiler is on, the rate cannot be changed without first turning it off. -// -// Most clients should use the runtime/pprof package or -// the testing package's -test.cpuprofile flag instead of calling -// SetCPUProfileRate directly. -func SetCPUProfileRate(hz int) { - // Clamp hz to something reasonable. - if hz < 0 { - hz = 0 - } - if hz > 1000000 { - hz = 1000000 - } - - lock(&cpuprofLock) - if hz > 0 { - if cpuprof == nil { - cpuprof = (*cpuProfile)(sysAlloc(unsafe.Sizeof(cpuProfile{}), &memstats.other_sys)) - if cpuprof == nil { - print("runtime: cpu profiling cannot allocate memory\n") - unlock(&cpuprofLock) - return - } - } - if cpuprof.on || cpuprof.handoff != 0 { - print("runtime: cannot set cpu profile rate until previous profile has finished.\n") - unlock(&cpuprofLock) - return - } - - cpuprof.on = true - // pprof binary header format. - // http://code.google.com/p/google-perftools/source/browse/trunk/src/profiledata.cc#117 - p := &cpuprof.log[0] - p[0] = 0 // count for header - p[1] = 3 // depth for header - p[2] = 0 // version number - p[3] = uintptr(1e6 / hz) // period (microseconds) - p[4] = 0 - cpuprof.nlog = 5 - cpuprof.toggle = 0 - cpuprof.wholding = false - cpuprof.wtoggle = 0 - cpuprof.flushing = false - cpuprof.eodSent = false - noteclear(&cpuprof.wait) - - setcpuprofilerate(int32(hz)) - } else if cpuprof != nil && cpuprof.on { - setcpuprofilerate(0) - cpuprof.on = false - - // Now add is not running anymore, and getprofile owns the entire log. - // Set the high bit in prof->handoff to tell getprofile. - for { - n := cpuprof.handoff - if n&0x80000000 != 0 { - print("runtime: setcpuprofile(off) twice\n") - } - if cas(&cpuprof.handoff, n, n|0x80000000) { - if n == 0 { - // we did the transition from 0 -> nonzero so we wake getprofile - notewakeup(&cpuprof.wait) - } - break - } - } - } - unlock(&cpuprofLock) -} - -func cpuproftick(pc *uintptr, n int32) { - if n > maxCPUProfStack { - n = maxCPUProfStack - } - s := (*[maxCPUProfStack]uintptr)(unsafe.Pointer(pc))[:n] - cpuprof.add(s) -} - -// add adds the stack trace to the profile. -// It is called from signal handlers and other limited environments -// and cannot allocate memory or acquire locks that might be -// held at the time of the signal, nor can it use substantial amounts -// of stack. It is allowed to call evict. -func (p *cpuProfile) add(pc []uintptr) { - // Compute hash. - h := uintptr(0) - for _, x := range pc { - h = h<<8 | (h >> (8 * (unsafe.Sizeof(h) - 1))) - h += x*31 + x*7 + x*3 - } - p.count++ - - // Add to entry count if already present in table. - b := &p.hash[h%numBuckets] -Assoc: - for i := range b.entry { - e := &b.entry[i] - if e.depth != uintptr(len(pc)) { - continue - } - for j := range pc { - if e.stack[j] != pc[j] { - continue Assoc - } - } - e.count++ - return - } - - // Evict entry with smallest count. - var e *cpuprofEntry - for i := range b.entry { - if e == nil || b.entry[i].count < e.count { - e = &b.entry[i] - } - } - if e.count > 0 { - if !p.evict(e) { - // Could not evict entry. Record lost stack. - p.lost++ - return - } - p.evicts++ - } - - // Reuse the newly evicted entry. - e.depth = uintptr(len(pc)) - e.count = 1 - copy(e.stack[:], pc) -} - -// evict copies the given entry's data into the log, so that -// the entry can be reused. evict is called from add, which -// is called from the profiling signal handler, so it must not -// allocate memory or block. It is safe to call flushlog. -// evict returns true if the entry was copied to the log, -// false if there was no room available. -func (p *cpuProfile) evict(e *cpuprofEntry) bool { - d := e.depth - nslot := d + 2 - log := &p.log[p.toggle] - if p.nlog+nslot > uintptr(len(p.log[0])) { - if !p.flushlog() { - return false - } - log = &p.log[p.toggle] - } - - q := p.nlog - log[q] = e.count - q++ - log[q] = d - q++ - copy(log[q:], e.stack[:d]) - q += d - p.nlog = q - e.count = 0 - return true -} - -// flushlog tries to flush the current log and switch to the other one. -// flushlog is called from evict, called from add, called from the signal handler, -// so it cannot allocate memory or block. It can try to swap logs with -// the writing goroutine, as explained in the comment at the top of this file. -func (p *cpuProfile) flushlog() bool { - if !cas(&p.handoff, 0, uint32(p.nlog)) { - return false - } - notewakeup(&p.wait) - - p.toggle = 1 - p.toggle - log := &p.log[p.toggle] - q := uintptr(0) - if p.lost > 0 { - lostPC := funcPC(lostProfileData) - log[0] = p.lost - log[1] = 1 - log[2] = lostPC - q = 3 - p.lost = 0 - } - p.nlog = q - return true -} - -// getprofile blocks until the next block of profiling data is available -// and returns it as a []byte. It is called from the writing goroutine. -func (p *cpuProfile) getprofile() []byte { - if p == nil { - return nil - } - - if p.wholding { - // Release previous log to signal handling side. - // Loop because we are racing against SetCPUProfileRate(0). - for { - n := p.handoff - if n == 0 { - print("runtime: phase error during cpu profile handoff\n") - return nil - } - if n&0x80000000 != 0 { - p.wtoggle = 1 - p.wtoggle - p.wholding = false - p.flushing = true - goto Flush - } - if cas(&p.handoff, n, 0) { - break - } - } - p.wtoggle = 1 - p.wtoggle - p.wholding = false - } - - if p.flushing { - goto Flush - } - - if !p.on && p.handoff == 0 { - return nil - } - - // Wait for new log. - notetsleepg(&p.wait, -1) - noteclear(&p.wait) - - switch n := p.handoff; { - case n == 0: - print("runtime: phase error during cpu profile wait\n") - return nil - case n == 0x80000000: - p.flushing = true - goto Flush - default: - n &^= 0x80000000 - - // Return new log to caller. - p.wholding = true - - return uintptrBytes(p.log[p.wtoggle][:n]) - } - - // In flush mode. - // Add is no longer being called. We own the log. - // Also, p->handoff is non-zero, so flushlog will return false. - // Evict the hash table into the log and return it. -Flush: - for i := range p.hash { - b := &p.hash[i] - for j := range b.entry { - e := &b.entry[j] - if e.count > 0 && !p.evict(e) { - // Filled the log. Stop the loop and return what we've got. - break Flush - } - } - } - - // Return pending log data. - if p.nlog > 0 { - // Note that we're using toggle now, not wtoggle, - // because we're working on the log directly. - n := p.nlog - p.nlog = 0 - return uintptrBytes(p.log[p.toggle][:n]) - } - - // Made it through the table without finding anything to log. - if !p.eodSent { - // We may not have space to append this to the partial log buf, - // so we always return a new slice for the end-of-data marker. - p.eodSent = true - return uintptrBytes(eod[:]) - } - - // Finally done. Clean up and return nil. - p.flushing = false - if !cas(&p.handoff, p.handoff, 0) { - print("runtime: profile flush racing with something\n") - } - return nil -} - -func uintptrBytes(p []uintptr) (ret []byte) { - pp := (*sliceStruct)(unsafe.Pointer(&p)) - rp := (*sliceStruct)(unsafe.Pointer(&ret)) - - rp.array = pp.array - rp.len = pp.len * int(unsafe.Sizeof(p[0])) - rp.cap = rp.len - - return -} - -// CPUProfile returns the next chunk of binary CPU profiling stack trace data, -// blocking until data is available. If profiling is turned off and all the profile -// data accumulated while it was on has been returned, CPUProfile returns nil. -// The caller must save the returned data before calling CPUProfile again. -// -// Most clients should use the runtime/pprof package or -// the testing package's -test.cpuprofile flag instead of calling -// CPUProfile directly. -func CPUProfile() []byte { - return cpuprof.getprofile() -} diff --git a/libgo/go/runtime/crash_cgo_test.go b/libgo/go/runtime/crash_cgo_test.go index 29f90fa36d2..2e65e4c7543 100644 --- a/libgo/go/runtime/crash_cgo_test.go +++ b/libgo/go/runtime/crash_cgo_test.go @@ -36,6 +36,20 @@ func TestCgoTraceback(t *testing.T) { } } +func TestCgoCallbackGC(t *testing.T) { + if runtime.GOOS == "plan9" || runtime.GOOS == "windows" { + t.Skipf("no pthreads on %s", runtime.GOOS) + } + if testing.Short() && runtime.GOOS == "dragonfly" { + t.Skip("see golang.org/issue/11990") + } + got := executeTest(t, cgoCallbackGCSource, nil) + want := "OK\n" + if got != want { + t.Fatalf("expected %q, but got %q", want, got) + } +} + func TestCgoExternalThreadPanic(t *testing.T) { if runtime.GOOS == "plan9" { t.Skipf("no pthreads on %s", runtime.GOOS) @@ -57,17 +71,24 @@ func TestCgoExternalThreadSIGPROF(t *testing.T) { case "plan9", "windows": t.Skipf("no pthreads on %s", runtime.GOOS) case "darwin": - // static constructor needs external linking, but we don't support - // external linking on OS X 10.6. - out, err := exec.Command("uname", "-r").Output() - if err != nil { - t.Fatalf("uname -r failed: %v", err) - } - // OS X 10.6 == Darwin 10.x - if strings.HasPrefix(string(out), "10.") { - t.Skipf("no external linking on OS X 10.6") + if runtime.GOARCH != "arm" && runtime.GOARCH != "arm64" { + // static constructor needs external linking, but we don't support + // external linking on OS X 10.6. + out, err := exec.Command("uname", "-r").Output() + if err != nil { + t.Fatalf("uname -r failed: %v", err) + } + // OS X 10.6 == Darwin 10.x + if strings.HasPrefix(string(out), "10.") { + t.Skipf("no external linking on OS X 10.6") + } } } + if runtime.GOARCH == "ppc64" || runtime.GOARCH == "ppc64le" { + // TODO(austin) External linking not implemented on + // ppc64 (issue #8912) + t.Skipf("no external linking on ppc64") + } got := executeTest(t, cgoExternalThreadSIGPROFSource, nil) want := "OK\n" if got != want { @@ -75,6 +96,31 @@ func TestCgoExternalThreadSIGPROF(t *testing.T) { } } +func TestCgoExternalThreadSignal(t *testing.T) { + // issue 10139 + switch runtime.GOOS { + case "plan9", "windows": + t.Skipf("no pthreads on %s", runtime.GOOS) + } + got := executeTest(t, cgoExternalThreadSignalSource, nil) + want := "OK\n" + if got != want { + t.Fatalf("expected %q, but got %q", want, got) + } +} + +func TestCgoDLLImports(t *testing.T) { + // test issue 9356 + if runtime.GOOS != "windows" { + t.Skip("skipping windows specific test") + } + got := executeTest(t, cgoDLLImportsMainSource, nil, "a/a.go", cgoDLLImportsPkgSource) + want := "OK\n" + if got != want { + t.Fatalf("expected %q, but got %v", want, got) + } +} + const cgoSignalDeadlockSource = ` package main @@ -159,6 +205,83 @@ func main() { } ` +const cgoCallbackGCSource = ` +package main + +import "runtime" + +/* +#include + +void go_callback(); + +static void *thr(void *arg) { + go_callback(); + return 0; +} + +static void foo() { + pthread_t th; + pthread_create(&th, 0, thr, 0); + pthread_join(th, 0); +} +*/ +import "C" +import "fmt" + +//export go_callback +func go_callback() { + runtime.GC() + grow() + runtime.GC() +} + +var cnt int + +func grow() { + x := 10000 + sum := 0 + if grow1(&x, &sum) == 0 { + panic("bad") + } +} + +func grow1(x, sum *int) int { + if *x == 0 { + return *sum + 1 + } + *x-- + sum1 := *sum + *x + return grow1(x, &sum1) +} + +func main() { + const P = 100 + done := make(chan bool) + // allocate a bunch of stack frames and spray them with pointers + for i := 0; i < P; i++ { + go func() { + grow() + done <- true + }() + } + for i := 0; i < P; i++ { + <-done + } + // now give these stack frames to cgo callbacks + for i := 0; i < P; i++ { + go func() { + C.foo() + done <- true + }() + } + for i := 0; i < P; i++ { + <-done + } + fmt.Printf("OK\n") +} +` + const cgoExternalThreadPanicSource = ` package main @@ -254,7 +377,7 @@ import ( func main() { // This test intends to test that sending SIGPROF to foreign threads // before we make any cgo call will not abort the whole process, so - // we cannot make any cgo call here. See http://golang.org/issue/9456. + // we cannot make any cgo call here. See https://golang.org/issue/9456. atomic.StoreInt32((*int32)(unsafe.Pointer(&C.spinlock)), 1) for atomic.LoadInt32((*int32)(unsafe.Pointer(&C.spinlock))) == 1 { runtime.Gosched() @@ -262,3 +385,97 @@ func main() { println("OK") } ` + +const cgoExternalThreadSignalSource = ` +package main + +/* +#include + +void **nullptr; + +void *crash(void *p) { + *nullptr = p; + return 0; +} + +int start_crashing_thread(void) { + pthread_t tid; + return pthread_create(&tid, 0, crash, 0); +} +*/ +import "C" + +import ( + "fmt" + "os" + "os/exec" + "time" +) + +func main() { + if len(os.Args) > 1 && os.Args[1] == "crash" { + i := C.start_crashing_thread() + if i != 0 { + fmt.Println("pthread_create failed:", i) + // Exit with 0 because parent expects us to crash. + return + } + + // We should crash immediately, but give it plenty of + // time before failing (by exiting 0) in case we are + // running on a slow system. + time.Sleep(5 * time.Second) + return + } + + out, err := exec.Command(os.Args[0], "crash").CombinedOutput() + if err == nil { + fmt.Println("C signal did not crash as expected\n") + fmt.Printf("%s\n", out) + os.Exit(1) + } + + fmt.Println("OK") +} +` + +const cgoDLLImportsMainSource = ` +package main + +/* +#include + +DWORD getthread() { + return GetCurrentThreadId(); +} +*/ +import "C" + +import "./a" + +func main() { + C.getthread() + a.GetThread() + println("OK") +} +` + +const cgoDLLImportsPkgSource = ` +package a + +/* +#cgo CFLAGS: -mnop-fun-dllimport + +#include + +DWORD agetthread() { + return GetCurrentThreadId(); +} +*/ +import "C" + +func GetThread() uint32 { + return uint32(C.agetthread()) +} +` diff --git a/libgo/go/runtime/crash_test.go b/libgo/go/runtime/crash_test.go index 7e8a2e45f0e..8efce4da2d4 100644 --- a/libgo/go/runtime/crash_test.go +++ b/libgo/go/runtime/crash_test.go @@ -5,38 +5,41 @@ package runtime_test import ( + "fmt" + "internal/testenv" "io/ioutil" "os" "os/exec" "path/filepath" + "regexp" "runtime" "strings" + "sync" "testing" "text/template" ) -// testEnv excludes GODEBUG from the environment -// to prevent its output from breaking tests that -// are trying to parse other command output. func testEnv(cmd *exec.Cmd) *exec.Cmd { if cmd.Env != nil { panic("environment already set") } for _, env := range os.Environ() { + // Exclude GODEBUG from the environment to prevent its output + // from breaking tests that are trying to parse other command output. if strings.HasPrefix(env, "GODEBUG=") { continue } + // Exclude GOTRACEBACK for the same reason. + if strings.HasPrefix(env, "GOTRACEBACK=") { + continue + } cmd.Env = append(cmd.Env, env) } return cmd } func executeTest(t *testing.T, templ string, data interface{}, extra ...string) string { - t.Skip("gccgo does not have a go command") - switch runtime.GOOS { - case "android", "nacl": - t.Skipf("skipping on %s", runtime.GOOS) - } + testenv.MustHaveGoBuild(t) checkStaleRuntime(t) @@ -63,7 +66,14 @@ func executeTest(t *testing.T, templ string, data interface{}, extra ...string) } for i := 0; i < len(extra); i += 2 { - if err := ioutil.WriteFile(filepath.Join(dir, extra[i]), []byte(extra[i+1]), 0666); err != nil { + fname := extra[i] + contents := extra[i+1] + if d, _ := filepath.Split(fname); d != "" { + if err := os.Mkdir(filepath.Join(dir, d), 0755); err != nil { + t.Fatal(err) + } + } + if err := ioutil.WriteFile(filepath.Join(dir, fname), []byte(contents), 0666); err != nil { t.Fatal(err) } } @@ -79,14 +89,25 @@ func executeTest(t *testing.T, templ string, data interface{}, extra ...string) return string(got) } +var ( + staleRuntimeOnce sync.Once // guards init of staleRuntimeErr + staleRuntimeErr error +) + func checkStaleRuntime(t *testing.T) { - // 'go run' uses the installed copy of runtime.a, which may be out of date. - out, err := testEnv(exec.Command("go", "list", "-f", "{{.Stale}}", "runtime")).CombinedOutput() - if err != nil { - t.Fatalf("failed to execute 'go list': %v\n%v", err, string(out)) - } - if string(out) != "false\n" { - t.Fatalf("Stale runtime.a. Run 'go install runtime'.") + staleRuntimeOnce.Do(func() { + // 'go run' uses the installed copy of runtime.a, which may be out of date. + out, err := testEnv(exec.Command("go", "list", "-f", "{{.Stale}}", "runtime")).CombinedOutput() + if err != nil { + staleRuntimeErr = fmt.Errorf("failed to execute 'go list': %v\n%v", err, string(out)) + return + } + if string(out) != "false\n" { + staleRuntimeErr = fmt.Errorf("Stale runtime.a. Run 'go install runtime'.") + } + }) + if staleRuntimeErr != nil { + t.Fatal(staleRuntimeErr) } } @@ -205,6 +226,14 @@ func TestMainGoroutineId(t *testing.T) { } } +func TestNoHelperGoroutines(t *testing.T) { + output := executeTest(t, noHelperGoroutinesSource, nil) + matches := regexp.MustCompile(`goroutine [0-9]+ \[`).FindAllStringSubmatch(output, -1) + if len(matches) != 1 || matches[0][0] != "goroutine 1 [" { + t.Fatalf("want to see only goroutine 1, see:\n%s", output) + } +} + func TestBreakpoint(t *testing.T) { output := executeTest(t, breakpointSource, nil) want := "runtime.Breakpoint()" @@ -419,6 +448,22 @@ func main() { } ` +const noHelperGoroutinesSource = ` +package main +import ( + "runtime" + "time" +) +func init() { + i := 0 + runtime.SetFinalizer(&i, func(p *int) {}) + time.AfterFunc(time.Hour, func() {}) + panic("oops") +} +func main() { +} +` + const breakpointSource = ` package main import "runtime" @@ -514,3 +559,31 @@ func TestRecoverBeforePanicAfterGoexit(t *testing.T) { }() runtime.Goexit() } + +func TestNetpollDeadlock(t *testing.T) { + output := executeTest(t, netpollDeadlockSource, nil) + want := "done\n" + if !strings.HasSuffix(output, want) { + t.Fatalf("output does not start with %q:\n%s", want, output) + } +} + +const netpollDeadlockSource = ` +package main +import ( + "fmt" + "net" +) +func init() { + fmt.Println("dialing") + c, err := net.Dial("tcp", "localhost:14356") + if err == nil { + c.Close() + } else { + fmt.Println("error: ", err) + } +} +func main() { + fmt.Println("done") +} +` diff --git a/libgo/go/runtime/crash_unix_test.go b/libgo/go/runtime/crash_unix_test.go new file mode 100644 index 00000000000..b925d028aaf --- /dev/null +++ b/libgo/go/runtime/crash_unix_test.go @@ -0,0 +1,135 @@ +// 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 darwin dragonfly freebsd linux netbsd openbsd solaris + +package runtime_test + +import ( + "bytes" + "internal/testenv" + "io/ioutil" + "os" + "os/exec" + "path/filepath" + "runtime" + "syscall" + "testing" +) + +func TestCrashDumpsAllThreads(t *testing.T) { + switch runtime.GOOS { + case "darwin", "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris": + default: + t.Skipf("skipping; not supported on %v", runtime.GOOS) + } + + // We don't use executeTest because we need to kill the + // program while it is running. + + testenv.MustHaveGoBuild(t) + + checkStaleRuntime(t) + + dir, err := ioutil.TempDir("", "go-build") + if err != nil { + t.Fatalf("failed to create temp directory: %v", err) + } + defer os.RemoveAll(dir) + + if err := ioutil.WriteFile(filepath.Join(dir, "main.go"), []byte(crashDumpsAllThreadsSource), 0666); err != nil { + t.Fatalf("failed to create Go file: %v", err) + } + + cmd := exec.Command("go", "build", "-o", "a.exe") + cmd.Dir = dir + out, err := testEnv(cmd).CombinedOutput() + if err != nil { + t.Fatalf("building source: %v\n%s", err, out) + } + + cmd = exec.Command(filepath.Join(dir, "a.exe")) + cmd = testEnv(cmd) + cmd.Env = append(cmd.Env, "GOTRACEBACK=crash") + var outbuf bytes.Buffer + cmd.Stdout = &outbuf + cmd.Stderr = &outbuf + + rp, wp, err := os.Pipe() + if err != nil { + t.Fatal(err) + } + cmd.ExtraFiles = []*os.File{wp} + + if err := cmd.Start(); err != nil { + t.Fatalf("starting program: %v", err) + } + + if err := wp.Close(); err != nil { + t.Logf("closing write pipe: %v", err) + } + if _, err := rp.Read(make([]byte, 1)); err != nil { + t.Fatalf("reading from pipe: %v", err) + } + + if err := cmd.Process.Signal(syscall.SIGQUIT); err != nil { + t.Fatalf("signal: %v", err) + } + + // No point in checking the error return from Wait--we expect + // it to fail. + cmd.Wait() + + // We want to see a stack trace for each thread. + // Before https://golang.org/cl/2811 running threads would say + // "goroutine running on other thread; stack unavailable". + out = outbuf.Bytes() + n := bytes.Count(out, []byte("main.loop(")) + if n != 4 { + t.Errorf("found %d instances of main.loop; expected 4", n) + t.Logf("%s", out) + } +} + +const crashDumpsAllThreadsSource = ` +package main + +import ( + "fmt" + "os" + "runtime" +) + +func main() { + const count = 4 + runtime.GOMAXPROCS(count + 1) + + chans := make([]chan bool, count) + for i := range chans { + chans[i] = make(chan bool) + go loop(i, chans[i]) + } + + // Wait for all the goroutines to start executing. + for _, c := range chans { + <-c + } + + // Tell our parent that all the goroutines are executing. + if _, err := os.NewFile(3, "pipe").WriteString("x"); err != nil { + fmt.Fprintf(os.Stderr, "write to pipe failed: %v\n", err) + os.Exit(2) + } + + select {} +} + +func loop(i int, c chan bool) { + close(c) + for { + for j := 0; j < 0x7fffffff; j++ { + } + } +} +` diff --git a/libgo/go/runtime/debug/garbage.go b/libgo/go/runtime/debug/garbage.go index edb3643871e..c3363f9dd58 100644 --- a/libgo/go/runtime/debug/garbage.go +++ b/libgo/go/runtime/debug/garbage.go @@ -149,5 +149,5 @@ func SetPanicOnFault(enabled bool) bool // WriteHeapDump writes a description of the heap and the objects in // it to the given file descriptor. -// The heap dump format is defined at http://golang.org/s/go13heapdump. +// The heap dump format is defined at https://golang.org/s/go13heapdump. func WriteHeapDump(fd uintptr) diff --git a/libgo/go/runtime/debug/garbage_test.go b/libgo/go/runtime/debug/garbage_test.go index 149bafc6f3c..13e1845098e 100644 --- a/libgo/go/runtime/debug/garbage_test.go +++ b/libgo/go/runtime/debug/garbage_test.go @@ -75,6 +75,10 @@ func TestReadGCStats(t *testing.T) { var big = make([]byte, 1<<20) func TestFreeOSMemory(t *testing.T) { + if runtime.GOARCH == "arm64" || runtime.GOARCH == "ppc64" || runtime.GOARCH == "ppc64le" || + runtime.GOOS == "nacl" { + t.Skip("issue 9993; scavenger temporarily disabled on systems with physical pages larger than logical pages") + } var ms1, ms2 runtime.MemStats if big == nil { diff --git a/libgo/go/runtime/debug/heapdump_test.go b/libgo/go/runtime/debug/heapdump_test.go index 9201901151f..cb2f2f06798 100644 --- a/libgo/go/runtime/debug/heapdump_test.go +++ b/libgo/go/runtime/debug/heapdump_test.go @@ -31,3 +31,39 @@ func TestWriteHeapDumpNonempty(t *testing.T) { t.Fatalf("Heap dump size %d bytes, expected at least %d bytes", size, minSize) } } + +type Obj struct { + x, y int +} + +func objfin(x *Obj) { + println("finalized", x) +} + +func TestWriteHeapDumpFinalizers(t *testing.T) { + if runtime.GOOS == "nacl" { + t.Skip("WriteHeapDump is not available on NaCl.") + } + f, err := ioutil.TempFile("", "heapdumptest") + if err != nil { + t.Fatalf("TempFile failed: %v", err) + } + defer os.Remove(f.Name()) + defer f.Close() + + // bug 9172: WriteHeapDump couldn't handle more than one finalizer + println("allocating objects") + x := &Obj{} + runtime.SetFinalizer(x, objfin) + y := &Obj{} + runtime.SetFinalizer(y, objfin) + + // Trigger collection of x and y, queueing of their finalizers. + println("starting gc") + runtime.GC() + + // Make sure WriteHeapDump doesn't fail with multiple queued finalizers. + println("starting dump") + WriteHeapDump(f.Fd()) + println("done dump") +} diff --git a/libgo/go/runtime/debug/stack.go b/libgo/go/runtime/debug/stack.go index c29b0a226a2..ab12bffa6e5 100644 --- a/libgo/go/runtime/debug/stack.go +++ b/libgo/go/runtime/debug/stack.go @@ -31,7 +31,7 @@ func PrintStack() { // then attempts to discover, for Go functions, the calling function or // method and the text of the line containing the invocation. // -// This function is deprecated. Use package runtime's Stack instead. +// Deprecated: Use package runtime's Stack instead. func Stack() []byte { return stack() } diff --git a/libgo/go/runtime/env_posix.go b/libgo/go/runtime/env_posix.go deleted file mode 100644 index 8b1dbb7994d..00000000000 --- a/libgo/go/runtime/env_posix.go +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows - -package runtime - -import "unsafe" - -func environ() []string - -func getenv(s *byte) *byte { - val := gogetenv(gostringnocopy(s)) - if val == "" { - return nil - } - // Strings found in environment are NUL-terminated. - return &bytes(val)[0] -} - -func gogetenv(key string) string { - env := environ() - if env == nil { - gothrow("getenv before env init") - } - for _, s := range environ() { - if len(s) > len(key) && s[len(key)] == '=' && s[:len(key)] == key { - return s[len(key)+1:] - } - } - return "" -} - -//extern setenv -func _cgo_setenv(unsafe.Pointer, unsafe.Pointer, int32) - -//extern unsetenv -func _cgo_unsetenv(unsafe.Pointer) - -// Update the C environment if cgo is loaded. -// Called from syscall.Setenv. -func syscall_setenv_c(k string, v string) { - _cgo_setenv(cstring(k), cstring(v), 1) -} - -// Update the C environment if cgo is loaded. -// Called from syscall.unsetenv. -func syscall_unsetenv_c(k string) { - _cgo_unsetenv(cstring(k)) -} - -func cstring(s string) unsafe.Pointer { - p := make([]byte, len(s)+1) - sp := (*_string)(unsafe.Pointer(&s)) - memmove(unsafe.Pointer(&p[0]), unsafe.Pointer(sp.str), uintptr(len(s))) - return unsafe.Pointer(&p[0]) -} diff --git a/libgo/go/runtime/env_test.go b/libgo/go/runtime/env_test.go new file mode 100644 index 00000000000..2399e46faa9 --- /dev/null +++ b/libgo/go/runtime/env_test.go @@ -0,0 +1,47 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime_test + +import ( + "runtime" + "syscall" + "testing" +) + +func TestFixedGOROOT(t *testing.T) { + if runtime.GOOS == "plan9" { + t.Skipf("skipping plan9, it is inconsistent by allowing GOROOT to be updated by Setenv") + } + + // Restore both the real GOROOT environment variable, and runtime's copies: + if orig, ok := syscall.Getenv("GOROOT"); ok { + defer syscall.Setenv("GOROOT", orig) + } else { + defer syscall.Unsetenv("GOROOT") + } + envs := runtime.Envs() + oldenvs := append([]string{}, envs...) + defer runtime.SetEnvs(oldenvs) + + // attempt to reuse existing envs backing array. + want := runtime.GOROOT() + runtime.SetEnvs(append(envs[:0], "GOROOT="+want)) + + if got := runtime.GOROOT(); got != want { + t.Errorf(`initial runtime.GOROOT()=%q, want %q`, got, want) + } + if err := syscall.Setenv("GOROOT", "/os"); err != nil { + t.Fatal(err) + } + if got := runtime.GOROOT(); got != want { + t.Errorf(`after setenv runtime.GOROOT()=%q, want %q`, got, want) + } + if err := syscall.Unsetenv("GOROOT"); err != nil { + t.Fatal(err) + } + if got := runtime.GOROOT(); got != want { + t.Errorf(`after unsetenv runtime.GOROOT()=%q, want %q`, got, want) + } +} diff --git a/libgo/go/runtime/error.go b/libgo/go/runtime/error.go index d759a54a519..c4621b6f858 100644 --- a/libgo/go/runtime/error.go +++ b/libgo/go/runtime/error.go @@ -9,9 +9,9 @@ type Error interface { error // RuntimeError is a no-op function but - // serves to distinguish types that are runtime + // serves to distinguish types that are run time // errors from ordinary errors: a type is a - // runtime error if it has a RuntimeError method. + // run time error if it has a RuntimeError method. RuntimeError() } diff --git a/libgo/go/runtime/export_arm_test.go b/libgo/go/runtime/export_arm_test.go new file mode 100644 index 00000000000..446d26465c8 --- /dev/null +++ b/libgo/go/runtime/export_arm_test.go @@ -0,0 +1,9 @@ +// Copyright 2015 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. + +// Export guts for testing. + +package runtime + +var Usplit = usplit diff --git a/libgo/go/runtime/export_linux_test.go b/libgo/go/runtime/export_linux_test.go new file mode 100644 index 00000000000..37cf164cd9b --- /dev/null +++ b/libgo/go/runtime/export_linux_test.go @@ -0,0 +1,9 @@ +// Copyright 2015 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. + +// Export guts for testing. + +package runtime + +//var NewOSProc0 = newosproc0 diff --git a/libgo/go/runtime/export_test.go b/libgo/go/runtime/export_test.go index 165bebf6316..8782914b5b9 100644 --- a/libgo/go/runtime/export_test.go +++ b/libgo/go/runtime/export_test.go @@ -6,26 +6,33 @@ package runtime -var Fadd64 = fadd64 -var Fsub64 = fsub64 -var Fmul64 = fmul64 -var Fdiv64 = fdiv64 -var F64to32 = f64to32 -var F32to64 = f32to64 -var Fcmp64 = fcmp64 -var Fintto64 = fintto64 -var F64toint = f64toint - -func entersyscall() -func exitsyscall() +import "unsafe" + +//var Fadd64 = fadd64 +//var Fsub64 = fsub64 +//var Fmul64 = fmul64 +//var Fdiv64 = fdiv64 +//var F64to32 = f64to32 +//var F32to64 = f32to64 +//var Fcmp64 = fcmp64 +//var Fintto64 = fintto64 +//var F64toint = f64toint +//var Sqrt = sqrt + +func entersyscall(int32) +func exitsyscall(int32) func golockedOSThread() bool var Entersyscall = entersyscall var Exitsyscall = exitsyscall var LockedOSThread = golockedOSThread +// var Xadduintptr = xadduintptr + +// var FuncPC = funcPC + type LFNode struct { - Next *LFNode + Next uint64 Pushcnt uintptr } @@ -36,18 +43,16 @@ var LFStackPush = lfstackpush_go var LFStackPop = lfstackpop_go type ParFor struct { - body *byte - done uint32 - Nthr uint32 - nthrmax uint32 - thrseq uint32 - Cnt uint32 - Ctx *byte - wait bool + body func(*ParFor, uint32) + done uint32 + Nthr uint32 + thrseq uint32 + Cnt uint32 + wait bool } func newParFor(nthrmax uint32) *ParFor -func parForSetup(desc *ParFor, nthr, n uint32, ctx *byte, wait bool, body func(*ParFor, uint32)) +func parForSetup(desc *ParFor, nthr, n uint32, wait bool, body func(*ParFor, uint32)) func parForDo(desc *ParFor) func parForIters(desc *ParFor, tid uintptr) (uintptr, uintptr) @@ -60,31 +65,110 @@ func ParForIters(desc *ParFor, tid uint32) (uint32, uint32) { return uint32(begin), uint32(end) } -func testSchedLocalQueue() -func testSchedLocalQueueSteal() +func GCMask(x interface{}) (ret []byte) { + return nil +} + +//func testSchedLocalQueue() +//func testSchedLocalQueueSteal() +// +//func RunSchedLocalQueueTest() { +// testSchedLocalQueue() +//} +// +//func RunSchedLocalQueueStealTest() { +// testSchedLocalQueueSteal() +//} + +//var StringHash = stringHash +//var BytesHash = bytesHash +//var Int32Hash = int32Hash +//var Int64Hash = int64Hash +//var EfaceHash = efaceHash +//var IfaceHash = ifaceHash +//var MemclrBytes = memclrBytes + +// var HashLoad = &hashLoad + +// entry point for testing +//func GostringW(w []uint16) (s string) { +// s = gostringw(&w[0]) +// return +//} + +//var Gostringnocopy = gostringnocopy +//var Maxstring = &maxstring + +//type Uintreg uintreg + +//extern __go_open +func open(path *byte, mode int32, perm int32) int32 + +func Open(path *byte, mode int32, perm int32) int32 { + return open(path, mode, perm) +} + +//extern close +func close(int32) int32 -var TestSchedLocalQueue1 = testSchedLocalQueue -var TestSchedLocalQueueSteal1 = testSchedLocalQueueSteal +func Close(fd int32) int32 { + return close(fd) +} -// func haveGoodHash() bool -// func stringHash(s string, seed uintptr) uintptr -// func bytesHash(b []byte, seed uintptr) uintptr -// func int32Hash(i uint32, seed uintptr) uintptr -// func int64Hash(i uint64, seed uintptr) uintptr +//extern read +func read(fd int32, buf unsafe.Pointer, size int32) int32 -// var HaveGoodHash = haveGoodHash -// var StringHash = stringHash -// var BytesHash = bytesHash -// var Int32Hash = int32Hash -// var Int64Hash = int64Hash +func Read(fd int32, buf unsafe.Pointer, size int32) int32 { + return read(fd, buf, size) +} -var hashLoad float64 // declared in hashmap.c -var HashLoad = &hashLoad +//extern write +func write(fd int32, buf unsafe.Pointer, size int32) int32 -func memclrBytes(b []byte) +func Write(fd uintptr, buf unsafe.Pointer, size int32) int32 { + return write(int32(fd), buf, size) +} -var MemclrBytes = memclrBytes +func envs() []string +func setenvs([]string) + +var Envs = envs +var SetEnvs = setenvs + +//var BigEndian = _BigEndian + +// For benchmarking. + +/* +func BenchSetType(n int, x interface{}) { + e := *(*eface)(unsafe.Pointer(&x)) + t := e._type + var size uintptr + var p unsafe.Pointer + switch t.kind & kindMask { + case _KindPtr: + t = (*ptrtype)(unsafe.Pointer(t)).elem + size = t.size + p = e.data + case _KindSlice: + slice := *(*struct { + ptr unsafe.Pointer + len, cap uintptr + })(e.data) + t = (*slicetype)(unsafe.Pointer(t)).elem + size = t.size * slice.len + p = slice.ptr + } + allocSize := roundupsize(size) + systemstack(func() { + for i := 0; i < n; i++ { + heapBitsSetType(uintptr(p), allocSize, size, t) + } + }) +} -// func gogoBytes() int32 +const PtrSize = ptrSize -// var GogoBytes = gogoBytes +var TestingAssertE2I2GC = &testingAssertE2I2GC +var TestingAssertE2T2GC = &testingAssertE2T2GC +*/ diff --git a/libgo/go/runtime/export_windows_test.go b/libgo/go/runtime/export_windows_test.go new file mode 100644 index 00000000000..61fcef9c0f6 --- /dev/null +++ b/libgo/go/runtime/export_windows_test.go @@ -0,0 +1,9 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Export guts for testing. + +package runtime + +var TestingWER = &testingWER diff --git a/libgo/go/runtime/extern.go b/libgo/go/runtime/extern.go index 3c3e427a05a..1f6b13eece6 100644 --- a/libgo/go/runtime/extern.go +++ b/libgo/go/runtime/extern.go @@ -19,10 +19,10 @@ A collection is triggered when the ratio of freshly allocated data to live data remaining after the previous collection reaches this percentage. The default is GOGC=100. Setting GOGC=off disables the garbage collector entirely. The runtime/debug package's SetGCPercent function allows changing this -percentage at run time. See http://golang.org/pkg/runtime/debug/#SetGCPercent. +percentage at run time. See https://golang.org/pkg/runtime/debug/#SetGCPercent. -The GODEBUG variable controls debug output from the runtime. GODEBUG value is -a comma-separated list of name=val pairs. Supported names are: +The GODEBUG variable controls debugging variables within the runtime. +It is a comma-separated list of name=val pairs setting these named variables: allocfreetrace: setting allocfreetrace=1 causes every allocation to be profiled and a stack trace printed on each object's allocation and free. @@ -31,18 +31,61 @@ a comma-separated list of name=val pairs. Supported names are: where each object is allocated on a unique page and addresses are never recycled. + gccheckmark: setting gccheckmark=1 enables verification of the + garbage collector's concurrent mark phase by performing a + second mark pass while the world is stopped. If the second + pass finds a reachable object that was not found by concurrent + mark, the garbage collector will panic. + + gcpacertrace: setting gcpacertrace=1 causes the garbage collector to + print information about the internal state of the concurrent pacer. + + gcshrinkstackoff: setting gcshrinkstackoff=1 disables moving goroutines + onto smaller stacks. In this mode, a goroutine's stack can only grow. + + gcstackbarrieroff: setting gcstackbarrieroff=1 disables the use of stack barriers + that allow the garbage collector to avoid repeating a stack scan during the + mark termination phase. + + gcstoptheworld: setting gcstoptheworld=1 disables concurrent garbage collection, + making every garbage collection a stop-the-world event. Setting gcstoptheworld=2 + also disables concurrent sweeping after the garbage collection finishes. + gctrace: setting gctrace=1 causes the garbage collector to emit a single line to standard error at each collection, summarizing the amount of memory collected and the length of the pause. Setting gctrace=2 emits the same summary but also - repeats each collection. - - gcdead: setting gcdead=1 causes the garbage collector to clobber all stack slots - that it thinks are dead. + repeats each collection. The format of this line is subject to change. + Currently, it is: + gc # @#s #%: #+...+# ms clock, #+...+# ms cpu, #->#-># MB, # MB goal, # P + where the fields are as follows: + gc # the GC number, incremented at each GC + @#s time in seconds since program start + #% percentage of time spent in GC since program start + #+...+# wall-clock/CPU times for the phases of the GC + #->#-># MB heap size at GC start, at GC end, and live heap + # MB goal goal heap size + # P number of processors used + The phases are stop-the-world (STW) sweep termination, scan, + synchronize Ps, mark, and STW mark termination. The CPU times + for mark are broken down in to assist time (GC performed in + line with allocation), background GC time, and idle GC time. + If the line ends with "(forced)", this GC was forced by a + runtime.GC() call and all phases are STW. + + memprofilerate: setting memprofilerate=X will update the value of runtime.MemProfileRate. + When set to 0 memory profiling is disabled. Refer to the description of + MemProfileRate for the default value. memprofilerate: setting memprofilerate=X changes the setting for runtime.MemProfileRate. Refer to the description of this variable for how it is used and its default value. + sbrk: setting sbrk=1 replaces the memory allocator and garbage collector + with a trivial allocator that obtains memory from the operating system and + never reclaims any memory. + + scavenge: scavenge=1 enables debugging mode of heap scavenger. + scheddetail: setting schedtrace=X and scheddetail=1 causes the scheduler to emit detailed multiline info every X milliseconds, describing state of the scheduler, processors, threads and goroutines. @@ -70,7 +113,7 @@ core dump. The GOARCH, GOOS, GOPATH, and GOROOT environment variables complete the set of Go environment variables. They influence the building of Go programs -(see http://golang.org/cmd/go and http://golang.org/pkg/go/build). +(see https://golang.org/cmd/go and https://golang.org/pkg/go/build). GOARCH, GOOS, and GOROOT are recorded at compile time and made available by constants or functions in this package, but they do not influence the execution of the run-time system. diff --git a/libgo/go/runtime/gc_test.go b/libgo/go/runtime/gc_test.go index fe9e8390200..262f87d66b0 100644 --- a/libgo/go/runtime/gc_test.go +++ b/libgo/go/runtime/gc_test.go @@ -5,7 +5,8 @@ package runtime_test import ( - // "os" + "os" + "reflect" "runtime" "runtime/debug" "testing" @@ -14,7 +15,6 @@ import ( ) func TestGcSys(t *testing.T) { - /* gccgo does not have a go command if os.Getenv("GOGC") == "off" { t.Skip("skipping test; GOGC=off in environment") } @@ -24,7 +24,6 @@ func TestGcSys(t *testing.T) { if got != want { t.Fatalf("expected %q, but got %q", want, got) } - */ } const testGCSysSource = ` @@ -199,45 +198,166 @@ func TestHugeGCInfo(t *testing.T) { } } -func BenchmarkSetTypeNoPtr1(b *testing.B) { - type NoPtr1 struct { - p uintptr - } - var p *NoPtr1 - for i := 0; i < b.N; i++ { - p = &NoPtr1{} - } - _ = p +func BenchmarkSetTypePtr(b *testing.B) { + benchSetType(b, new(*byte)) } -func BenchmarkSetTypeNoPtr2(b *testing.B) { - type NoPtr2 struct { - p, q uintptr - } - var p *NoPtr2 - for i := 0; i < b.N; i++ { - p = &NoPtr2{} - } - _ = p + +func BenchmarkSetTypePtr8(b *testing.B) { + benchSetType(b, new([8]*byte)) } -func BenchmarkSetTypePtr1(b *testing.B) { - type Ptr1 struct { - p *byte - } - var p *Ptr1 - for i := 0; i < b.N; i++ { - p = &Ptr1{} - } - _ = p + +func BenchmarkSetTypePtr16(b *testing.B) { + benchSetType(b, new([16]*byte)) } -func BenchmarkSetTypePtr2(b *testing.B) { - type Ptr2 struct { - p, q *byte - } - var p *Ptr2 - for i := 0; i < b.N; i++ { - p = &Ptr2{} - } - _ = p + +func BenchmarkSetTypePtr32(b *testing.B) { + benchSetType(b, new([32]*byte)) +} + +func BenchmarkSetTypePtr64(b *testing.B) { + benchSetType(b, new([64]*byte)) +} + +func BenchmarkSetTypePtr126(b *testing.B) { + benchSetType(b, new([126]*byte)) +} + +func BenchmarkSetTypePtr128(b *testing.B) { + benchSetType(b, new([128]*byte)) +} + +func BenchmarkSetTypePtrSlice(b *testing.B) { + benchSetType(b, make([]*byte, 1<<10)) +} + +type Node1 struct { + Value [1]uintptr + Left, Right *byte +} + +func BenchmarkSetTypeNode1(b *testing.B) { + benchSetType(b, new(Node1)) +} + +func BenchmarkSetTypeNode1Slice(b *testing.B) { + benchSetType(b, make([]Node1, 32)) +} + +type Node8 struct { + Value [8]uintptr + Left, Right *byte +} + +func BenchmarkSetTypeNode8(b *testing.B) { + benchSetType(b, new(Node8)) +} + +func BenchmarkSetTypeNode8Slice(b *testing.B) { + benchSetType(b, make([]Node8, 32)) +} + +type Node64 struct { + Value [64]uintptr + Left, Right *byte +} + +func BenchmarkSetTypeNode64(b *testing.B) { + benchSetType(b, new(Node64)) +} + +func BenchmarkSetTypeNode64Slice(b *testing.B) { + benchSetType(b, make([]Node64, 32)) +} + +type Node64Dead struct { + Left, Right *byte + Value [64]uintptr +} + +func BenchmarkSetTypeNode64Dead(b *testing.B) { + benchSetType(b, new(Node64Dead)) +} + +func BenchmarkSetTypeNode64DeadSlice(b *testing.B) { + benchSetType(b, make([]Node64Dead, 32)) +} + +type Node124 struct { + Value [124]uintptr + Left, Right *byte +} + +func BenchmarkSetTypeNode124(b *testing.B) { + benchSetType(b, new(Node124)) +} + +func BenchmarkSetTypeNode124Slice(b *testing.B) { + benchSetType(b, make([]Node124, 32)) +} + +type Node126 struct { + Value [126]uintptr + Left, Right *byte +} + +func BenchmarkSetTypeNode126(b *testing.B) { + benchSetType(b, new(Node126)) +} + +func BenchmarkSetTypeNode126Slice(b *testing.B) { + benchSetType(b, make([]Node126, 32)) +} + +type Node128 struct { + Value [128]uintptr + Left, Right *byte +} + +func BenchmarkSetTypeNode128(b *testing.B) { + benchSetType(b, new(Node128)) +} + +func BenchmarkSetTypeNode128Slice(b *testing.B) { + benchSetType(b, make([]Node128, 32)) +} + +type Node130 struct { + Value [130]uintptr + Left, Right *byte +} + +func BenchmarkSetTypeNode130(b *testing.B) { + benchSetType(b, new(Node130)) +} + +func BenchmarkSetTypeNode130Slice(b *testing.B) { + benchSetType(b, make([]Node130, 32)) +} + +type Node1024 struct { + Value [1024]uintptr + Left, Right *byte +} + +func BenchmarkSetTypeNode1024(b *testing.B) { + benchSetType(b, new(Node1024)) +} + +func BenchmarkSetTypeNode1024Slice(b *testing.B) { + benchSetType(b, make([]Node1024, 32)) +} + +func benchSetType(b *testing.B, x interface{}) { + v := reflect.ValueOf(x) + t := v.Type() + switch t.Kind() { + case reflect.Ptr: + b.SetBytes(int64(t.Elem().Size())) + case reflect.Slice: + b.SetBytes(int64(t.Elem().Size()) * int64(v.Len())) + } + b.ResetTimer() + //runtime.BenchSetType(b.N, x) } func BenchmarkAllocation(b *testing.B) { @@ -292,3 +412,63 @@ func TestPrintGC(t *testing.T) { } close(done) } + +/* + +// The implicit y, ok := x.(error) for the case error +// in testTypeSwitch used to not initialize the result y +// before passing &y to assertE2I2GC. +// Catch this by making assertE2I2 call runtime.GC, +// which will force a stack scan and failure if there are +// bad pointers, and then fill the stack with bad pointers +// and run the type switch. +func TestAssertE2I2Liveness(t *testing.T) { + // Note that this flag is defined in export_test.go + // and is not available to ordinary imports of runtime. + *runtime.TestingAssertE2I2GC = true + defer func() { + *runtime.TestingAssertE2I2GC = false + }() + + poisonStack() + testTypeSwitch(io.EOF) + poisonStack() + testAssert(io.EOF) + poisonStack() + testAssertVar(io.EOF) +} + +func poisonStack() uintptr { + var x [1000]uintptr + for i := range x { + x[i] = 0xff + } + return x[123] +} + +func testTypeSwitch(x interface{}) error { + switch y := x.(type) { + case nil: + // ok + case error: + return y + } + return nil +} + +func testAssert(x interface{}) error { + if y, ok := x.(error); ok { + return y + } + return nil +} + +func testAssertVar(x interface{}) error { + var y, ok = x.(error) + if ok { + return y + } + return nil +} + +*/ diff --git a/libgo/go/runtime/gcinfo_test.go b/libgo/go/runtime/gcinfo_test.go index 00449929c95..7e345e55a4c 100644 --- a/libgo/go/runtime/gcinfo_test.go +++ b/libgo/go/runtime/gcinfo_test.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// +build ignore + package runtime_test import ( @@ -10,25 +12,16 @@ import ( "testing" ) +const ( + typeScalar = 0 + typePointer = 1 +) + // TestGCInfo tests that various objects in heap, data and bss receive correct GC pointer type info. func TestGCInfo(t *testing.T) { t.Skip("skipping on gccgo for now") - verifyGCInfo(t, "bss ScalarPtr", &bssScalarPtr, nonStackInfo(infoScalarPtr)) - verifyGCInfo(t, "bss PtrScalar", &bssPtrScalar, nonStackInfo(infoPtrScalar)) - verifyGCInfo(t, "bss BigStruct", &bssBigStruct, nonStackInfo(infoBigStruct())) - verifyGCInfo(t, "bss string", &bssString, nonStackInfo(infoString)) - verifyGCInfo(t, "bss slice", &bssSlice, nonStackInfo(infoSlice)) - verifyGCInfo(t, "bss eface", &bssEface, nonStackInfo(infoEface)) - verifyGCInfo(t, "bss iface", &bssIface, nonStackInfo(infoIface)) - - verifyGCInfo(t, "data ScalarPtr", &dataScalarPtr, nonStackInfo(infoScalarPtr)) - verifyGCInfo(t, "data PtrScalar", &dataPtrScalar, nonStackInfo(infoPtrScalar)) - verifyGCInfo(t, "data BigStruct", &dataBigStruct, nonStackInfo(infoBigStruct())) - verifyGCInfo(t, "data string", &dataString, nonStackInfo(infoString)) - verifyGCInfo(t, "data slice", &dataSlice, nonStackInfo(infoSlice)) - verifyGCInfo(t, "data eface", &dataEface, nonStackInfo(infoEface)) - verifyGCInfo(t, "data iface", &dataIface, nonStackInfo(infoIface)) + verifyGCInfo(t, "stack Ptr", new(Ptr), infoPtr) verifyGCInfo(t, "stack ScalarPtr", new(ScalarPtr), infoScalarPtr) verifyGCInfo(t, "stack PtrScalar", new(PtrScalar), infoPtrScalar) verifyGCInfo(t, "stack BigStruct", new(BigStruct), infoBigStruct()) @@ -38,40 +31,43 @@ func TestGCInfo(t *testing.T) { verifyGCInfo(t, "stack iface", new(Iface), infoIface) for i := 0; i < 10; i++ { - verifyGCInfo(t, "heap ScalarPtr", escape(new(ScalarPtr)), nonStackInfo(infoScalarPtr)) - verifyGCInfo(t, "heap PtrScalar", escape(new(PtrScalar)), nonStackInfo(infoPtrScalar)) - verifyGCInfo(t, "heap BigStruct", escape(new(BigStruct)), nonStackInfo(infoBigStruct())) - verifyGCInfo(t, "heap string", escape(new(string)), nonStackInfo(infoString)) - verifyGCInfo(t, "heap eface", escape(new(interface{})), nonStackInfo(infoEface)) - verifyGCInfo(t, "heap iface", escape(new(Iface)), nonStackInfo(infoIface)) + verifyGCInfo(t, "heap Ptr", escape(new(Ptr)), trimDead(padDead(infoPtr))) + verifyGCInfo(t, "heap PtrSlice", escape(&make([]*byte, 10)[0]), trimDead(infoPtr10)) + verifyGCInfo(t, "heap ScalarPtr", escape(new(ScalarPtr)), trimDead(infoScalarPtr)) + verifyGCInfo(t, "heap ScalarPtrSlice", escape(&make([]ScalarPtr, 4)[0]), trimDead(infoScalarPtr4)) + verifyGCInfo(t, "heap PtrScalar", escape(new(PtrScalar)), trimDead(infoPtrScalar)) + verifyGCInfo(t, "heap BigStruct", escape(new(BigStruct)), trimDead(infoBigStruct())) + verifyGCInfo(t, "heap string", escape(new(string)), trimDead(infoString)) + verifyGCInfo(t, "heap eface", escape(new(interface{})), trimDead(infoEface)) + verifyGCInfo(t, "heap iface", escape(new(Iface)), trimDead(infoIface)) } - } func verifyGCInfo(t *testing.T, name string, p interface{}, mask0 []byte) { - mask := /* runtime.GCMask(p) */ []byte(nil) - if len(mask) > len(mask0) { - mask0 = append(mask0, BitsDead) - mask = mask[:len(mask0)] - } + mask := runtime.GCMask(p) if bytes.Compare(mask, mask0) != 0 { t.Errorf("bad GC program for %v:\nwant %+v\ngot %+v", name, mask0, mask) return } } -func nonStackInfo(mask []byte) []byte { - // BitsDead is replaced with BitsScalar everywhere except stacks. - mask1 := make([]byte, len(mask)) - mw := false - for i, v := range mask { - if !mw && v == BitsDead { - v = BitsScalar - } - mw = !mw && v == BitsMultiWord - mask1[i] = v +func padDead(mask []byte) []byte { + // Because the dead bit isn't encoded until the third word, + // and because on 32-bit systems a one-word allocation + // uses a two-word block, the pointer info for a one-word + // object needs to be expanded to include an extra scalar + // on 32-bit systems to match the heap bitmap. + if runtime.PtrSize == 4 && len(mask) == 1 { + return []byte{mask[0], 0} } - return mask1 + return mask +} + +func trimDead(mask []byte) []byte { + for len(mask) > 2 && mask[len(mask)-1] == typeScalar { + mask = mask[:len(mask)-1] + } + return mask } var gcinfoSink interface{} @@ -81,19 +77,13 @@ func escape(p interface{}) interface{} { return p } -const ( - BitsDead = iota - BitsScalar - BitsPointer - BitsMultiWord -) +var infoPtr = []byte{typePointer} -const ( - BitsString = iota // unused - BitsSlice // unused - BitsIface - BitsEface -) +type Ptr struct { + *byte +} + +var infoPtr10 = []byte{typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer} type ScalarPtr struct { q int @@ -104,7 +94,9 @@ type ScalarPtr struct { y *int } -var infoScalarPtr = []byte{BitsScalar, BitsPointer, BitsScalar, BitsPointer, BitsScalar, BitsPointer} +var infoScalarPtr = []byte{typeScalar, typePointer, typeScalar, typePointer, typeScalar, typePointer} + +var infoScalarPtr4 = append(append(append(append([]byte(nil), infoScalarPtr...), infoScalarPtr...), infoScalarPtr...), infoScalarPtr...) type PtrScalar struct { q *int @@ -115,7 +107,7 @@ type PtrScalar struct { y int } -var infoPtrScalar = []byte{BitsPointer, BitsScalar, BitsPointer, BitsScalar, BitsPointer, BitsScalar} +var infoPtrScalar = []byte{typePointer, typeScalar, typePointer, typeScalar, typePointer, typeScalar} type BigStruct struct { q *int @@ -132,27 +124,27 @@ func infoBigStruct() []byte { switch runtime.GOARCH { case "386", "arm": return []byte{ - BitsPointer, // q *int - BitsScalar, BitsScalar, BitsScalar, BitsScalar, BitsScalar, // w byte; e [17]byte - BitsPointer, BitsDead, BitsDead, // r []byte - BitsScalar, BitsScalar, BitsScalar, BitsScalar, // t int; y uint16; u uint64 - BitsPointer, BitsDead, // i string + typePointer, // q *int + typeScalar, typeScalar, typeScalar, typeScalar, typeScalar, // w byte; e [17]byte + typePointer, typeScalar, typeScalar, // r []byte + typeScalar, typeScalar, typeScalar, typeScalar, // t int; y uint16; u uint64 + typePointer, typeScalar, // i string } - case "amd64": + case "arm64", "amd64", "ppc64", "ppc64le": return []byte{ - BitsPointer, // q *int - BitsScalar, BitsScalar, BitsScalar, // w byte; e [17]byte - BitsPointer, BitsDead, BitsDead, // r []byte - BitsScalar, BitsScalar, BitsScalar, // t int; y uint16; u uint64 - BitsPointer, BitsDead, // i string + typePointer, // q *int + typeScalar, typeScalar, typeScalar, // w byte; e [17]byte + typePointer, typeScalar, typeScalar, // r []byte + typeScalar, typeScalar, typeScalar, // t int; y uint16; u uint64 + typePointer, typeScalar, // i string } case "amd64p32": return []byte{ - BitsPointer, // q *int - BitsScalar, BitsScalar, BitsScalar, BitsScalar, BitsScalar, // w byte; e [17]byte - BitsPointer, BitsDead, BitsDead, // r []byte - BitsScalar, BitsScalar, BitsDead, BitsScalar, BitsScalar, // t int; y uint16; u uint64 - BitsPointer, BitsDead, // i string + typePointer, // q *int + typeScalar, typeScalar, typeScalar, typeScalar, typeScalar, // w byte; e [17]byte + typePointer, typeScalar, typeScalar, // r []byte + typeScalar, typeScalar, typeScalar, typeScalar, typeScalar, // t int; y uint16; u uint64 + typePointer, typeScalar, // i string } default: panic("unknown arch") @@ -170,6 +162,7 @@ func (IfaceImpl) f() { var ( // BSS + bssPtr Ptr bssScalarPtr ScalarPtr bssPtrScalar PtrScalar bssBigStruct BigStruct @@ -179,6 +172,7 @@ var ( bssIface Iface // DATA + dataPtr = Ptr{new(byte)} dataScalarPtr = ScalarPtr{q: 1} dataPtrScalar = PtrScalar{w: 1} dataBigStruct = BigStruct{w: 1} @@ -187,8 +181,8 @@ var ( dataEface interface{} = 42 dataIface Iface = IfaceImpl(42) - infoString = []byte{BitsPointer, BitsDead} - infoSlice = []byte{BitsPointer, BitsDead, BitsDead} - infoEface = []byte{BitsMultiWord, BitsEface} - infoIface = []byte{BitsMultiWord, BitsIface} + infoString = []byte{typePointer, typeScalar} + infoSlice = []byte{typePointer, typeScalar, typeScalar} + infoEface = []byte{typePointer, typePointer} + infoIface = []byte{typePointer, typePointer} ) diff --git a/libgo/go/runtime/hashmap.go b/libgo/go/runtime/hashmap.go deleted file mode 100644 index 791af8cf36a..00000000000 --- a/libgo/go/runtime/hashmap.go +++ /dev/null @@ -1,960 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -// This file contains the implementation of Go's map type. -// -// A map is just a hash table. The data is arranged -// into an array of buckets. Each bucket contains up to -// 8 key/value pairs. The low-order bits of the hash are -// used to select a bucket. Each bucket contains a few -// high-order bits of each hash to distinguish the entries -// within a single bucket. -// -// If more than 8 keys hash to a bucket, we chain on -// extra buckets. -// -// When the hashtable grows, we allocate a new array -// of buckets twice as big. Buckets are incrementally -// copied from the old bucket array to the new bucket array. -// -// Map iterators walk through the array of buckets and -// return the keys in walk order (bucket #, then overflow -// chain order, then bucket index). To maintain iteration -// semantics, we never move keys within their bucket (if -// we did, keys might be returned 0 or 2 times). When -// growing the table, iterators remain iterating through the -// old table and must check the new table if the bucket -// they are iterating through has been moved ("evacuated") -// to the new table. - -// Picking loadFactor: too large and we have lots of overflow -// buckets, too small and we waste a lot of space. I wrote -// a simple program to check some stats for different loads: -// (64-bit, 8 byte keys and values) -// loadFactor %overflow bytes/entry hitprobe missprobe -// 4.00 2.13 20.77 3.00 4.00 -// 4.50 4.05 17.30 3.25 4.50 -// 5.00 6.85 14.77 3.50 5.00 -// 5.50 10.55 12.94 3.75 5.50 -// 6.00 15.27 11.67 4.00 6.00 -// 6.50 20.90 10.79 4.25 6.50 -// 7.00 27.14 10.15 4.50 7.00 -// 7.50 34.03 9.73 4.75 7.50 -// 8.00 41.10 9.40 5.00 8.00 -// -// %overflow = percentage of buckets which have an overflow bucket -// bytes/entry = overhead bytes used per key/value pair -// hitprobe = # of entries to check when looking up a present key -// missprobe = # of entries to check when looking up an absent key -// -// Keep in mind this data is for maximally loaded tables, i.e. just -// before the table grows. Typical tables will be somewhat less loaded. - -import ( - "unsafe" -) - -const ( - // Maximum number of key/value pairs a bucket can hold. - bucketCntBits = 3 - bucketCnt = 1 << bucketCntBits - - // Maximum average load of a bucket that triggers growth. - loadFactor = 6.5 - - // Maximum key or value size to keep inline (instead of mallocing per element). - // Must fit in a uint8. - // Fast versions cannot handle big values - the cutoff size for - // fast versions in ../../cmd/gc/walk.c must be at most this value. - maxKeySize = 128 - maxValueSize = 128 - - // data offset should be the size of the bmap struct, but needs to be - // aligned correctly. For amd64p32 this means 64-bit alignment - // even though pointers are 32 bit. - dataOffset = unsafe.Offsetof(struct { - b bmap - v int64 - }{}.v) - - // Possible tophash values. We reserve a few possibilities for special marks. - // Each bucket (including its overflow buckets, if any) will have either all or none of its - // entries in the evacuated* states (except during the evacuate() method, which only happens - // during map writes and thus no one else can observe the map during that time). - empty = 0 // cell is empty - evacuatedEmpty = 1 // cell is empty, bucket is evacuated. - evacuatedX = 2 // key/value is valid. Entry has been evacuated to first half of larger table. - evacuatedY = 3 // same as above, but evacuated to second half of larger table. - minTopHash = 4 // minimum tophash for a normal filled cell. - - // flags - iterator = 1 // there may be an iterator using buckets - oldIterator = 2 // there may be an iterator using oldbuckets - - // sentinel bucket ID for iterator checks - noCheck = 1<<(8*ptrSize) - 1 - - // trigger a garbage collection at every alloc called from this code - checkgc = false -) - -// A header for a Go map. -type hmap struct { - // Note: the format of the Hmap is encoded in ../../cmd/gc/reflect.c and - // ../reflect/type.go. Don't change this structure without also changing that code! - count int // # live cells == size of map. Must be first (used by len() builtin) - flags uint32 - hash0 uint32 // hash seed - B uint8 // log_2 of # of buckets (can hold up to loadFactor * 2^B items) - - buckets unsafe.Pointer // array of 2^B Buckets. may be nil if count==0. - oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing - nevacuate uintptr // progress counter for evacuation (buckets less than this have been evacuated) -} - -// A bucket for a Go map. -type bmap struct { - tophash [bucketCnt]uint8 - // Followed by bucketCnt keys and then bucketCnt values. - // NOTE: packing all the keys together and then all the values together makes the - // code a bit more complicated than alternating key/value/key/value/... but it allows - // us to eliminate padding which would be needed for, e.g., map[int64]int8. - // Followed by an overflow pointer. -} - -// A hash iteration structure. -// If you modify hiter, also change cmd/gc/reflect.c to indicate -// the layout of this structure. -type hiter struct { - key unsafe.Pointer // Must be in first position. Write nil to indicate iteration end (see cmd/gc/range.c). - value unsafe.Pointer // Must be in second position (see cmd/gc/range.c). - t *maptype - h *hmap - buckets unsafe.Pointer // bucket ptr at hash_iter initialization time - bptr *bmap // current bucket - startBucket uintptr // bucket iteration started at - offset uint8 // intra-bucket offset to start from during iteration (should be big enough to hold bucketCnt-1) - wrapped bool // already wrapped around from end of bucket array to beginning - B uint8 - i uint8 - bucket uintptr - checkBucket uintptr -} - -func evacuated(b *bmap) bool { - h := b.tophash[0] - return h > empty && h < minTopHash -} - -func (b *bmap) overflow(t *maptype) *bmap { - return *(**bmap)(add(unsafe.Pointer(b), uintptr(t.bucketsize)-regSize)) -} -func (b *bmap) setoverflow(t *maptype, ovf *bmap) { - *(**bmap)(add(unsafe.Pointer(b), uintptr(t.bucketsize)-regSize)) = ovf -} - -func makemap(t *maptype, hint int64) *hmap { - if sz := unsafe.Sizeof(hmap{}); sz > 48 || sz != uintptr(t.hmap.size) { - gothrow("bad hmap size") - } - - if hint < 0 || int64(int32(hint)) != hint { - panic("makemap: size out of range") - // TODO: make hint an int, then none of this nonsense - } - - if !ismapkey(t.key) { - gothrow("runtime.makemap: unsupported map key type") - } - - // check compiler's and reflect's math - if t.key.size > maxKeySize && (!t.indirectkey || t.keysize != uint8(ptrSize)) || - t.key.size <= maxKeySize && (t.indirectkey || t.keysize != uint8(t.key.size)) { - gothrow("key size wrong") - } - if t.elem.size > maxValueSize && (!t.indirectvalue || t.valuesize != uint8(ptrSize)) || - t.elem.size <= maxValueSize && (t.indirectvalue || t.valuesize != uint8(t.elem.size)) { - gothrow("value size wrong") - } - - // invariants we depend on. We should probably check these at compile time - // somewhere, but for now we'll do it here. - if t.key.align > bucketCnt { - gothrow("key align too big") - } - if t.elem.align > bucketCnt { - gothrow("value align too big") - } - if uintptr(t.key.size)%uintptr(t.key.align) != 0 { - gothrow("key size not a multiple of key align") - } - if uintptr(t.elem.size)%uintptr(t.elem.align) != 0 { - gothrow("value size not a multiple of value align") - } - if bucketCnt < 8 { - gothrow("bucketsize too small for proper alignment") - } - if dataOffset%uintptr(t.key.align) != 0 { - gothrow("need padding in bucket (key)") - } - if dataOffset%uintptr(t.elem.align) != 0 { - gothrow("need padding in bucket (value)") - } - - // find size parameter which will hold the requested # of elements - B := uint8(0) - for ; hint > bucketCnt && float32(hint) > loadFactor*float32(uintptr(1)<>1))*uintptr(t.bucketsize))) - if !evacuated(oldb) { - b = oldb - } - } - top := uint8(hash >> (ptrSize*8 - 8)) - if top < minTopHash { - top += minTopHash - } - for { - for i := uintptr(0); i < bucketCnt; i++ { - if b.tophash[i] != top { - continue - } - k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.keysize)) - if t.indirectkey { - k = *((*unsafe.Pointer)(k)) - } - if alg.equal(key, k, uintptr(t.key.size)) { - v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize)) - if t.indirectvalue { - v = *((*unsafe.Pointer)(v)) - } - return v - } - } - b = b.overflow(t) - if b == nil { - return unsafe.Pointer(t.elem.zero) - } - } -} - -func mapaccess2(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, bool) { - if raceenabled && h != nil { - callerpc := getcallerpc(unsafe.Pointer(&t)) - pc := funcPC(mapaccess2) - racereadpc(unsafe.Pointer(h), callerpc, pc) - raceReadObjectPC(t.key, key, callerpc, pc) - } - if h == nil || h.count == 0 { - return unsafe.Pointer(t.elem.zero), false - } - alg := goalg(t.key.alg) - hash := alg.hash(key, uintptr(t.key.size), uintptr(h.hash0)) - m := uintptr(1)<>1))*uintptr(t.bucketsize))) - if !evacuated(oldb) { - b = oldb - } - } - top := uint8(hash >> (ptrSize*8 - 8)) - if top < minTopHash { - top += minTopHash - } - for { - for i := uintptr(0); i < bucketCnt; i++ { - if b.tophash[i] != top { - continue - } - k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.keysize)) - if t.indirectkey { - k = *((*unsafe.Pointer)(k)) - } - if alg.equal(key, k, uintptr(t.key.size)) { - v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize)) - if t.indirectvalue { - v = *((*unsafe.Pointer)(v)) - } - return v, true - } - } - b = b.overflow(t) - if b == nil { - return unsafe.Pointer(t.elem.zero), false - } - } -} - -// returns both key and value. Used by map iterator -func mapaccessK(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, unsafe.Pointer) { - if h == nil || h.count == 0 { - return nil, nil - } - alg := goalg(t.key.alg) - hash := alg.hash(key, uintptr(t.key.size), uintptr(h.hash0)) - m := uintptr(1)<>1))*uintptr(t.bucketsize))) - if !evacuated(oldb) { - b = oldb - } - } - top := uint8(hash >> (ptrSize*8 - 8)) - if top < minTopHash { - top += minTopHash - } - for { - for i := uintptr(0); i < bucketCnt; i++ { - if b.tophash[i] != top { - continue - } - k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.keysize)) - if t.indirectkey { - k = *((*unsafe.Pointer)(k)) - } - if alg.equal(key, k, uintptr(t.key.size)) { - v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize)) - if t.indirectvalue { - v = *((*unsafe.Pointer)(v)) - } - return k, v - } - } - b = b.overflow(t) - if b == nil { - return nil, nil - } - } -} - -func mapassign1(t *maptype, h *hmap, key unsafe.Pointer, val unsafe.Pointer) { - if h == nil { - panic("assignment to entry in nil map") - } - if raceenabled { - callerpc := getcallerpc(unsafe.Pointer(&t)) - pc := funcPC(mapassign1) - racewritepc(unsafe.Pointer(h), callerpc, pc) - raceReadObjectPC(t.key, key, callerpc, pc) - raceReadObjectPC(t.elem, val, callerpc, pc) - } - - alg := goalg(t.key.alg) - hash := alg.hash(key, uintptr(t.key.size), uintptr(h.hash0)) - - if h.buckets == nil { - if checkgc { - memstats.next_gc = memstats.heap_alloc - } - h.buckets = newarray(t.bucket, 1) - } - -again: - bucket := hash & (uintptr(1)<> (ptrSize*8 - 8)) - if top < minTopHash { - top += minTopHash - } - - var inserti *uint8 - var insertk unsafe.Pointer - var insertv unsafe.Pointer - for { - for i := uintptr(0); i < bucketCnt; i++ { - if b.tophash[i] != top { - if b.tophash[i] == empty && inserti == nil { - inserti = &b.tophash[i] - insertk = add(unsafe.Pointer(b), dataOffset+i*uintptr(t.keysize)) - insertv = add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize)) - } - continue - } - k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.keysize)) - k2 := k - if t.indirectkey { - k2 = *((*unsafe.Pointer)(k2)) - } - if !alg.equal(key, k2, uintptr(t.key.size)) { - continue - } - // already have a mapping for key. Update it. - memmove(k2, key, uintptr(t.key.size)) - v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize)) - v2 := v - if t.indirectvalue { - v2 = *((*unsafe.Pointer)(v2)) - } - memmove(v2, val, uintptr(t.elem.size)) - return - } - ovf := b.overflow(t) - if ovf == nil { - break - } - b = ovf - } - - // did not find mapping for key. Allocate new cell & add entry. - if float32(h.count) >= loadFactor*float32((uintptr(1)<= bucketCnt { - hashGrow(t, h) - goto again // Growing the table invalidates everything, so try again - } - - if inserti == nil { - // all current buckets are full, allocate a new one. - if checkgc { - memstats.next_gc = memstats.heap_alloc - } - newb := (*bmap)(newobject(t.bucket)) - b.setoverflow(t, newb) - inserti = &newb.tophash[0] - insertk = add(unsafe.Pointer(newb), dataOffset) - insertv = add(insertk, bucketCnt*uintptr(t.keysize)) - } - - // store new key/value at insert position - if t.indirectkey { - if checkgc { - memstats.next_gc = memstats.heap_alloc - } - kmem := newobject(t.key) - *(*unsafe.Pointer)(insertk) = kmem - insertk = kmem - } - if t.indirectvalue { - if checkgc { - memstats.next_gc = memstats.heap_alloc - } - vmem := newobject(t.elem) - *(*unsafe.Pointer)(insertv) = vmem - insertv = vmem - } - memmove(insertk, key, uintptr(t.key.size)) - memmove(insertv, val, uintptr(t.elem.size)) - *inserti = top - h.count++ -} - -func mapdelete(t *maptype, h *hmap, key unsafe.Pointer) { - if raceenabled && h != nil { - callerpc := getcallerpc(unsafe.Pointer(&t)) - pc := funcPC(mapdelete) - racewritepc(unsafe.Pointer(h), callerpc, pc) - raceReadObjectPC(t.key, key, callerpc, pc) - } - if h == nil || h.count == 0 { - return - } - alg := goalg(t.key.alg) - hash := alg.hash(key, uintptr(t.key.size), uintptr(h.hash0)) - bucket := hash & (uintptr(1)<> (ptrSize*8 - 8)) - if top < minTopHash { - top += minTopHash - } - for { - for i := uintptr(0); i < bucketCnt; i++ { - if b.tophash[i] != top { - continue - } - k := add(unsafe.Pointer(b), dataOffset+i*uintptr(t.keysize)) - k2 := k - if t.indirectkey { - k2 = *((*unsafe.Pointer)(k2)) - } - if !alg.equal(key, k2, uintptr(t.key.size)) { - continue - } - memclr(k, uintptr(t.keysize)) - v := unsafe.Pointer(uintptr(unsafe.Pointer(b)) + dataOffset + bucketCnt*uintptr(t.keysize) + i*uintptr(t.valuesize)) - memclr(v, uintptr(t.valuesize)) - b.tophash[i] = empty - h.count-- - return - } - b = b.overflow(t) - if b == nil { - return - } - } -} - -func mapiterinit(t *maptype, h *hmap, it *hiter) { - // Clear pointer fields so garbage collector does not complain. - it.key = nil - it.value = nil - it.t = nil - it.h = nil - it.buckets = nil - it.bptr = nil - - if raceenabled && h != nil { - callerpc := getcallerpc(unsafe.Pointer(&t)) - racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapiterinit)) - } - - if h == nil || h.count == 0 { - it.key = nil - it.value = nil - return - } - - if unsafe.Sizeof(hiter{})/ptrSize != 10 { - gothrow("hash_iter size incorrect") // see ../../cmd/gc/reflect.c - } - it.t = t - it.h = h - - // grab snapshot of bucket state - it.B = h.B - it.buckets = h.buckets - - // decide where to start - r := uintptr(fastrand1()) - if h.B > 31-bucketCntBits { - r += uintptr(fastrand1()) << 31 - } - it.startBucket = r & (uintptr(1)<> h.B & (bucketCnt - 1)) - - // iterator state - it.bucket = it.startBucket - it.wrapped = false - it.bptr = nil - - // Remember we have an iterator. - // Can run concurrently with another hash_iter_init(). - for { - old := h.flags - if old == old|iterator|oldIterator { - break - } - if cas(&h.flags, old, old|iterator|oldIterator) { - break - } - } - - mapiternext(it) -} - -func mapiternext(it *hiter) { - h := it.h - if raceenabled { - callerpc := getcallerpc(unsafe.Pointer(&it)) - racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapiternext)) - } - t := it.t - bucket := it.bucket - b := it.bptr - i := it.i - checkBucket := it.checkBucket - alg := goalg(t.key.alg) - -next: - if b == nil { - if bucket == it.startBucket && it.wrapped { - // end of iteration - it.key = nil - it.value = nil - return - } - if h.oldbuckets != nil && it.B == h.B { - // Iterator was started in the middle of a grow, and the grow isn't done yet. - // If the bucket we're looking at hasn't been filled in yet (i.e. the old - // bucket hasn't been evacuated) then we need to iterate through the old - // bucket and only return the ones that will be migrated to this bucket. - oldbucket := bucket & (uintptr(1)<<(it.B-1) - 1) - b = (*bmap)(add(h.oldbuckets, oldbucket*uintptr(t.bucketsize))) - if !evacuated(b) { - checkBucket = bucket - } else { - b = (*bmap)(add(it.buckets, bucket*uintptr(t.bucketsize))) - checkBucket = noCheck - } - } else { - b = (*bmap)(add(it.buckets, bucket*uintptr(t.bucketsize))) - checkBucket = noCheck - } - bucket++ - if bucket == uintptr(1)<>(it.B-1) != uintptr(b.tophash[offi]&1) { - continue - } - } - } - if b.tophash[offi] != evacuatedX && b.tophash[offi] != evacuatedY { - // this is the golden data, we can return it. - if t.indirectkey { - k = *((*unsafe.Pointer)(k)) - } - it.key = k - if t.indirectvalue { - v = *((*unsafe.Pointer)(v)) - } - it.value = v - } else { - // The hash table has grown since the iterator was started. - // The golden data for this key is now somewhere else. - k2 := k - if t.indirectkey { - k2 = *((*unsafe.Pointer)(k2)) - } - if alg.equal(k2, k2, uintptr(t.key.size)) { - // Check the current hash table for the data. - // This code handles the case where the key - // has been deleted, updated, or deleted and reinserted. - // NOTE: we need to regrab the key as it has potentially been - // updated to an equal() but not identical key (e.g. +0.0 vs -0.0). - rk, rv := mapaccessK(t, h, k2) - if rk == nil { - continue // key has been deleted - } - it.key = rk - it.value = rv - } else { - // if key!=key then the entry can't be deleted or - // updated, so we can just return it. That's lucky for - // us because when key!=key we can't look it up - // successfully in the current table. - it.key = k2 - if t.indirectvalue { - v = *((*unsafe.Pointer)(v)) - } - it.value = v - } - } - it.bucket = bucket - it.bptr = b - it.i = i + 1 - it.checkBucket = checkBucket - return - } - } - b = b.overflow(t) - i = 0 - goto next -} - -func hashGrow(t *maptype, h *hmap) { - if h.oldbuckets != nil { - gothrow("evacuation not done in time") - } - oldbuckets := h.buckets - if checkgc { - memstats.next_gc = memstats.heap_alloc - } - newbuckets := newarray(t.bucket, uintptr(1)<<(h.B+1)) - flags := h.flags &^ (iterator | oldIterator) - if h.flags&iterator != 0 { - flags |= oldIterator - } - // commit the grow (atomic wrt gc) - h.B++ - h.flags = flags - h.oldbuckets = oldbuckets - h.buckets = newbuckets - h.nevacuate = 0 - - // the actual copying of the hash table data is done incrementally - // by growWork() and evacuate(). -} - -func growWork(t *maptype, h *hmap, bucket uintptr) { - noldbuckets := uintptr(1) << (h.B - 1) - - // make sure we evacuate the oldbucket corresponding - // to the bucket we're about to use - evacuate(t, h, bucket&(noldbuckets-1)) - - // evacuate one more oldbucket to make progress on growing - if h.oldbuckets != nil { - evacuate(t, h, h.nevacuate) - } -} - -func evacuate(t *maptype, h *hmap, oldbucket uintptr) { - b := (*bmap)(add(h.oldbuckets, oldbucket*uintptr(t.bucketsize))) - newbit := uintptr(1) << (h.B - 1) - alg := goalg(t.key.alg) - if !evacuated(b) { - // TODO: reuse overflow buckets instead of using new ones, if there - // is no iterator using the old buckets. (If !oldIterator.) - - x := (*bmap)(add(h.buckets, oldbucket*uintptr(t.bucketsize))) - y := (*bmap)(add(h.buckets, (oldbucket+newbit)*uintptr(t.bucketsize))) - xi := 0 - yi := 0 - xk := add(unsafe.Pointer(x), dataOffset) - yk := add(unsafe.Pointer(y), dataOffset) - xv := add(xk, bucketCnt*uintptr(t.keysize)) - yv := add(yk, bucketCnt*uintptr(t.keysize)) - for ; b != nil; b = b.overflow(t) { - k := add(unsafe.Pointer(b), dataOffset) - v := add(k, bucketCnt*uintptr(t.keysize)) - for i := 0; i < bucketCnt; i, k, v = i+1, add(k, uintptr(t.keysize)), add(v, uintptr(t.valuesize)) { - top := b.tophash[i] - if top == empty { - b.tophash[i] = evacuatedEmpty - continue - } - if top < minTopHash { - gothrow("bad map state") - } - k2 := k - if t.indirectkey { - k2 = *((*unsafe.Pointer)(k2)) - } - // Compute hash to make our evacuation decision (whether we need - // to send this key/value to bucket x or bucket y). - hash := alg.hash(k2, uintptr(t.key.size), uintptr(h.hash0)) - if h.flags&iterator != 0 { - if !alg.equal(k2, k2, uintptr(t.key.size)) { - // If key != key (NaNs), then the hash could be (and probably - // will be) entirely different from the old hash. Moreover, - // it isn't reproducible. Reproducibility is required in the - // presence of iterators, as our evacuation decision must - // match whatever decision the iterator made. - // Fortunately, we have the freedom to send these keys either - // way. Also, tophash is meaningless for these kinds of keys. - // We let the low bit of tophash drive the evacuation decision. - // We recompute a new random tophash for the next level so - // these keys will get evenly distributed across all buckets - // after multiple grows. - if (top & 1) != 0 { - hash |= newbit - } else { - hash &^= newbit - } - top = uint8(hash >> (ptrSize*8 - 8)) - if top < minTopHash { - top += minTopHash - } - } - } - if (hash & newbit) == 0 { - b.tophash[i] = evacuatedX - if xi == bucketCnt { - if checkgc { - memstats.next_gc = memstats.heap_alloc - } - newx := (*bmap)(newobject(t.bucket)) - x.setoverflow(t, newx) - x = newx - xi = 0 - xk = add(unsafe.Pointer(x), dataOffset) - xv = add(xk, bucketCnt*uintptr(t.keysize)) - } - x.tophash[xi] = top - if t.indirectkey { - *(*unsafe.Pointer)(xk) = k2 // copy pointer - } else { - memmove(xk, k, uintptr(t.key.size)) // copy value - } - if t.indirectvalue { - *(*unsafe.Pointer)(xv) = *(*unsafe.Pointer)(v) - } else { - memmove(xv, v, uintptr(t.elem.size)) - } - xi++ - xk = add(xk, uintptr(t.keysize)) - xv = add(xv, uintptr(t.valuesize)) - } else { - b.tophash[i] = evacuatedY - if yi == bucketCnt { - if checkgc { - memstats.next_gc = memstats.heap_alloc - } - newy := (*bmap)(newobject(t.bucket)) - y.setoverflow(t, newy) - y = newy - yi = 0 - yk = add(unsafe.Pointer(y), dataOffset) - yv = add(yk, bucketCnt*uintptr(t.keysize)) - } - y.tophash[yi] = top - if t.indirectkey { - *(*unsafe.Pointer)(yk) = k2 - } else { - memmove(yk, k, uintptr(t.key.size)) - } - if t.indirectvalue { - *(*unsafe.Pointer)(yv) = *(*unsafe.Pointer)(v) - } else { - memmove(yv, v, uintptr(t.elem.size)) - } - yi++ - yk = add(yk, uintptr(t.keysize)) - yv = add(yv, uintptr(t.valuesize)) - } - } - } - // Unlink the overflow buckets & clear key/value to help GC. - if h.flags&oldIterator == 0 { - b = (*bmap)(add(h.oldbuckets, oldbucket*uintptr(t.bucketsize))) - memclr(add(unsafe.Pointer(b), dataOffset), uintptr(t.bucketsize)-dataOffset) - } - } - - // Advance evacuation mark - if oldbucket == h.nevacuate { - h.nevacuate = oldbucket + 1 - if oldbucket+1 == newbit { // newbit == # of oldbuckets - // Growing is all done. Free old main bucket array. - h.oldbuckets = nil - } - } -} - -func ismapkey(t *_type) bool { - return goalg(t.alg).hash != nil -} - -// Reflect stubs. Called from ../reflect/asm_*.s - -func reflect_makemap(t *maptype) *hmap { - return makemap(t, 0) -} - -func reflect_mapaccess(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer { - val, ok := mapaccess2(t, h, key) - if !ok { - // reflect wants nil for a missing element - val = nil - } - return val -} - -func reflect_mapassign(t *maptype, h *hmap, key unsafe.Pointer, val unsafe.Pointer) { - mapassign1(t, h, key, val) -} - -func reflect_mapdelete(t *maptype, h *hmap, key unsafe.Pointer) { - mapdelete(t, h, key) -} - -func reflect_mapiterinit(t *maptype, h *hmap) *hiter { - it := new(hiter) - mapiterinit(t, h, it) - return it -} - -func reflect_mapiternext(it *hiter) { - mapiternext(it) -} - -func reflect_mapiterkey(it *hiter) unsafe.Pointer { - return it.key -} - -func reflect_maplen(h *hmap) int { - if h == nil { - return 0 - } - if raceenabled { - callerpc := getcallerpc(unsafe.Pointer(&h)) - racereadpc(unsafe.Pointer(h), callerpc, funcPC(reflect_maplen)) - } - return h.count -} - -func reflect_ismapkey(t *_type) bool { - return ismapkey(t) -} diff --git a/libgo/go/runtime/hashmap_fast.go b/libgo/go/runtime/hashmap_fast.go deleted file mode 100644 index afa6ecc99a9..00000000000 --- a/libgo/go/runtime/hashmap_fast.go +++ /dev/null @@ -1,379 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -import ( - "unsafe" -) - -func mapaccess1_fast32(t *maptype, h *hmap, key uint32) unsafe.Pointer { - if raceenabled && h != nil { - callerpc := getcallerpc(unsafe.Pointer(&t)) - racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapaccess1_fast32)) - } - if h == nil || h.count == 0 { - return unsafe.Pointer(t.elem.zero) - } - var b *bmap - if h.B == 0 { - // One-bucket table. No need to hash. - b = (*bmap)(h.buckets) - } else { - hash := goalg(t.key.alg).hash(noescape(unsafe.Pointer(&key)), 4, uintptr(h.hash0)) - m := uintptr(1)<>1))*uintptr(t.bucketsize))) - if !evacuated(oldb) { - b = oldb - } - } - } - for { - for i := uintptr(0); i < bucketCnt; i++ { - k := *((*uint32)(add(unsafe.Pointer(b), dataOffset+i*4))) - if k != key { - continue - } - x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check - if x == empty { - continue - } - return add(unsafe.Pointer(b), dataOffset+bucketCnt*4+i*uintptr(t.valuesize)) - } - b = b.overflow(t) - if b == nil { - return unsafe.Pointer(t.elem.zero) - } - } -} - -func mapaccess2_fast32(t *maptype, h *hmap, key uint32) (unsafe.Pointer, bool) { - if raceenabled && h != nil { - callerpc := getcallerpc(unsafe.Pointer(&t)) - racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapaccess2_fast32)) - } - if h == nil || h.count == 0 { - return unsafe.Pointer(t.elem.zero), false - } - var b *bmap - if h.B == 0 { - // One-bucket table. No need to hash. - b = (*bmap)(h.buckets) - } else { - hash := goalg(t.key.alg).hash(noescape(unsafe.Pointer(&key)), 4, uintptr(h.hash0)) - m := uintptr(1)<>1))*uintptr(t.bucketsize))) - if !evacuated(oldb) { - b = oldb - } - } - } - for { - for i := uintptr(0); i < bucketCnt; i++ { - k := *((*uint32)(add(unsafe.Pointer(b), dataOffset+i*4))) - if k != key { - continue - } - x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check - if x == empty { - continue - } - return add(unsafe.Pointer(b), dataOffset+bucketCnt*4+i*uintptr(t.valuesize)), true - } - b = b.overflow(t) - if b == nil { - return unsafe.Pointer(t.elem.zero), false - } - } -} - -func mapaccess1_fast64(t *maptype, h *hmap, key uint64) unsafe.Pointer { - if raceenabled && h != nil { - callerpc := getcallerpc(unsafe.Pointer(&t)) - racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapaccess1_fast64)) - } - if h == nil || h.count == 0 { - return unsafe.Pointer(t.elem.zero) - } - var b *bmap - if h.B == 0 { - // One-bucket table. No need to hash. - b = (*bmap)(h.buckets) - } else { - hash := goalg(t.key.alg).hash(noescape(unsafe.Pointer(&key)), 8, uintptr(h.hash0)) - m := uintptr(1)<>1))*uintptr(t.bucketsize))) - if !evacuated(oldb) { - b = oldb - } - } - } - for { - for i := uintptr(0); i < bucketCnt; i++ { - k := *((*uint64)(add(unsafe.Pointer(b), dataOffset+i*8))) - if k != key { - continue - } - x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check - if x == empty { - continue - } - return add(unsafe.Pointer(b), dataOffset+bucketCnt*8+i*uintptr(t.valuesize)) - } - b = b.overflow(t) - if b == nil { - return unsafe.Pointer(t.elem.zero) - } - } -} - -func mapaccess2_fast64(t *maptype, h *hmap, key uint64) (unsafe.Pointer, bool) { - if raceenabled && h != nil { - callerpc := getcallerpc(unsafe.Pointer(&t)) - racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapaccess2_fast64)) - } - if h == nil || h.count == 0 { - return unsafe.Pointer(t.elem.zero), false - } - var b *bmap - if h.B == 0 { - // One-bucket table. No need to hash. - b = (*bmap)(h.buckets) - } else { - hash := goalg(t.key.alg).hash(noescape(unsafe.Pointer(&key)), 8, uintptr(h.hash0)) - m := uintptr(1)<>1))*uintptr(t.bucketsize))) - if !evacuated(oldb) { - b = oldb - } - } - } - for { - for i := uintptr(0); i < bucketCnt; i++ { - k := *((*uint64)(add(unsafe.Pointer(b), dataOffset+i*8))) - if k != key { - continue - } - x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check - if x == empty { - continue - } - return add(unsafe.Pointer(b), dataOffset+bucketCnt*8+i*uintptr(t.valuesize)), true - } - b = b.overflow(t) - if b == nil { - return unsafe.Pointer(t.elem.zero), false - } - } -} - -func mapaccess1_faststr(t *maptype, h *hmap, ky string) unsafe.Pointer { - if raceenabled && h != nil { - callerpc := getcallerpc(unsafe.Pointer(&t)) - racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapaccess1_faststr)) - } - if h == nil || h.count == 0 { - return unsafe.Pointer(t.elem.zero) - } - key := (*stringStruct)(unsafe.Pointer(&ky)) - if h.B == 0 { - // One-bucket table. - b := (*bmap)(h.buckets) - if key.len < 32 { - // short key, doing lots of comparisons is ok - for i := uintptr(0); i < bucketCnt; i++ { - x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check - if x == empty { - continue - } - k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+i*2*ptrSize)) - if k.len != key.len { - continue - } - if k.str == key.str || memeq(k.str, key.str, uintptr(key.len)) { - return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*ptrSize+i*uintptr(t.valuesize)) - } - } - return unsafe.Pointer(t.elem.zero) - } - // long key, try not to do more comparisons than necessary - keymaybe := uintptr(bucketCnt) - for i := uintptr(0); i < bucketCnt; i++ { - x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check - if x == empty { - continue - } - k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+i*2*ptrSize)) - if k.len != key.len { - continue - } - if k.str == key.str { - return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*ptrSize+i*uintptr(t.valuesize)) - } - // check first 4 bytes - // TODO: on amd64/386 at least, make this compile to one 4-byte comparison instead of - // four 1-byte comparisons. - if *((*[4]byte)(key.str)) != *((*[4]byte)(k.str)) { - continue - } - // check last 4 bytes - if *((*[4]byte)(add(key.str, uintptr(key.len)-4))) != *((*[4]byte)(add(k.str, uintptr(key.len)-4))) { - continue - } - if keymaybe != bucketCnt { - // Two keys are potential matches. Use hash to distinguish them. - goto dohash - } - keymaybe = i - } - if keymaybe != bucketCnt { - k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+keymaybe*2*ptrSize)) - if memeq(k.str, key.str, uintptr(key.len)) { - return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*ptrSize+keymaybe*uintptr(t.valuesize)) - } - } - return unsafe.Pointer(t.elem.zero) - } -dohash: - hash := goalg(t.key.alg).hash(noescape(unsafe.Pointer(&ky)), 2*ptrSize, uintptr(h.hash0)) - m := uintptr(1)<>1))*uintptr(t.bucketsize))) - if !evacuated(oldb) { - b = oldb - } - } - top := uint8(hash >> (ptrSize*8 - 8)) - if top < minTopHash { - top += minTopHash - } - for { - for i := uintptr(0); i < bucketCnt; i++ { - x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check - if x != top { - continue - } - k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+i*2*ptrSize)) - if k.len != key.len { - continue - } - if k.str == key.str || memeq(k.str, key.str, uintptr(key.len)) { - return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*ptrSize+i*uintptr(t.valuesize)) - } - } - b = b.overflow(t) - if b == nil { - return unsafe.Pointer(t.elem.zero) - } - } -} - -func mapaccess2_faststr(t *maptype, h *hmap, ky string) (unsafe.Pointer, bool) { - if raceenabled && h != nil { - callerpc := getcallerpc(unsafe.Pointer(&t)) - racereadpc(unsafe.Pointer(h), callerpc, funcPC(mapaccess2_faststr)) - } - if h == nil || h.count == 0 { - return unsafe.Pointer(t.elem.zero), false - } - key := (*stringStruct)(unsafe.Pointer(&ky)) - if h.B == 0 { - // One-bucket table. - b := (*bmap)(h.buckets) - if key.len < 32 { - // short key, doing lots of comparisons is ok - for i := uintptr(0); i < bucketCnt; i++ { - x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check - if x == empty { - continue - } - k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+i*2*ptrSize)) - if k.len != key.len { - continue - } - if k.str == key.str || memeq(k.str, key.str, uintptr(key.len)) { - return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*ptrSize+i*uintptr(t.valuesize)), true - } - } - return unsafe.Pointer(t.elem.zero), false - } - // long key, try not to do more comparisons than necessary - keymaybe := uintptr(bucketCnt) - for i := uintptr(0); i < bucketCnt; i++ { - x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check - if x == empty { - continue - } - k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+i*2*ptrSize)) - if k.len != key.len { - continue - } - if k.str == key.str { - return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*ptrSize+i*uintptr(t.valuesize)), true - } - // check first 4 bytes - if *((*[4]byte)(key.str)) != *((*[4]byte)(k.str)) { - continue - } - // check last 4 bytes - if *((*[4]byte)(add(key.str, uintptr(key.len)-4))) != *((*[4]byte)(add(k.str, uintptr(key.len)-4))) { - continue - } - if keymaybe != bucketCnt { - // Two keys are potential matches. Use hash to distinguish them. - goto dohash - } - keymaybe = i - } - if keymaybe != bucketCnt { - k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+keymaybe*2*ptrSize)) - if memeq(k.str, key.str, uintptr(key.len)) { - return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*ptrSize+keymaybe*uintptr(t.valuesize)), true - } - } - return unsafe.Pointer(t.elem.zero), false - } -dohash: - hash := goalg(t.key.alg).hash(noescape(unsafe.Pointer(&ky)), 2*ptrSize, uintptr(h.hash0)) - m := uintptr(1)<>1))*uintptr(t.bucketsize))) - if !evacuated(oldb) { - b = oldb - } - } - top := uint8(hash >> (ptrSize*8 - 8)) - if top < minTopHash { - top += minTopHash - } - for { - for i := uintptr(0); i < bucketCnt; i++ { - x := *((*uint8)(add(unsafe.Pointer(b), i))) // b.topbits[i] without the bounds check - if x != top { - continue - } - k := (*stringStruct)(add(unsafe.Pointer(b), dataOffset+i*2*ptrSize)) - if k.len != key.len { - continue - } - if k.str == key.str || memeq(k.str, key.str, uintptr(key.len)) { - return add(unsafe.Pointer(b), dataOffset+bucketCnt*2*ptrSize+i*uintptr(t.valuesize)), true - } - } - b = b.overflow(t) - if b == nil { - return unsafe.Pointer(t.elem.zero), false - } - } -} diff --git a/libgo/go/runtime/iface_test.go b/libgo/go/runtime/iface_test.go index bca0ea0ee75..7f27baa61fb 100644 --- a/libgo/go/runtime/iface_test.go +++ b/libgo/go/runtime/iface_test.go @@ -5,6 +5,7 @@ package runtime_test import ( + "runtime" "testing" ) @@ -36,8 +37,50 @@ var ( ts TS tm TM tl TL + ok bool ) +// Issue 9370 +func TestCmpIfaceConcreteAlloc(t *testing.T) { + if runtime.Compiler != "gc" { + t.Skip("skipping on non-gc compiler") + } + + n := testing.AllocsPerRun(1, func() { + _ = e == ts + _ = i1 == ts + _ = e == 1 + }) + + if n > 0 { + t.Fatalf("iface cmp allocs=%v; want 0", n) + } +} + +func BenchmarkEqEfaceConcrete(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = e == ts + } +} + +func BenchmarkEqIfaceConcrete(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = i1 == ts + } +} + +func BenchmarkNeEfaceConcrete(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = e != ts + } +} + +func BenchmarkNeIfaceConcrete(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = i1 != ts + } +} + func BenchmarkConvT2ESmall(b *testing.B) { for i := 0; i < b.N; i++ { e = ts @@ -136,3 +179,85 @@ func BenchmarkAssertE2E(b *testing.B) { e_ = e } } + +func BenchmarkAssertE2T2(b *testing.B) { + e = tm + for i := 0; i < b.N; i++ { + tm, ok = e.(TM) + } +} + +func BenchmarkAssertE2T2Blank(b *testing.B) { + e = tm + for i := 0; i < b.N; i++ { + _, ok = e.(TM) + } +} + +func BenchmarkAssertI2E2(b *testing.B) { + i1 = tm + for i := 0; i < b.N; i++ { + e, ok = i1.(interface{}) + } +} + +func BenchmarkAssertI2E2Blank(b *testing.B) { + i1 = tm + for i := 0; i < b.N; i++ { + _, ok = i1.(interface{}) + } +} + +func BenchmarkAssertE2E2(b *testing.B) { + e = tm + for i := 0; i < b.N; i++ { + e_, ok = e.(interface{}) + } +} + +func BenchmarkAssertE2E2Blank(b *testing.B) { + e = tm + for i := 0; i < b.N; i++ { + _, ok = e.(interface{}) + } +} + +func TestNonEscapingConvT2E(t *testing.T) { + m := make(map[interface{}]bool) + m[42] = true + if !m[42] { + t.Fatalf("42 is not present in the map") + } + if m[0] { + t.Fatalf("0 is present in the map") + } + + n := testing.AllocsPerRun(1000, func() { + if m[0] { + t.Fatalf("0 is present in the map") + } + }) + if n != 0 { + t.Fatalf("want 0 allocs, got %v", n) + } +} + +func TestNonEscapingConvT2I(t *testing.T) { + m := make(map[I1]bool) + m[TM(42)] = true + if !m[TM(42)] { + t.Fatalf("42 is not present in the map") + } + if m[TM(0)] { + t.Fatalf("0 is present in the map") + } + + n := testing.AllocsPerRun(1000, func() { + if m[TM(0)] { + t.Fatalf("0 is present in the map") + } + }) + if n != 0 { + t.Fatalf("want 0 allocs, got %v", n) + } +} diff --git a/libgo/go/runtime/lfstack_test.go b/libgo/go/runtime/lfstack_test.go index e5187770453..fb4b45992d8 100644 --- a/libgo/go/runtime/lfstack_test.go +++ b/libgo/go/runtime/lfstack_test.go @@ -24,9 +24,13 @@ func toMyNode(node *LFNode) *MyNode { return (*MyNode)(unsafe.Pointer(node)) } +var global interface{} + func TestLFStack(t *testing.T) { stack := new(uint64) - // Need to keep additional referenfces to nodes, the stack is not all that type-safe. + global = stack // force heap allocation + + // Need to keep additional references to nodes, the stack is not all that type-safe. var nodes []*MyNode // Check the stack is initially empty. @@ -121,7 +125,7 @@ func TestLFStackStress(t *testing.T) { } cnt++ sum2 += node.data - node.Next = nil + node.Next = 0 } } if cnt != K { diff --git a/libgo/go/runtime/lock_futex.go b/libgo/go/runtime/lock_futex.go deleted file mode 100644 index 725962341d4..00000000000 --- a/libgo/go/runtime/lock_futex.go +++ /dev/null @@ -1,205 +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 dragonfly freebsd linux - -package runtime - -import "unsafe" - -// This implementation depends on OS-specific implementations of -// -// runtime·futexsleep(uint32 *addr, uint32 val, int64 ns) -// Atomically, -// if(*addr == val) sleep -// Might be woken up spuriously; that's allowed. -// Don't sleep longer than ns; ns < 0 means forever. -// -// runtime·futexwakeup(uint32 *addr, uint32 cnt) -// If any procs are sleeping on addr, wake up at most cnt. - -const ( - mutex_unlocked = 0 - mutex_locked = 1 - mutex_sleeping = 2 - - active_spin = 4 - active_spin_cnt = 30 - passive_spin = 1 -) - -// Possible lock states are mutex_unlocked, mutex_locked and mutex_sleeping. -// mutex_sleeping means that there is presumably at least one sleeping thread. -// Note that there can be spinning threads during all states - they do not -// affect mutex's state. - -func futexsleep(addr *uint32, val uint32, ns int64) -func futexwakeup(addr *uint32, cnt uint32) - -// We use the uintptr mutex.key and note.key as a uint32. -func key32(p *uintptr) *uint32 { - return (*uint32)(unsafe.Pointer(p)) -} - -func lock(l *mutex) { - gp := getg() - - if gp.m.locks < 0 { - gothrow("runtime·lock: lock count") - } - gp.m.locks++ - - // Speculative grab for lock. - v := xchg(key32(&l.key), mutex_locked) - if v == mutex_unlocked { - return - } - - // wait is either MUTEX_LOCKED or MUTEX_SLEEPING - // depending on whether there is a thread sleeping - // on this mutex. If we ever change l->key from - // MUTEX_SLEEPING to some other value, we must be - // careful to change it back to MUTEX_SLEEPING before - // returning, to ensure that the sleeping thread gets - // its wakeup call. - wait := v - - // On uniprocessors, no point spinning. - // On multiprocessors, spin for ACTIVE_SPIN attempts. - spin := 0 - if ncpu > 1 { - spin = active_spin - } - for { - // Try for lock, spinning. - for i := 0; i < spin; i++ { - for l.key == mutex_unlocked { - if cas(key32(&l.key), mutex_unlocked, wait) { - return - } - } - procyield(active_spin_cnt) - } - - // Try for lock, rescheduling. - for i := 0; i < passive_spin; i++ { - for l.key == mutex_unlocked { - if cas(key32(&l.key), mutex_unlocked, wait) { - return - } - } - osyield() - } - - // Sleep. - v = xchg(key32(&l.key), mutex_sleeping) - if v == mutex_unlocked { - return - } - wait = mutex_sleeping - futexsleep(key32(&l.key), mutex_sleeping, -1) - } -} - -func unlock(l *mutex) { - v := xchg(key32(&l.key), mutex_unlocked) - if v == mutex_unlocked { - gothrow("unlock of unlocked lock") - } - if v == mutex_sleeping { - futexwakeup(key32(&l.key), 1) - } - - gp := getg() - gp.m.locks-- - if gp.m.locks < 0 { - gothrow("runtime·unlock: lock count") - } - if gp.m.locks == 0 && gp.preempt { // restore the preemption request in case we've cleared it in newstack - gp.stackguard0 = stackPreempt - } -} - -// One-time notifications. -func noteclear(n *note) { - n.key = 0 -} - -func notewakeup(n *note) { - old := xchg(key32(&n.key), 1) - if old != 0 { - print("notewakeup - double wakeup (", old, ")\n") - gothrow("notewakeup - double wakeup") - } - futexwakeup(key32(&n.key), 1) -} - -func notesleep(n *note) { - gp := getg() - if gp != gp.m.g0 { - gothrow("notesleep not on g0") - } - for atomicload(key32(&n.key)) == 0 { - gp.m.blocked = true - futexsleep(key32(&n.key), 0, -1) - gp.m.blocked = false - } -} - -//go:nosplit -func notetsleep_internal(n *note, ns int64) bool { - gp := getg() - - if ns < 0 { - for atomicload(key32(&n.key)) == 0 { - gp.m.blocked = true - futexsleep(key32(&n.key), 0, -1) - gp.m.blocked = false - } - return true - } - - if atomicload(key32(&n.key)) != 0 { - return true - } - - deadline := nanotime() + ns - for { - gp.m.blocked = true - futexsleep(key32(&n.key), 0, ns) - gp.m.blocked = false - if atomicload(key32(&n.key)) != 0 { - break - } - now := nanotime() - if now >= deadline { - break - } - ns = deadline - now - } - return atomicload(key32(&n.key)) != 0 -} - -func notetsleep(n *note, ns int64) bool { - gp := getg() - if gp != gp.m.g0 && gp.m.gcing == 0 { - gothrow("notetsleep not on g0") - } - - return notetsleep_internal(n, ns) -} - -// same as runtime·notetsleep, but called on user g (not g0) -// calls only nosplit functions between entersyscallblock/exitsyscall -func notetsleepg(n *note, ns int64) bool { - gp := getg() - if gp == gp.m.g0 { - gothrow("notetsleepg on g0") - } - - entersyscallblock() - ok := notetsleep_internal(n, ns) - exitsyscall() - return ok -} diff --git a/libgo/go/runtime/lock_sema.go b/libgo/go/runtime/lock_sema.go deleted file mode 100644 index d136b828061..00000000000 --- a/libgo/go/runtime/lock_sema.go +++ /dev/null @@ -1,270 +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 darwin nacl netbsd openbsd plan9 solaris windows - -package runtime - -import "unsafe" - -// This implementation depends on OS-specific implementations of -// -// uintptr runtime·semacreate(void) -// Create a semaphore, which will be assigned to m->waitsema. -// The zero value is treated as absence of any semaphore, -// so be sure to return a non-zero value. -// -// int32 runtime·semasleep(int64 ns) -// If ns < 0, acquire m->waitsema and return 0. -// If ns >= 0, try to acquire m->waitsema for at most ns nanoseconds. -// Return 0 if the semaphore was acquired, -1 if interrupted or timed out. -// -// int32 runtime·semawakeup(M *mp) -// Wake up mp, which is or will soon be sleeping on mp->waitsema. -// -const ( - locked uintptr = 1 - - active_spin = 4 - active_spin_cnt = 30 - passive_spin = 1 -) - -func semacreate() uintptr -func semasleep(int64) int32 -func semawakeup(mp *m) - -func lock(l *mutex) { - gp := getg() - if gp.m.locks < 0 { - gothrow("runtime·lock: lock count") - } - gp.m.locks++ - - // Speculative grab for lock. - if casuintptr(&l.key, 0, locked) { - return - } - if gp.m.waitsema == 0 { - gp.m.waitsema = semacreate() - } - - // On uniprocessor's, no point spinning. - // On multiprocessors, spin for ACTIVE_SPIN attempts. - spin := 0 - if ncpu > 1 { - spin = active_spin - } -Loop: - for i := 0; ; i++ { - v := atomicloaduintptr(&l.key) - if v&locked == 0 { - // Unlocked. Try to lock. - if casuintptr(&l.key, v, v|locked) { - return - } - i = 0 - } - if i < spin { - procyield(active_spin_cnt) - } else if i < spin+passive_spin { - osyield() - } else { - // Someone else has it. - // l->waitm points to a linked list of M's waiting - // for this lock, chained through m->nextwaitm. - // Queue this M. - for { - gp.m.nextwaitm = (*m)((unsafe.Pointer)(v &^ locked)) - if casuintptr(&l.key, v, uintptr(unsafe.Pointer(gp.m))|locked) { - break - } - v = atomicloaduintptr(&l.key) - if v&locked == 0 { - continue Loop - } - } - if v&locked != 0 { - // Queued. Wait. - semasleep(-1) - i = 0 - } - } - } -} - -func unlock(l *mutex) { - gp := getg() - var mp *m - for { - v := atomicloaduintptr(&l.key) - if v == locked { - if casuintptr(&l.key, locked, 0) { - break - } - } else { - // Other M's are waiting for the lock. - // Dequeue an M. - mp = (*m)((unsafe.Pointer)(v &^ locked)) - if casuintptr(&l.key, v, uintptr(unsafe.Pointer(mp.nextwaitm))) { - // Dequeued an M. Wake it. - semawakeup(mp) - break - } - } - } - gp.m.locks-- - if gp.m.locks < 0 { - gothrow("runtime·unlock: lock count") - } - if gp.m.locks == 0 && gp.preempt { // restore the preemption request in case we've cleared it in newstack - gp.stackguard0 = stackPreempt - } -} - -// One-time notifications. -func noteclear(n *note) { - n.key = 0 -} - -func notewakeup(n *note) { - var v uintptr - for { - v = atomicloaduintptr(&n.key) - if casuintptr(&n.key, v, locked) { - break - } - } - - // Successfully set waitm to locked. - // What was it before? - switch { - case v == 0: - // Nothing was waiting. Done. - case v == locked: - // Two notewakeups! Not allowed. - gothrow("notewakeup - double wakeup") - default: - // Must be the waiting m. Wake it up. - semawakeup((*m)(unsafe.Pointer(v))) - } -} - -func notesleep(n *note) { - gp := getg() - if gp != gp.m.g0 { - gothrow("notesleep not on g0") - } - if gp.m.waitsema == 0 { - gp.m.waitsema = semacreate() - } - if !casuintptr(&n.key, 0, uintptr(unsafe.Pointer(gp.m))) { - // Must be locked (got wakeup). - if n.key != locked { - gothrow("notesleep - waitm out of sync") - } - return - } - // Queued. Sleep. - gp.m.blocked = true - semasleep(-1) - gp.m.blocked = false -} - -//go:nosplit -func notetsleep_internal(n *note, ns int64, gp *g, deadline int64) bool { - // gp and deadline are logically local variables, but they are written - // as parameters so that the stack space they require is charged - // to the caller. - // This reduces the nosplit footprint of notetsleep_internal. - gp = getg() - - // Register for wakeup on n->waitm. - if !casuintptr(&n.key, 0, uintptr(unsafe.Pointer(gp.m))) { - // Must be locked (got wakeup). - if n.key != locked { - gothrow("notetsleep - waitm out of sync") - } - return true - } - if ns < 0 { - // Queued. Sleep. - gp.m.blocked = true - semasleep(-1) - gp.m.blocked = false - return true - } - - deadline = nanotime() + ns - for { - // Registered. Sleep. - gp.m.blocked = true - if semasleep(ns) >= 0 { - gp.m.blocked = false - // Acquired semaphore, semawakeup unregistered us. - // Done. - return true - } - gp.m.blocked = false - // Interrupted or timed out. Still registered. Semaphore not acquired. - ns = deadline - nanotime() - if ns <= 0 { - break - } - // Deadline hasn't arrived. Keep sleeping. - } - - // Deadline arrived. Still registered. Semaphore not acquired. - // Want to give up and return, but have to unregister first, - // so that any notewakeup racing with the return does not - // try to grant us the semaphore when we don't expect it. - for { - v := atomicloaduintptr(&n.key) - switch v { - case uintptr(unsafe.Pointer(gp.m)): - // No wakeup yet; unregister if possible. - if casuintptr(&n.key, v, 0) { - return false - } - case locked: - // Wakeup happened so semaphore is available. - // Grab it to avoid getting out of sync. - gp.m.blocked = true - if semasleep(-1) < 0 { - gothrow("runtime: unable to acquire - semaphore out of sync") - } - gp.m.blocked = false - return true - default: - gothrow("runtime: unexpected waitm - semaphore out of sync") - } - } -} - -func notetsleep(n *note, ns int64) bool { - gp := getg() - if gp != gp.m.g0 && gp.m.gcing == 0 { - gothrow("notetsleep not on g0") - } - if gp.m.waitsema == 0 { - gp.m.waitsema = semacreate() - } - return notetsleep_internal(n, ns, nil, 0) -} - -// same as runtime·notetsleep, but called on user g (not g0) -// calls only nosplit functions between entersyscallblock/exitsyscall -func notetsleepg(n *note, ns int64) bool { - gp := getg() - if gp == gp.m.g0 { - gothrow("notetsleepg on g0") - } - if gp.m.waitsema == 0 { - gp.m.waitsema = semacreate() - } - entersyscallblock() - ok := notetsleep_internal(n, ns, nil, 0) - exitsyscall() - return ok -} diff --git a/libgo/go/runtime/malloc.go b/libgo/go/runtime/malloc.go deleted file mode 100644 index 11704494404..00000000000 --- a/libgo/go/runtime/malloc.go +++ /dev/null @@ -1,837 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -import ( - "unsafe" -) - -const ( - debugMalloc = false - - flagNoScan = _FlagNoScan - flagNoZero = _FlagNoZero - - maxTinySize = _TinySize - tinySizeClass = _TinySizeClass - maxSmallSize = _MaxSmallSize - - pageShift = _PageShift - pageSize = _PageSize - pageMask = _PageMask - - bitsPerPointer = _BitsPerPointer - bitsMask = _BitsMask - pointersPerByte = _PointersPerByte - maxGCMask = _MaxGCMask - bitsDead = _BitsDead - bitsPointer = _BitsPointer - - mSpanInUse = _MSpanInUse - - concurrentSweep = _ConcurrentSweep != 0 -) - -// Page number (address>>pageShift) -type pageID uintptr - -// base address for all 0-byte allocations -var zerobase uintptr - -// Allocate an object of size bytes. -// Small objects are allocated from the per-P cache's free lists. -// Large objects (> 32 kB) are allocated straight from the heap. -func mallocgc(size uintptr, typ *_type, flags uint32) unsafe.Pointer { - if size == 0 { - return unsafe.Pointer(&zerobase) - } - size0 := size - - if flags&flagNoScan == 0 && typ == nil { - gothrow("malloc missing type") - } - - // This function must be atomic wrt GC, but for performance reasons - // we don't acquirem/releasem on fast path. The code below does not have - // split stack checks, so it can't be preempted by GC. - // Functions like roundup/add are inlined. And onM/racemalloc are nosplit. - // If debugMalloc = true, these assumptions are checked below. - if debugMalloc { - mp := acquirem() - if mp.mallocing != 0 { - gothrow("malloc deadlock") - } - mp.mallocing = 1 - if mp.curg != nil { - mp.curg.stackguard0 = ^uintptr(0xfff) | 0xbad - } - } - - c := gomcache() - var s *mspan - var x unsafe.Pointer - if size <= maxSmallSize { - if flags&flagNoScan != 0 && size < maxTinySize { - // Tiny allocator. - // - // Tiny allocator combines several tiny allocation requests - // into a single memory block. The resulting memory block - // is freed when all subobjects are unreachable. The subobjects - // must be FlagNoScan (don't have pointers), this ensures that - // the amount of potentially wasted memory is bounded. - // - // Size of the memory block used for combining (maxTinySize) is tunable. - // Current setting is 16 bytes, which relates to 2x worst case memory - // wastage (when all but one subobjects are unreachable). - // 8 bytes would result in no wastage at all, but provides less - // opportunities for combining. - // 32 bytes provides more opportunities for combining, - // but can lead to 4x worst case wastage. - // The best case winning is 8x regardless of block size. - // - // Objects obtained from tiny allocator must not be freed explicitly. - // So when an object will be freed explicitly, we ensure that - // its size >= maxTinySize. - // - // SetFinalizer has a special case for objects potentially coming - // from tiny allocator, it such case it allows to set finalizers - // for an inner byte of a memory block. - // - // The main targets of tiny allocator are small strings and - // standalone escaping variables. On a json benchmark - // the allocator reduces number of allocations by ~12% and - // reduces heap size by ~20%. - tinysize := uintptr(c.tinysize) - if size <= tinysize { - tiny := unsafe.Pointer(c.tiny) - // Align tiny pointer for required (conservative) alignment. - if size&7 == 0 { - tiny = roundup(tiny, 8) - } else if size&3 == 0 { - tiny = roundup(tiny, 4) - } else if size&1 == 0 { - tiny = roundup(tiny, 2) - } - size1 := size + (uintptr(tiny) - uintptr(unsafe.Pointer(c.tiny))) - if size1 <= tinysize { - // The object fits into existing tiny block. - x = tiny - c.tiny = (*byte)(add(x, size)) - c.tinysize -= uintptr(size1) - c.local_tinyallocs++ - if debugMalloc { - mp := acquirem() - if mp.mallocing == 0 { - gothrow("bad malloc") - } - mp.mallocing = 0 - if mp.curg != nil { - mp.curg.stackguard0 = mp.curg.stack.lo + _StackGuard - } - // Note: one releasem for the acquirem just above. - // The other for the acquirem at start of malloc. - releasem(mp) - releasem(mp) - } - return x - } - } - // Allocate a new maxTinySize block. - s = c.alloc[tinySizeClass] - v := s.freelist - if v == nil { - mp := acquirem() - mp.scalararg[0] = tinySizeClass - onM(mcacheRefill_m) - releasem(mp) - s = c.alloc[tinySizeClass] - v = s.freelist - } - s.freelist = v.next - s.ref++ - //TODO: prefetch v.next - x = unsafe.Pointer(v) - (*[2]uint64)(x)[0] = 0 - (*[2]uint64)(x)[1] = 0 - // See if we need to replace the existing tiny block with the new one - // based on amount of remaining free space. - if maxTinySize-size > tinysize { - c.tiny = (*byte)(add(x, size)) - c.tinysize = uintptr(maxTinySize - size) - } - size = maxTinySize - } else { - var sizeclass int8 - if size <= 1024-8 { - sizeclass = size_to_class8[(size+7)>>3] - } else { - sizeclass = size_to_class128[(size-1024+127)>>7] - } - size = uintptr(class_to_size[sizeclass]) - s = c.alloc[sizeclass] - v := s.freelist - if v == nil { - mp := acquirem() - mp.scalararg[0] = uintptr(sizeclass) - onM(mcacheRefill_m) - releasem(mp) - s = c.alloc[sizeclass] - v = s.freelist - } - s.freelist = v.next - s.ref++ - //TODO: prefetch - x = unsafe.Pointer(v) - if flags&flagNoZero == 0 { - v.next = nil - if size > 2*ptrSize && ((*[2]uintptr)(x))[1] != 0 { - memclr(unsafe.Pointer(v), size) - } - } - } - c.local_cachealloc += intptr(size) - } else { - mp := acquirem() - mp.scalararg[0] = uintptr(size) - mp.scalararg[1] = uintptr(flags) - onM(largeAlloc_m) - s = (*mspan)(mp.ptrarg[0]) - mp.ptrarg[0] = nil - releasem(mp) - x = unsafe.Pointer(uintptr(s.start << pageShift)) - size = uintptr(s.elemsize) - } - - if flags&flagNoScan != 0 { - // All objects are pre-marked as noscan. - goto marked - } - - // If allocating a defer+arg block, now that we've picked a malloc size - // large enough to hold everything, cut the "asked for" size down to - // just the defer header, so that the GC bitmap will record the arg block - // as containing nothing at all (as if it were unused space at the end of - // a malloc block caused by size rounding). - // The defer arg areas are scanned as part of scanstack. - if typ == deferType { - size0 = unsafe.Sizeof(_defer{}) - } - - // From here till marked label marking the object as allocated - // and storing type info in the GC bitmap. - { - arena_start := uintptr(unsafe.Pointer(mheap_.arena_start)) - off := (uintptr(x) - arena_start) / ptrSize - xbits := (*uint8)(unsafe.Pointer(arena_start - off/wordsPerBitmapByte - 1)) - shift := (off % wordsPerBitmapByte) * gcBits - if debugMalloc && ((*xbits>>shift)&(bitMask|bitPtrMask)) != bitBoundary { - println("runtime: bits =", (*xbits>>shift)&(bitMask|bitPtrMask)) - gothrow("bad bits in markallocated") - } - - var ti, te uintptr - var ptrmask *uint8 - if size == ptrSize { - // It's one word and it has pointers, it must be a pointer. - *xbits |= (bitsPointer << 2) << shift - goto marked - } - if typ.kind&kindGCProg != 0 { - nptr := (uintptr(typ.size) + ptrSize - 1) / ptrSize - masksize := nptr - if masksize%2 != 0 { - masksize *= 2 // repeated - } - masksize = masksize * pointersPerByte / 8 // 4 bits per word - masksize++ // unroll flag in the beginning - if masksize > maxGCMask && typ.gc[1] != 0 { - // If the mask is too large, unroll the program directly - // into the GC bitmap. It's 7 times slower than copying - // from the pre-unrolled mask, but saves 1/16 of type size - // memory for the mask. - mp := acquirem() - mp.ptrarg[0] = x - mp.ptrarg[1] = unsafe.Pointer(typ) - mp.scalararg[0] = uintptr(size) - mp.scalararg[1] = uintptr(size0) - onM(unrollgcproginplace_m) - releasem(mp) - goto marked - } - ptrmask = (*uint8)(unsafe.Pointer(uintptr(typ.gc[0]))) - // Check whether the program is already unrolled. - if uintptr(atomicloadp(unsafe.Pointer(ptrmask)))&0xff == 0 { - mp := acquirem() - mp.ptrarg[0] = unsafe.Pointer(typ) - onM(unrollgcprog_m) - releasem(mp) - } - ptrmask = (*uint8)(add(unsafe.Pointer(ptrmask), 1)) // skip the unroll flag byte - } else { - ptrmask = (*uint8)(unsafe.Pointer(typ.gc[0])) // pointer to unrolled mask - } - if size == 2*ptrSize { - *xbits = *ptrmask | bitBoundary - goto marked - } - te = uintptr(typ.size) / ptrSize - // If the type occupies odd number of words, its mask is repeated. - if te%2 == 0 { - te /= 2 - } - // Copy pointer bitmask into the bitmap. - for i := uintptr(0); i < size0; i += 2 * ptrSize { - v := *(*uint8)(add(unsafe.Pointer(ptrmask), ti)) - ti++ - if ti == te { - ti = 0 - } - if i == 0 { - v |= bitBoundary - } - if i+ptrSize == size0 { - v &^= uint8(bitPtrMask << 4) - } - - *xbits = v - xbits = (*byte)(add(unsafe.Pointer(xbits), ^uintptr(0))) - } - if size0%(2*ptrSize) == 0 && size0 < size { - // Mark the word after last object's word as bitsDead. - *xbits = bitsDead << 2 - } - } -marked: - if raceenabled { - racemalloc(x, size) - } - - if debugMalloc { - mp := acquirem() - if mp.mallocing == 0 { - gothrow("bad malloc") - } - mp.mallocing = 0 - if mp.curg != nil { - mp.curg.stackguard0 = mp.curg.stack.lo + _StackGuard - } - // Note: one releasem for the acquirem just above. - // The other for the acquirem at start of malloc. - releasem(mp) - releasem(mp) - } - - if debug.allocfreetrace != 0 { - tracealloc(x, size, typ) - } - - if rate := MemProfileRate; rate > 0 { - if size < uintptr(rate) && int32(size) < c.next_sample { - c.next_sample -= int32(size) - } else { - mp := acquirem() - profilealloc(mp, x, size) - releasem(mp) - } - } - - if memstats.heap_alloc >= memstats.next_gc { - gogc(0) - } - - return x -} - -// implementation of new builtin -func newobject(typ *_type) unsafe.Pointer { - flags := uint32(0) - if typ.kind&kindNoPointers != 0 { - flags |= flagNoScan - } - return mallocgc(uintptr(typ.size), typ, flags) -} - -// implementation of make builtin for slices -func newarray(typ *_type, n uintptr) unsafe.Pointer { - flags := uint32(0) - if typ.kind&kindNoPointers != 0 { - flags |= flagNoScan - } - if int(n) < 0 || (typ.size > 0 && n > maxmem/uintptr(typ.size)) { - panic("runtime: allocation size out of range") - } - return mallocgc(uintptr(typ.size)*n, typ, flags) -} - -// rawmem returns a chunk of pointerless memory. It is -// not zeroed. -func rawmem(size uintptr) unsafe.Pointer { - return mallocgc(size, nil, flagNoScan|flagNoZero) -} - -// round size up to next size class -func goroundupsize(size uintptr) uintptr { - if size < maxSmallSize { - if size <= 1024-8 { - return uintptr(class_to_size[size_to_class8[(size+7)>>3]]) - } - return uintptr(class_to_size[size_to_class128[(size-1024+127)>>7]]) - } - if size+pageSize < size { - return size - } - return (size + pageSize - 1) &^ pageMask -} - -func profilealloc(mp *m, x unsafe.Pointer, size uintptr) { - c := mp.mcache - rate := MemProfileRate - if size < uintptr(rate) { - // pick next profile time - // If you change this, also change allocmcache. - if rate > 0x3fffffff { // make 2*rate not overflow - rate = 0x3fffffff - } - next := int32(fastrand1()) % (2 * int32(rate)) - // Subtract the "remainder" of the current allocation. - // Otherwise objects that are close in size to sampling rate - // will be under-sampled, because we consistently discard this remainder. - next -= (int32(size) - c.next_sample) - if next < 0 { - next = 0 - } - c.next_sample = next - } - - mProf_Malloc(x, size) -} - -// force = 1 - do GC regardless of current heap usage -// force = 2 - go GC and eager sweep -func gogc(force int32) { - // The gc is turned off (via enablegc) until the bootstrap has completed. - // Also, malloc gets called in the guts of a number of libraries that might be - // holding locks. To avoid deadlocks during stoptheworld, don't bother - // trying to run gc while holding a lock. The next mallocgc without a lock - // will do the gc instead. - mp := acquirem() - if gp := getg(); gp == mp.g0 || mp.locks > 1 || !memstats.enablegc || panicking != 0 || gcpercent < 0 { - releasem(mp) - return - } - releasem(mp) - mp = nil - - semacquire(&worldsema, false) - - if force == 0 && memstats.heap_alloc < memstats.next_gc { - // typically threads which lost the race to grab - // worldsema exit here when gc is done. - semrelease(&worldsema) - return - } - - // Ok, we're doing it! Stop everybody else - startTime := nanotime() - mp = acquirem() - mp.gcing = 1 - releasem(mp) - onM(stoptheworld) - if mp != acquirem() { - gothrow("gogc: rescheduled") - } - - clearpools() - - // Run gc on the g0 stack. We do this so that the g stack - // we're currently running on will no longer change. Cuts - // the root set down a bit (g0 stacks are not scanned, and - // we don't need to scan gc's internal state). We also - // need to switch to g0 so we can shrink the stack. - n := 1 - if debug.gctrace > 1 { - n = 2 - } - for i := 0; i < n; i++ { - if i > 0 { - startTime = nanotime() - } - // switch to g0, call gc, then switch back - mp.scalararg[0] = uintptr(uint32(startTime)) // low 32 bits - mp.scalararg[1] = uintptr(startTime >> 32) // high 32 bits - if force >= 2 { - mp.scalararg[2] = 1 // eagersweep - } else { - mp.scalararg[2] = 0 - } - onM(gc_m) - } - - // all done - mp.gcing = 0 - semrelease(&worldsema) - onM(starttheworld) - releasem(mp) - mp = nil - - // now that gc is done, kick off finalizer thread if needed - if !concurrentSweep { - // give the queued finalizers, if any, a chance to run - Gosched() - } -} - -// GC runs a garbage collection. -func GC() { - gogc(2) -} - -// linker-provided -var noptrdata struct{} -var enoptrdata struct{} -var noptrbss struct{} -var enoptrbss struct{} - -// SetFinalizer sets the finalizer associated with x to f. -// When the garbage collector finds an unreachable block -// with an associated finalizer, it clears the association and runs -// f(x) in a separate goroutine. This makes x reachable again, but -// now without an associated finalizer. Assuming that SetFinalizer -// is not called again, the next time the garbage collector sees -// that x is unreachable, it will free x. -// -// SetFinalizer(x, nil) clears any finalizer associated with x. -// -// The argument x must be a pointer to an object allocated by -// calling new or by taking the address of a composite literal. -// The argument f must be a function that takes a single argument -// to which x's type can be assigned, and can have arbitrary ignored return -// values. If either of these is not true, SetFinalizer aborts the -// program. -// -// Finalizers are run in dependency order: if A points at B, both have -// finalizers, and they are otherwise unreachable, only the finalizer -// for A runs; once A is freed, the finalizer for B can run. -// If a cyclic structure includes a block with a finalizer, that -// cycle is not guaranteed to be garbage collected and the finalizer -// is not guaranteed to run, because there is no ordering that -// respects the dependencies. -// -// The finalizer for x is scheduled to run at some arbitrary time after -// x becomes unreachable. -// There is no guarantee that finalizers will run before a program exits, -// so typically they are useful only for releasing non-memory resources -// associated with an object during a long-running program. -// For example, an os.File object could use a finalizer to close the -// associated operating system file descriptor when a program discards -// an os.File without calling Close, but it would be a mistake -// to depend on a finalizer to flush an in-memory I/O buffer such as a -// bufio.Writer, because the buffer would not be flushed at program exit. -// -// It is not guaranteed that a finalizer will run if the size of *x is -// zero bytes. -// -// It is not guaranteed that a finalizer will run for objects allocated -// in initializers for package-level variables. Such objects may be -// linker-allocated, not heap-allocated. -// -// A single goroutine runs all finalizers for a program, sequentially. -// If a finalizer must run for a long time, it should do so by starting -// a new goroutine. -func SetFinalizer(obj interface{}, finalizer interface{}) { - e := (*eface)(unsafe.Pointer(&obj)) - etyp := e._type - if etyp == nil { - gothrow("runtime.SetFinalizer: first argument is nil") - } - if etyp.kind&kindMask != kindPtr { - gothrow("runtime.SetFinalizer: first argument is " + *etyp._string + ", not pointer") - } - ot := (*ptrtype)(unsafe.Pointer(etyp)) - if ot.elem == nil { - gothrow("nil elem type!") - } - - // find the containing object - _, base, _ := findObject(e.data) - - if base == nil { - // 0-length objects are okay. - if e.data == unsafe.Pointer(&zerobase) { - return - } - - // Global initializers might be linker-allocated. - // var Foo = &Object{} - // func main() { - // runtime.SetFinalizer(Foo, nil) - // } - // The relevant segments are: noptrdata, data, bss, noptrbss. - // We cannot assume they are in any order or even contiguous, - // due to external linking. - if uintptr(unsafe.Pointer(&noptrdata)) <= uintptr(e.data) && uintptr(e.data) < uintptr(unsafe.Pointer(&enoptrdata)) || - uintptr(unsafe.Pointer(&data)) <= uintptr(e.data) && uintptr(e.data) < uintptr(unsafe.Pointer(&edata)) || - uintptr(unsafe.Pointer(&bss)) <= uintptr(e.data) && uintptr(e.data) < uintptr(unsafe.Pointer(&ebss)) || - uintptr(unsafe.Pointer(&noptrbss)) <= uintptr(e.data) && uintptr(e.data) < uintptr(unsafe.Pointer(&enoptrbss)) { - return - } - gothrow("runtime.SetFinalizer: pointer not in allocated block") - } - - if e.data != base { - // As an implementation detail we allow to set finalizers for an inner byte - // of an object if it could come from tiny alloc (see mallocgc for details). - if ot.elem == nil || ot.elem.kind&kindNoPointers == 0 || ot.elem.size >= maxTinySize { - gothrow("runtime.SetFinalizer: pointer not at beginning of allocated block") - } - } - - f := (*eface)(unsafe.Pointer(&finalizer)) - ftyp := f._type - if ftyp == nil { - // switch to M stack and remove finalizer - mp := acquirem() - mp.ptrarg[0] = e.data - onM(removeFinalizer_m) - releasem(mp) - return - } - - if ftyp.kind&kindMask != kindFunc { - gothrow("runtime.SetFinalizer: second argument is " + *ftyp._string + ", not a function") - } - ft := (*functype)(unsafe.Pointer(ftyp)) - ins := *(*[]*_type)(unsafe.Pointer(&ft.in)) - if ft.dotdotdot || len(ins) != 1 { - gothrow("runtime.SetFinalizer: cannot pass " + *etyp._string + " to finalizer " + *ftyp._string) - } - fint := ins[0] - switch { - case fint == etyp: - // ok - same type - goto okarg - case fint.kind&kindMask == kindPtr: - if (fint.x == nil || fint.x.name == nil || etyp.x == nil || etyp.x.name == nil) && (*ptrtype)(unsafe.Pointer(fint)).elem == ot.elem { - // ok - not same type, but both pointers, - // one or the other is unnamed, and same element type, so assignable. - goto okarg - } - case fint.kind&kindMask == kindInterface: - ityp := (*interfacetype)(unsafe.Pointer(fint)) - if len(ityp.mhdr) == 0 { - // ok - satisfies empty interface - goto okarg - } - if _, ok := assertE2I2(ityp, obj); ok { - goto okarg - } - } - gothrow("runtime.SetFinalizer: cannot pass " + *etyp._string + " to finalizer " + *ftyp._string) -okarg: - // compute size needed for return parameters - nret := uintptr(0) - for _, t := range *(*[]*_type)(unsafe.Pointer(&ft.out)) { - nret = round(nret, uintptr(t.align)) + uintptr(t.size) - } - nret = round(nret, ptrSize) - - // make sure we have a finalizer goroutine - createfing() - - // switch to M stack to add finalizer record - mp := acquirem() - mp.ptrarg[0] = f.data - mp.ptrarg[1] = e.data - mp.scalararg[0] = nret - mp.ptrarg[2] = unsafe.Pointer(fint) - mp.ptrarg[3] = unsafe.Pointer(ot) - onM(setFinalizer_m) - if mp.scalararg[0] != 1 { - gothrow("runtime.SetFinalizer: finalizer already set") - } - releasem(mp) -} - -// round n up to a multiple of a. a must be a power of 2. -func round(n, a uintptr) uintptr { - return (n + a - 1) &^ (a - 1) -} - -// Look up pointer v in heap. Return the span containing the object, -// the start of the object, and the size of the object. If the object -// does not exist, return nil, nil, 0. -func findObject(v unsafe.Pointer) (s *mspan, x unsafe.Pointer, n uintptr) { - c := gomcache() - c.local_nlookup++ - if ptrSize == 4 && c.local_nlookup >= 1<<30 { - // purge cache stats to prevent overflow - lock(&mheap_.lock) - purgecachedstats(c) - unlock(&mheap_.lock) - } - - // find span - arena_start := uintptr(unsafe.Pointer(mheap_.arena_start)) - arena_used := uintptr(unsafe.Pointer(mheap_.arena_used)) - if uintptr(v) < arena_start || uintptr(v) >= arena_used { - return - } - p := uintptr(v) >> pageShift - q := p - arena_start>>pageShift - s = *(**mspan)(add(unsafe.Pointer(mheap_.spans), q*ptrSize)) - if s == nil { - return - } - x = unsafe.Pointer(uintptr(s.start) << pageShift) - - if uintptr(v) < uintptr(x) || uintptr(v) >= uintptr(unsafe.Pointer(s.limit)) || s.state != mSpanInUse { - s = nil - x = nil - return - } - - n = uintptr(s.elemsize) - if s.sizeclass != 0 { - x = add(x, (uintptr(v)-uintptr(x))/n*n) - } - return -} - -var fingCreate uint32 - -func createfing() { - // start the finalizer goroutine exactly once - if fingCreate == 0 && cas(&fingCreate, 0, 1) { - go runfinq() - } -} - -// This is the goroutine that runs all of the finalizers -func runfinq() { - var ( - frame unsafe.Pointer - framecap uintptr - ) - - for { - lock(&finlock) - fb := finq - finq = nil - if fb == nil { - gp := getg() - fing = gp - fingwait = true - gp.issystem = true - goparkunlock(&finlock, "finalizer wait") - gp.issystem = false - continue - } - unlock(&finlock) - if raceenabled { - racefingo() - } - for fb != nil { - for i := int32(0); i < fb.cnt; i++ { - f := (*finalizer)(add(unsafe.Pointer(&fb.fin), uintptr(i)*unsafe.Sizeof(finalizer{}))) - - framesz := unsafe.Sizeof((interface{})(nil)) + uintptr(f.nret) - if framecap < framesz { - // The frame does not contain pointers interesting for GC, - // all not yet finalized objects are stored in finq. - // If we do not mark it as FlagNoScan, - // the last finalized object is not collected. - frame = mallocgc(framesz, nil, flagNoScan) - framecap = framesz - } - - if f.fint == nil { - gothrow("missing type in runfinq") - } - switch f.fint.kind & kindMask { - case kindPtr: - // direct use of pointer - *(*unsafe.Pointer)(frame) = f.arg - case kindInterface: - ityp := (*interfacetype)(unsafe.Pointer(f.fint)) - // set up with empty interface - (*eface)(frame)._type = &f.ot.typ - (*eface)(frame).data = f.arg - if len(ityp.mhdr) != 0 { - // convert to interface with methods - // this conversion is guaranteed to succeed - we checked in SetFinalizer - *(*fInterface)(frame) = assertE2I(ityp, *(*interface{})(frame)) - } - default: - gothrow("bad kind in runfinq") - } - reflectcall(unsafe.Pointer(f.fn), frame, uint32(framesz), uint32(framesz)) - - // drop finalizer queue references to finalized object - f.fn = nil - f.arg = nil - f.ot = nil - } - fb.cnt = 0 - next := fb.next - lock(&finlock) - fb.next = finc - finc = fb - unlock(&finlock) - fb = next - } - } -} - -var persistent struct { - lock mutex - pos unsafe.Pointer - end unsafe.Pointer -} - -// Wrapper around sysAlloc that can allocate small chunks. -// There is no associated free operation. -// Intended for things like function/type/debug-related persistent data. -// If align is 0, uses default align (currently 8). -func persistentalloc(size, align uintptr, stat *uint64) unsafe.Pointer { - const ( - chunk = 256 << 10 - maxBlock = 64 << 10 // VM reservation granularity is 64K on windows - ) - - if align != 0 { - if align&(align-1) != 0 { - gothrow("persistentalloc: align is not a power of 2") - } - if align > _PageSize { - gothrow("persistentalloc: align is too large") - } - } else { - align = 8 - } - - if size >= maxBlock { - return sysAlloc(size, stat) - } - - lock(&persistent.lock) - persistent.pos = roundup(persistent.pos, align) - if uintptr(persistent.pos)+size > uintptr(persistent.end) { - persistent.pos = sysAlloc(chunk, &memstats.other_sys) - if persistent.pos == nil { - unlock(&persistent.lock) - gothrow("runtime: cannot allocate memory") - } - persistent.end = add(persistent.pos, chunk) - } - p := persistent.pos - persistent.pos = add(persistent.pos, size) - unlock(&persistent.lock) - - if stat != &memstats.other_sys { - xadd64(stat, int64(size)) - xadd64(&memstats.other_sys, -int64(size)) - } - return p -} diff --git a/libgo/go/runtime/malloc_test.go b/libgo/go/runtime/malloc_test.go index 054f6a7d744..df6a0e5246c 100644 --- a/libgo/go/runtime/malloc_test.go +++ b/libgo/go/runtime/malloc_test.go @@ -13,17 +13,74 @@ import ( ) func TestMemStats(t *testing.T) { + t.Skip("skipping test with gccgo") // Test that MemStats has sane values. st := new(MemStats) ReadMemStats(st) - if st.HeapSys == 0 || /* st.StackSys == 0 || */ st.MSpanSys == 0 || st.MCacheSys == 0 || - st.BuckHashSys == 0 || st.GCSys == 0 || st.OtherSys == 0 { - t.Fatalf("Zero sys value: %+v", *st) + + // Everything except HeapReleased and HeapIdle, because they indeed can be 0. + if st.Alloc == 0 || st.TotalAlloc == 0 || st.Sys == 0 || st.Lookups == 0 || + st.Mallocs == 0 || st.Frees == 0 || st.HeapAlloc == 0 || st.HeapSys == 0 || + st.HeapInuse == 0 || st.HeapObjects == 0 || st.StackInuse == 0 || + st.StackSys == 0 || st.MSpanInuse == 0 || st.MSpanSys == 0 || st.MCacheInuse == 0 || + st.MCacheSys == 0 || st.BuckHashSys == 0 || st.GCSys == 0 || st.OtherSys == 0 || + st.NextGC == 0 || st.NumGC == 0 { + t.Fatalf("Zero value: %+v", *st) + } + + if st.Alloc > 1e10 || st.TotalAlloc > 1e11 || st.Sys > 1e10 || st.Lookups > 1e10 || + st.Mallocs > 1e10 || st.Frees > 1e10 || st.HeapAlloc > 1e10 || st.HeapSys > 1e10 || + st.HeapIdle > 1e10 || st.HeapInuse > 1e10 || st.HeapObjects > 1e10 || st.StackInuse > 1e10 || + st.StackSys > 1e10 || st.MSpanInuse > 1e10 || st.MSpanSys > 1e10 || st.MCacheInuse > 1e10 || + st.MCacheSys > 1e10 || st.BuckHashSys > 1e10 || st.GCSys > 1e10 || st.OtherSys > 1e10 || + st.NextGC > 1e10 || st.NumGC > 1e9 || st.PauseTotalNs > 1e11 { + t.Fatalf("Insanely high value (overflow?): %+v", *st) } if st.Sys != st.HeapSys+st.StackSys+st.MSpanSys+st.MCacheSys+ st.BuckHashSys+st.GCSys+st.OtherSys { t.Fatalf("Bad sys value: %+v", *st) } + + if st.HeapIdle+st.HeapInuse != st.HeapSys { + t.Fatalf("HeapIdle(%d) + HeapInuse(%d) should be equal to HeapSys(%d), but isn't.", st.HeapIdle, st.HeapInuse, st.HeapSys) + } + + if lpe := st.PauseEnd[int(st.NumGC+255)%len(st.PauseEnd)]; st.LastGC != lpe { + t.Fatalf("LastGC(%d) != last PauseEnd(%d)", st.LastGC, lpe) + } + + var pauseTotal uint64 + for _, pause := range st.PauseNs { + pauseTotal += pause + } + if int(st.NumGC) < len(st.PauseNs) { + // We have all pauses, so this should be exact. + if st.PauseTotalNs != pauseTotal { + t.Fatalf("PauseTotalNs(%d) != sum PauseNs(%d)", st.PauseTotalNs, pauseTotal) + } + } else { + if st.PauseTotalNs < pauseTotal { + t.Fatalf("PauseTotalNs(%d) < sum PauseNs(%d)", st.PauseTotalNs, pauseTotal) + } + } +} + +func TestStringConcatenationAllocs(t *testing.T) { + t.Skip("skipping test with gccgo") + n := testing.AllocsPerRun(1e3, func() { + b := make([]byte, 10) + for i := 0; i < 10; i++ { + b[i] = byte(i) + '0' + } + s := "foo" + string(b) + if want := "foo0123456789"; s != want { + t.Fatalf("want %v, got %v", want, s) + } + }) + // Only string concatenation allocates. + if n != 1 { + t.Fatalf("want 1 allocation, got %v", n) + } } var mallocSink uintptr diff --git a/libgo/go/runtime/map_test.go b/libgo/go/runtime/map_test.go index 9ed183bb9d1..ed0347a453a 100644 --- a/libgo/go/runtime/map_test.go +++ b/libgo/go/runtime/map_test.go @@ -391,7 +391,7 @@ func TestMapNanGrowIterator(t *testing.T) { nan := math.NaN() const nBuckets = 16 // To fill nBuckets buckets takes LOAD * nBuckets keys. - nKeys := int(nBuckets * *runtime.HashLoad) + nKeys := int(nBuckets * /* *runtime.HashLoad */ 6.5) // Get map to full point with nan keys. for i := 0; i < nKeys; i++ { @@ -537,6 +537,61 @@ func TestMapStringBytesLookup(t *testing.T) { } } +func TestMapLargeKeyNoPointer(t *testing.T) { + const ( + I = 1000 + N = 64 + ) + type T [N]int + m := make(map[T]int) + for i := 0; i < I; i++ { + var v T + for j := 0; j < N; j++ { + v[j] = i + j + } + m[v] = i + } + runtime.GC() + for i := 0; i < I; i++ { + var v T + for j := 0; j < N; j++ { + v[j] = i + j + } + if m[v] != i { + t.Fatalf("corrupted map: want %+v, got %+v", i, m[v]) + } + } +} + +func TestMapLargeValNoPointer(t *testing.T) { + const ( + I = 1000 + N = 64 + ) + type T [N]int + m := make(map[int]T) + for i := 0; i < I; i++ { + var v T + for j := 0; j < N; j++ { + v[j] = i + j + } + m[i] = v + } + runtime.GC() + for i := 0; i < I; i++ { + var v T + for j := 0; j < N; j++ { + v[j] = i + j + } + v1 := m[i] + for j := 0; j < N; j++ { + if v1[j] != v[j] { + t.Fatalf("corrupted map: want %+v, got %+v", v, v1) + } + } + } +} + func benchmarkMapPop(b *testing.B, n int) { m := map[int]int{} for i := 0; i < b.N; i++ { @@ -557,3 +612,14 @@ func benchmarkMapPop(b *testing.B, n int) { func BenchmarkMapPop100(b *testing.B) { benchmarkMapPop(b, 100) } func BenchmarkMapPop1000(b *testing.B) { benchmarkMapPop(b, 1000) } func BenchmarkMapPop10000(b *testing.B) { benchmarkMapPop(b, 10000) } + +func TestNonEscapingMap(t *testing.T) { + t.Skip("does not work on gccgo without better escape analysis") + n := testing.AllocsPerRun(1000, func() { + m := make(map[int]int) + m[0] = 0 + }) + if n != 0 { + t.Fatalf("want 0 allocs, got %v", n) + } +} diff --git a/libgo/go/runtime/mapspeed_test.go b/libgo/go/runtime/mapspeed_test.go index 119eb3f39c7..ac93119d77d 100644 --- a/libgo/go/runtime/mapspeed_test.go +++ b/libgo/go/runtime/mapspeed_test.go @@ -234,6 +234,15 @@ func BenchmarkNewEmptyMap(b *testing.B) { } } +func BenchmarkNewSmallMap(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + m := make(map[int]int) + m[0] = 0 + m[1] = 1 + } +} + func BenchmarkMapIter(b *testing.B) { m := make(map[int]bool) for i := 0; i < 8; i++ { @@ -298,3 +307,22 @@ func BenchmarkSmallKeyMap(b *testing.B) { _ = m[5] } } + +type ComplexAlgKey struct { + a, b, c int64 + _ int + d int32 + _ int + e string + _ int + f, g, h int64 +} + +func BenchmarkComplexAlgMap(b *testing.B) { + m := make(map[ComplexAlgKey]bool) + var k ComplexAlgKey + m[k] = true + for i := 0; i < b.N; i++ { + _ = m[k] + } +} diff --git a/libgo/go/runtime/mem.go b/libgo/go/runtime/mem.go index fb35535c3a3..b41d741b93d 100644 --- a/libgo/go/runtime/mem.go +++ b/libgo/go/runtime/mem.go @@ -41,13 +41,15 @@ type MemStats struct { OtherSys uint64 // other system allocations // Garbage collector statistics. - NextGC uint64 // next run in HeapAlloc time (bytes) - LastGC uint64 // last run in absolute time (ns) - PauseTotalNs uint64 - PauseNs [256]uint64 // circular buffer of recent GC pause times, most recent at [(NumGC+255)%256] - NumGC uint32 - EnableGC bool - DebugGC bool + NextGC uint64 // next run in HeapAlloc time (bytes) + LastGC uint64 // last run in absolute time (ns) + PauseTotalNs uint64 + PauseNs [256]uint64 // circular buffer of recent GC pause times, most recent at [(NumGC+255)%256] + PauseEnd [256]uint64 // circular buffer of recent GC pause end times + NumGC uint32 + GCCPUFraction float64 // fraction of CPU time used by GC + EnableGC bool + DebugGC bool // Per-size allocation statistics. // 61 is NumSizeClasses in the C code. diff --git a/libgo/go/runtime/memmove_test.go b/libgo/go/runtime/memmove_test.go deleted file mode 100644 index ffda4fe6c53..00000000000 --- a/libgo/go/runtime/memmove_test.go +++ /dev/null @@ -1,295 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime_test - -import ( - . "runtime" - "testing" -) - -func TestMemmove(t *testing.T) { - size := 256 - if testing.Short() { - size = 128 + 16 - } - src := make([]byte, size) - dst := make([]byte, size) - for i := 0; i < size; i++ { - src[i] = byte(128 + (i & 127)) - } - for i := 0; i < size; i++ { - dst[i] = byte(i & 127) - } - for n := 0; n <= size; n++ { - for x := 0; x <= size-n; x++ { // offset in src - for y := 0; y <= size-n; y++ { // offset in dst - copy(dst[y:y+n], src[x:x+n]) - for i := 0; i < y; i++ { - if dst[i] != byte(i&127) { - t.Fatalf("prefix dst[%d] = %d", i, dst[i]) - } - } - for i := y; i < y+n; i++ { - if dst[i] != byte(128+((i-y+x)&127)) { - t.Fatalf("copied dst[%d] = %d", i, dst[i]) - } - dst[i] = byte(i & 127) // reset dst - } - for i := y + n; i < size; i++ { - if dst[i] != byte(i&127) { - t.Fatalf("suffix dst[%d] = %d", i, dst[i]) - } - } - } - } - } -} - -func TestMemmoveAlias(t *testing.T) { - size := 256 - if testing.Short() { - size = 128 + 16 - } - buf := make([]byte, size) - for i := 0; i < size; i++ { - buf[i] = byte(i) - } - for n := 0; n <= size; n++ { - for x := 0; x <= size-n; x++ { // src offset - for y := 0; y <= size-n; y++ { // dst offset - copy(buf[y:y+n], buf[x:x+n]) - for i := 0; i < y; i++ { - if buf[i] != byte(i) { - t.Fatalf("prefix buf[%d] = %d", i, buf[i]) - } - } - for i := y; i < y+n; i++ { - if buf[i] != byte(i-y+x) { - t.Fatalf("copied buf[%d] = %d", i, buf[i]) - } - buf[i] = byte(i) // reset buf - } - for i := y + n; i < size; i++ { - if buf[i] != byte(i) { - t.Fatalf("suffix buf[%d] = %d", i, buf[i]) - } - } - } - } - } -} - -func bmMemmove(b *testing.B, n int) { - x := make([]byte, n) - y := make([]byte, n) - b.SetBytes(int64(n)) - for i := 0; i < b.N; i++ { - copy(x, y) - } -} - -func BenchmarkMemmove0(b *testing.B) { bmMemmove(b, 0) } -func BenchmarkMemmove1(b *testing.B) { bmMemmove(b, 1) } -func BenchmarkMemmove2(b *testing.B) { bmMemmove(b, 2) } -func BenchmarkMemmove3(b *testing.B) { bmMemmove(b, 3) } -func BenchmarkMemmove4(b *testing.B) { bmMemmove(b, 4) } -func BenchmarkMemmove5(b *testing.B) { bmMemmove(b, 5) } -func BenchmarkMemmove6(b *testing.B) { bmMemmove(b, 6) } -func BenchmarkMemmove7(b *testing.B) { bmMemmove(b, 7) } -func BenchmarkMemmove8(b *testing.B) { bmMemmove(b, 8) } -func BenchmarkMemmove9(b *testing.B) { bmMemmove(b, 9) } -func BenchmarkMemmove10(b *testing.B) { bmMemmove(b, 10) } -func BenchmarkMemmove11(b *testing.B) { bmMemmove(b, 11) } -func BenchmarkMemmove12(b *testing.B) { bmMemmove(b, 12) } -func BenchmarkMemmove13(b *testing.B) { bmMemmove(b, 13) } -func BenchmarkMemmove14(b *testing.B) { bmMemmove(b, 14) } -func BenchmarkMemmove15(b *testing.B) { bmMemmove(b, 15) } -func BenchmarkMemmove16(b *testing.B) { bmMemmove(b, 16) } -func BenchmarkMemmove32(b *testing.B) { bmMemmove(b, 32) } -func BenchmarkMemmove64(b *testing.B) { bmMemmove(b, 64) } -func BenchmarkMemmove128(b *testing.B) { bmMemmove(b, 128) } -func BenchmarkMemmove256(b *testing.B) { bmMemmove(b, 256) } -func BenchmarkMemmove512(b *testing.B) { bmMemmove(b, 512) } -func BenchmarkMemmove1024(b *testing.B) { bmMemmove(b, 1024) } -func BenchmarkMemmove2048(b *testing.B) { bmMemmove(b, 2048) } -func BenchmarkMemmove4096(b *testing.B) { bmMemmove(b, 4096) } - -func TestMemclr(t *testing.T) { - size := 512 - if testing.Short() { - size = 128 + 16 - } - mem := make([]byte, size) - for i := 0; i < size; i++ { - mem[i] = 0xee - } - for n := 0; n < size; n++ { - for x := 0; x <= size-n; x++ { // offset in mem - MemclrBytes(mem[x : x+n]) - for i := 0; i < x; i++ { - if mem[i] != 0xee { - t.Fatalf("overwrite prefix mem[%d] = %d", i, mem[i]) - } - } - for i := x; i < x+n; i++ { - if mem[i] != 0 { - t.Fatalf("failed clear mem[%d] = %d", i, mem[i]) - } - mem[i] = 0xee - } - for i := x + n; i < size; i++ { - if mem[i] != 0xee { - t.Fatalf("overwrite suffix mem[%d] = %d", i, mem[i]) - } - } - } - } -} - -func bmMemclr(b *testing.B, n int) { - x := make([]byte, n) - b.SetBytes(int64(n)) - for i := 0; i < b.N; i++ { - MemclrBytes(x) - } -} -func BenchmarkMemclr5(b *testing.B) { bmMemclr(b, 5) } -func BenchmarkMemclr16(b *testing.B) { bmMemclr(b, 16) } -func BenchmarkMemclr64(b *testing.B) { bmMemclr(b, 64) } -func BenchmarkMemclr256(b *testing.B) { bmMemclr(b, 256) } -func BenchmarkMemclr4096(b *testing.B) { bmMemclr(b, 4096) } -func BenchmarkMemclr65536(b *testing.B) { bmMemclr(b, 65536) } - -func BenchmarkClearFat8(b *testing.B) { - for i := 0; i < b.N; i++ { - var x [8 / 4]uint32 - _ = x - } -} -func BenchmarkClearFat12(b *testing.B) { - for i := 0; i < b.N; i++ { - var x [12 / 4]uint32 - _ = x - } -} -func BenchmarkClearFat16(b *testing.B) { - for i := 0; i < b.N; i++ { - var x [16 / 4]uint32 - _ = x - } -} -func BenchmarkClearFat24(b *testing.B) { - for i := 0; i < b.N; i++ { - var x [24 / 4]uint32 - _ = x - } -} -func BenchmarkClearFat32(b *testing.B) { - for i := 0; i < b.N; i++ { - var x [32 / 4]uint32 - _ = x - } -} -func BenchmarkClearFat64(b *testing.B) { - for i := 0; i < b.N; i++ { - var x [64 / 4]uint32 - _ = x - } -} -func BenchmarkClearFat128(b *testing.B) { - for i := 0; i < b.N; i++ { - var x [128 / 4]uint32 - _ = x - } -} -func BenchmarkClearFat256(b *testing.B) { - for i := 0; i < b.N; i++ { - var x [256 / 4]uint32 - _ = x - } -} -func BenchmarkClearFat512(b *testing.B) { - for i := 0; i < b.N; i++ { - var x [512 / 4]uint32 - _ = x - } -} -func BenchmarkClearFat1024(b *testing.B) { - for i := 0; i < b.N; i++ { - var x [1024 / 4]uint32 - _ = x - } -} - -func BenchmarkCopyFat8(b *testing.B) { - var x [8 / 4]uint32 - for i := 0; i < b.N; i++ { - y := x - _ = y - } -} -func BenchmarkCopyFat12(b *testing.B) { - var x [12 / 4]uint32 - for i := 0; i < b.N; i++ { - y := x - _ = y - } -} -func BenchmarkCopyFat16(b *testing.B) { - var x [16 / 4]uint32 - for i := 0; i < b.N; i++ { - y := x - _ = y - } -} -func BenchmarkCopyFat24(b *testing.B) { - var x [24 / 4]uint32 - for i := 0; i < b.N; i++ { - y := x - _ = y - } -} -func BenchmarkCopyFat32(b *testing.B) { - var x [32 / 4]uint32 - for i := 0; i < b.N; i++ { - y := x - _ = y - } -} -func BenchmarkCopyFat64(b *testing.B) { - var x [64 / 4]uint32 - for i := 0; i < b.N; i++ { - y := x - _ = y - } -} -func BenchmarkCopyFat128(b *testing.B) { - var x [128 / 4]uint32 - for i := 0; i < b.N; i++ { - y := x - _ = y - } -} -func BenchmarkCopyFat256(b *testing.B) { - var x [256 / 4]uint32 - for i := 0; i < b.N; i++ { - y := x - _ = y - } -} -func BenchmarkCopyFat512(b *testing.B) { - var x [512 / 4]uint32 - for i := 0; i < b.N; i++ { - y := x - _ = y - } -} -func BenchmarkCopyFat1024(b *testing.B) { - var x [1024 / 4]uint32 - for i := 0; i < b.N; i++ { - y := x - _ = y - } -} diff --git a/libgo/go/runtime/mfinal_test.go b/libgo/go/runtime/mfinal_test.go index ab7c8aefb3f..38c2623bb7b 100644 --- a/libgo/go/runtime/mfinal_test.go +++ b/libgo/go/runtime/mfinal_test.go @@ -177,9 +177,6 @@ func adjChunks() (*objtype, *objtype) { // Make sure an empty slice on the stack doesn't pin the next object in memory. func TestEmptySlice(t *testing.T) { - if true { // disable until bug 7564 is fixed. - return - } if runtime.Compiler == "gccgo" { t.Skip("skipping for gccgo") } diff --git a/libgo/go/runtime/mgc0.go b/libgo/go/runtime/mgc0.go deleted file mode 100644 index cbf5e9cfdef..00000000000 --- a/libgo/go/runtime/mgc0.go +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -import "unsafe" - -// Called from C. Returns the Go type *m. -func gc_m_ptr(ret *interface{}) { - *ret = (*m)(nil) -} - -// Called from C. Returns the Go type *g. -func gc_g_ptr(ret *interface{}) { - *ret = (*g)(nil) -} - -// Called from C. Returns the Go type *itab. -func gc_itab_ptr(ret *interface{}) { - *ret = (*itab)(nil) -} - -func gc_unixnanotime(now *int64) { - sec, nsec := timenow() - *now = sec*1e9 + int64(nsec) -} - -func freeOSMemory() { - gogc(2) // force GC and do eager sweep - onM(scavenge_m) -} - -var poolcleanup func() - -func registerPoolCleanup(f func()) { - poolcleanup = f -} - -func clearpools() { - // clear sync.Pools - if poolcleanup != nil { - poolcleanup() - } - - for _, p := range &allp { - if p == nil { - break - } - // clear tinyalloc pool - if c := p.mcache; c != nil { - c.tiny = nil - c.tinysize = 0 - - // disconnect cached list before dropping it on the floor, - // so that a dangling ref to one entry does not pin all of them. - var sg, sgnext *sudog - for sg = c.sudogcache; sg != nil; sg = sgnext { - sgnext = sg.next - sg.next = nil - } - c.sudogcache = nil - } - - // clear defer pools - for i := range p.deferpool { - // disconnect cached list before dropping it on the floor, - // so that a dangling ref to one entry does not pin all of them. - var d, dlink *_defer - for d = p.deferpool[i]; d != nil; d = dlink { - dlink = d.link - d.link = nil - } - p.deferpool[i] = nil - } - } -} - -func gosweepone() uintptr -func gosweepdone() bool - -func bgsweep() { - getg().issystem = true - for { - for gosweepone() != ^uintptr(0) { - sweep.nbgsweep++ - Gosched() - } - lock(&gclock) - if !gosweepdone() { - // This can happen if a GC runs between - // gosweepone returning ^0 above - // and the lock being acquired. - unlock(&gclock) - continue - } - sweep.parked = true - goparkunlock(&gclock, "GC sweep wait") - } -} - -// NOTE: Really dst *unsafe.Pointer, src unsafe.Pointer, -// but if we do that, Go inserts a write barrier on *dst = src. -//go:nosplit -func writebarrierptr(dst *uintptr, src uintptr) { - *dst = src -} - -//go:nosplit -func writebarrierstring(dst *[2]uintptr, src [2]uintptr) { - dst[0] = src[0] - dst[1] = src[1] -} - -//go:nosplit -func writebarrierslice(dst *[3]uintptr, src [3]uintptr) { - dst[0] = src[0] - dst[1] = src[1] - dst[2] = src[2] -} - -//go:nosplit -func writebarrieriface(dst *[2]uintptr, src [2]uintptr) { - dst[0] = src[0] - dst[1] = src[1] -} - -//go:nosplit -func writebarrierfat2(dst *[2]uintptr, _ *byte, src [2]uintptr) { - dst[0] = src[0] - dst[1] = src[1] -} - -//go:nosplit -func writebarrierfat3(dst *[3]uintptr, _ *byte, src [3]uintptr) { - dst[0] = src[0] - dst[1] = src[1] - dst[2] = src[2] -} - -//go:nosplit -func writebarrierfat4(dst *[4]uintptr, _ *byte, src [4]uintptr) { - dst[0] = src[0] - dst[1] = src[1] - dst[2] = src[2] - dst[3] = src[3] -} - -//go:nosplit -func writebarrierfat(typ *_type, dst, src unsafe.Pointer) { - memmove(dst, src, typ.size) -} diff --git a/libgo/go/runtime/mprof.go b/libgo/go/runtime/mprof.go deleted file mode 100644 index f4da45f5c30..00000000000 --- a/libgo/go/runtime/mprof.go +++ /dev/null @@ -1,668 +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. - -// Malloc profiling. -// Patterned after tcmalloc's algorithms; shorter code. - -package runtime - -import ( - "unsafe" -) - -// NOTE(rsc): Everything here could use cas if contention became an issue. -var proflock mutex - -// All memory allocations are local and do not escape outside of the profiler. -// The profiler is forbidden from referring to garbage-collected memory. - -const ( - // profile types - memProfile bucketType = 1 + iota - blockProfile - - // size of bucket hash table - buckHashSize = 179999 - - // max depth of stack to record in bucket - maxStack = 32 -) - -type bucketType int - -// A bucket holds per-call-stack profiling information. -// The representation is a bit sleazy, inherited from C. -// This struct defines the bucket header. It is followed in -// memory by the stack words and then the actual record -// data, either a memRecord or a blockRecord. -// -// Per-call-stack profiling information. -// Lookup by hashing call stack into a linked-list hash table. -type bucket struct { - next *bucket - allnext *bucket - typ bucketType // memBucket or blockBucket - hash uintptr - size uintptr - nstk uintptr -} - -// A memRecord is the bucket data for a bucket of type memProfile, -// part of the memory profile. -type memRecord struct { - // The following complex 3-stage scheme of stats accumulation - // is required to obtain a consistent picture of mallocs and frees - // for some point in time. - // The problem is that mallocs come in real time, while frees - // come only after a GC during concurrent sweeping. So if we would - // naively count them, we would get a skew toward mallocs. - // - // Mallocs are accounted in recent stats. - // Explicit frees are accounted in recent stats. - // GC frees are accounted in prev stats. - // After GC prev stats are added to final stats and - // recent stats are moved into prev stats. - allocs uintptr - frees uintptr - alloc_bytes uintptr - free_bytes uintptr - - // changes between next-to-last GC and last GC - prev_allocs uintptr - prev_frees uintptr - prev_alloc_bytes uintptr - prev_free_bytes uintptr - - // changes since last GC - recent_allocs uintptr - recent_frees uintptr - recent_alloc_bytes uintptr - recent_free_bytes uintptr -} - -// A blockRecord is the bucket data for a bucket of type blockProfile, -// part of the blocking profile. -type blockRecord struct { - count int64 - cycles int64 -} - -var ( - mbuckets *bucket // memory profile buckets - bbuckets *bucket // blocking profile buckets - buckhash *[179999]*bucket - bucketmem uintptr -) - -// newBucket allocates a bucket with the given type and number of stack entries. -func newBucket(typ bucketType, nstk int) *bucket { - size := unsafe.Sizeof(bucket{}) + uintptr(nstk)*unsafe.Sizeof(uintptr(0)) - switch typ { - default: - gothrow("invalid profile bucket type") - case memProfile: - size += unsafe.Sizeof(memRecord{}) - case blockProfile: - size += unsafe.Sizeof(blockRecord{}) - } - - b := (*bucket)(persistentalloc(size, 0, &memstats.buckhash_sys)) - bucketmem += size - b.typ = typ - b.nstk = uintptr(nstk) - return b -} - -// stk returns the slice in b holding the stack. -func (b *bucket) stk() []uintptr { - stk := (*[maxStack]uintptr)(add(unsafe.Pointer(b), unsafe.Sizeof(*b))) - return stk[:b.nstk:b.nstk] -} - -// mp returns the memRecord associated with the memProfile bucket b. -func (b *bucket) mp() *memRecord { - if b.typ != memProfile { - gothrow("bad use of bucket.mp") - } - data := add(unsafe.Pointer(b), unsafe.Sizeof(*b)+b.nstk*unsafe.Sizeof(uintptr(0))) - return (*memRecord)(data) -} - -// bp returns the blockRecord associated with the blockProfile bucket b. -func (b *bucket) bp() *blockRecord { - if b.typ != blockProfile { - gothrow("bad use of bucket.bp") - } - data := add(unsafe.Pointer(b), unsafe.Sizeof(*b)+b.nstk*unsafe.Sizeof(uintptr(0))) - return (*blockRecord)(data) -} - -// Return the bucket for stk[0:nstk], allocating new bucket if needed. -func stkbucket(typ bucketType, size uintptr, stk []uintptr, alloc bool) *bucket { - if buckhash == nil { - buckhash = (*[buckHashSize]*bucket)(sysAlloc(unsafe.Sizeof(*buckhash), &memstats.buckhash_sys)) - if buckhash == nil { - gothrow("runtime: cannot allocate memory") - } - } - - // Hash stack. - var h uintptr - for _, pc := range stk { - h += pc - h += h << 10 - h ^= h >> 6 - } - // hash in size - h += size - h += h << 10 - h ^= h >> 6 - // finalize - h += h << 3 - h ^= h >> 11 - - i := int(h % buckHashSize) - for b := buckhash[i]; b != nil; b = b.next { - if b.typ == typ && b.hash == h && b.size == size && eqslice(b.stk(), stk) { - return b - } - } - - if !alloc { - return nil - } - - // Create new bucket. - b := newBucket(typ, len(stk)) - copy(b.stk(), stk) - b.hash = h - b.size = size - b.next = buckhash[i] - buckhash[i] = b - if typ == memProfile { - b.allnext = mbuckets - mbuckets = b - } else { - b.allnext = bbuckets - bbuckets = b - } - return b -} - -func sysAlloc(n uintptr, stat *uint64) unsafe.Pointer - -func eqslice(x, y []uintptr) bool { - if len(x) != len(y) { - return false - } - for i, xi := range x { - if xi != y[i] { - return false - } - } - return true -} - -func mprof_GC() { - for b := mbuckets; b != nil; b = b.allnext { - mp := b.mp() - mp.allocs += mp.prev_allocs - mp.frees += mp.prev_frees - mp.alloc_bytes += mp.prev_alloc_bytes - mp.free_bytes += mp.prev_free_bytes - - mp.prev_allocs = mp.recent_allocs - mp.prev_frees = mp.recent_frees - mp.prev_alloc_bytes = mp.recent_alloc_bytes - mp.prev_free_bytes = mp.recent_free_bytes - - mp.recent_allocs = 0 - mp.recent_frees = 0 - mp.recent_alloc_bytes = 0 - mp.recent_free_bytes = 0 - } -} - -// Record that a gc just happened: all the 'recent' statistics are now real. -func mProf_GC() { - lock(&proflock) - mprof_GC() - unlock(&proflock) -} - -// Called by malloc to record a profiled block. -func mProf_Malloc(p unsafe.Pointer, size uintptr) { - var stk [maxStack]uintptr - nstk := callers(4, &stk[0], len(stk)) - lock(&proflock) - b := stkbucket(memProfile, size, stk[:nstk], true) - mp := b.mp() - mp.recent_allocs++ - mp.recent_alloc_bytes += size - unlock(&proflock) - - // Setprofilebucket locks a bunch of other mutexes, so we call it outside of proflock. - // This reduces potential contention and chances of deadlocks. - // Since the object must be alive during call to mProf_Malloc, - // it's fine to do this non-atomically. - setprofilebucket(p, b) -} - -func setprofilebucket_m() // mheap.c - -func setprofilebucket(p unsafe.Pointer, b *bucket) { - g := getg() - g.m.ptrarg[0] = p - g.m.ptrarg[1] = unsafe.Pointer(b) - onM(setprofilebucket_m) -} - -// Called when freeing a profiled block. -func mProf_Free(b *bucket, size uintptr, freed bool) { - lock(&proflock) - mp := b.mp() - if freed { - mp.recent_frees++ - mp.recent_free_bytes += size - } else { - mp.prev_frees++ - mp.prev_free_bytes += size - } - unlock(&proflock) -} - -var blockprofilerate uint64 // in CPU ticks - -// SetBlockProfileRate controls the fraction of goroutine blocking events -// that are reported in the blocking profile. The profiler aims to sample -// an average of one blocking event per rate nanoseconds spent blocked. -// -// To include every blocking event in the profile, pass rate = 1. -// To turn off profiling entirely, pass rate <= 0. -func SetBlockProfileRate(rate int) { - var r int64 - if rate <= 0 { - r = 0 // disable profiling - } else if rate == 1 { - r = 1 // profile everything - } else { - // convert ns to cycles, use float64 to prevent overflow during multiplication - r = int64(float64(rate) * float64(tickspersecond()) / (1000 * 1000 * 1000)) - if r == 0 { - r = 1 - } - } - - atomicstore64(&blockprofilerate, uint64(r)) -} - -func blockevent(cycles int64, skip int) { - if cycles <= 0 { - cycles = 1 - } - rate := int64(atomicload64(&blockprofilerate)) - if rate <= 0 || (rate > cycles && int64(fastrand1())%rate > cycles) { - return - } - gp := getg() - var nstk int - var stk [maxStack]uintptr - if gp.m.curg == nil || gp.m.curg == gp { - nstk = callers(skip, &stk[0], len(stk)) - } else { - nstk = gcallers(gp.m.curg, skip, &stk[0], len(stk)) - } - lock(&proflock) - b := stkbucket(blockProfile, 0, stk[:nstk], true) - b.bp().count++ - b.bp().cycles += cycles - unlock(&proflock) -} - -// Go interface to profile data. - -// A StackRecord describes a single execution stack. -type StackRecord struct { - Stack0 [32]uintptr // stack trace for this record; ends at first 0 entry -} - -// Stack returns the stack trace associated with the record, -// a prefix of r.Stack0. -func (r *StackRecord) Stack() []uintptr { - for i, v := range r.Stack0 { - if v == 0 { - return r.Stack0[0:i] - } - } - return r.Stack0[0:] -} - -// MemProfileRate controls the fraction of memory allocations -// that are recorded and reported in the memory profile. -// The profiler aims to sample an average of -// one allocation per MemProfileRate bytes allocated. -// -// To include every allocated block in the profile, set MemProfileRate to 1. -// To turn off profiling entirely, set MemProfileRate to 0. -// -// The tools that process the memory profiles assume that the -// profile rate is constant across the lifetime of the program -// and equal to the current value. Programs that change the -// memory profiling rate should do so just once, as early as -// possible in the execution of the program (for example, -// at the beginning of main). -var MemProfileRate int = 512 * 1024 - -// A MemProfileRecord describes the live objects allocated -// by a particular call sequence (stack trace). -type MemProfileRecord struct { - AllocBytes, FreeBytes int64 // number of bytes allocated, freed - AllocObjects, FreeObjects int64 // number of objects allocated, freed - Stack0 [32]uintptr // stack trace for this record; ends at first 0 entry -} - -// InUseBytes returns the number of bytes in use (AllocBytes - FreeBytes). -func (r *MemProfileRecord) InUseBytes() int64 { return r.AllocBytes - r.FreeBytes } - -// InUseObjects returns the number of objects in use (AllocObjects - FreeObjects). -func (r *MemProfileRecord) InUseObjects() int64 { - return r.AllocObjects - r.FreeObjects -} - -// Stack returns the stack trace associated with the record, -// a prefix of r.Stack0. -func (r *MemProfileRecord) Stack() []uintptr { - for i, v := range r.Stack0 { - if v == 0 { - return r.Stack0[0:i] - } - } - return r.Stack0[0:] -} - -// MemProfile returns n, the number of records in the current memory profile. -// If len(p) >= n, MemProfile copies the profile into p and returns n, true. -// If len(p) < n, MemProfile does not change p and returns n, false. -// -// If inuseZero is true, the profile includes allocation records -// where r.AllocBytes > 0 but r.AllocBytes == r.FreeBytes. -// These are sites where memory was allocated, but it has all -// been released back to the runtime. -// -// Most clients should use the runtime/pprof package or -// the testing package's -test.memprofile flag instead -// of calling MemProfile directly. -func MemProfile(p []MemProfileRecord, inuseZero bool) (n int, ok bool) { - lock(&proflock) - clear := true - for b := mbuckets; b != nil; b = b.allnext { - mp := b.mp() - if inuseZero || mp.alloc_bytes != mp.free_bytes { - n++ - } - if mp.allocs != 0 || mp.frees != 0 { - clear = false - } - } - if clear { - // Absolutely no data, suggesting that a garbage collection - // has not yet happened. In order to allow profiling when - // garbage collection is disabled from the beginning of execution, - // accumulate stats as if a GC just happened, and recount buckets. - mprof_GC() - mprof_GC() - n = 0 - for b := mbuckets; b != nil; b = b.allnext { - mp := b.mp() - if inuseZero || mp.alloc_bytes != mp.free_bytes { - n++ - } - } - } - if n <= len(p) { - ok = true - idx := 0 - for b := mbuckets; b != nil; b = b.allnext { - mp := b.mp() - if inuseZero || mp.alloc_bytes != mp.free_bytes { - record(&p[idx], b) - idx++ - } - } - } - unlock(&proflock) - return -} - -// Write b's data to r. -func record(r *MemProfileRecord, b *bucket) { - mp := b.mp() - r.AllocBytes = int64(mp.alloc_bytes) - r.FreeBytes = int64(mp.free_bytes) - r.AllocObjects = int64(mp.allocs) - r.FreeObjects = int64(mp.frees) - copy(r.Stack0[:], b.stk()) - for i := int(b.nstk); i < len(r.Stack0); i++ { - r.Stack0[i] = 0 - } -} - -func iterate_memprof(fn func(*bucket, uintptr, *uintptr, uintptr, uintptr, uintptr)) { - lock(&proflock) - for b := mbuckets; b != nil; b = b.allnext { - mp := b.mp() - fn(b, uintptr(b.nstk), &b.stk()[0], b.size, mp.allocs, mp.frees) - } - unlock(&proflock) -} - -// BlockProfileRecord describes blocking events originated -// at a particular call sequence (stack trace). -type BlockProfileRecord struct { - Count int64 - Cycles int64 - StackRecord -} - -// BlockProfile returns n, the number of records in the current blocking profile. -// If len(p) >= n, BlockProfile copies the profile into p and returns n, true. -// If len(p) < n, BlockProfile does not change p and returns n, false. -// -// Most clients should use the runtime/pprof package or -// the testing package's -test.blockprofile flag instead -// of calling BlockProfile directly. -func BlockProfile(p []BlockProfileRecord) (n int, ok bool) { - lock(&proflock) - for b := bbuckets; b != nil; b = b.allnext { - n++ - } - if n <= len(p) { - ok = true - for b := bbuckets; b != nil; b = b.allnext { - bp := b.bp() - r := &p[0] - r.Count = int64(bp.count) - r.Cycles = int64(bp.cycles) - i := copy(r.Stack0[:], b.stk()) - for ; i < len(r.Stack0); i++ { - r.Stack0[i] = 0 - } - p = p[1:] - } - } - unlock(&proflock) - return -} - -// ThreadCreateProfile returns n, the number of records in the thread creation profile. -// If len(p) >= n, ThreadCreateProfile copies the profile into p and returns n, true. -// If len(p) < n, ThreadCreateProfile does not change p and returns n, false. -// -// Most clients should use the runtime/pprof package instead -// of calling ThreadCreateProfile directly. -func ThreadCreateProfile(p []StackRecord) (n int, ok bool) { - first := (*m)(atomicloadp(unsafe.Pointer(&allm))) - for mp := first; mp != nil; mp = mp.alllink { - n++ - } - if n <= len(p) { - ok = true - i := 0 - for mp := first; mp != nil; mp = mp.alllink { - for s := range mp.createstack { - p[i].Stack0[s] = uintptr(mp.createstack[s]) - } - i++ - } - } - return -} - -var allgs []*g // proc.c - -// GoroutineProfile returns n, the number of records in the active goroutine stack profile. -// If len(p) >= n, GoroutineProfile copies the profile into p and returns n, true. -// If len(p) < n, GoroutineProfile does not change p and returns n, false. -// -// Most clients should use the runtime/pprof package instead -// of calling GoroutineProfile directly. -func GoroutineProfile(p []StackRecord) (n int, ok bool) { - - n = NumGoroutine() - if n <= len(p) { - gp := getg() - semacquire(&worldsema, false) - gp.m.gcing = 1 - onM(stoptheworld) - - n = NumGoroutine() - if n <= len(p) { - ok = true - r := p - sp := getcallersp(unsafe.Pointer(&p)) - pc := getcallerpc(unsafe.Pointer(&p)) - onM(func() { - saveg(pc, sp, gp, &r[0]) - }) - r = r[1:] - for _, gp1 := range allgs { - if gp1 == gp || readgstatus(gp1) == _Gdead { - continue - } - saveg(^uintptr(0), ^uintptr(0), gp1, &r[0]) - r = r[1:] - } - } - - gp.m.gcing = 0 - semrelease(&worldsema) - onM(starttheworld) - } - - return n, ok -} - -func saveg(pc, sp uintptr, gp *g, r *StackRecord) { - n := gentraceback(pc, sp, 0, gp, 0, &r.Stack0[0], len(r.Stack0), nil, nil, 0) - if n < len(r.Stack0) { - r.Stack0[n] = 0 - } -} - -// Stack formats a stack trace of the calling goroutine into buf -// and returns the number of bytes written to buf. -// If all is true, Stack formats stack traces of all other goroutines -// into buf after the trace for the current goroutine. -func Stack(buf []byte, all bool) int { - if all { - semacquire(&worldsema, false) - gp := getg() - gp.m.gcing = 1 - onM(stoptheworld) - } - - n := 0 - if len(buf) > 0 { - gp := getg() - sp := getcallersp(unsafe.Pointer(&buf)) - pc := getcallerpc(unsafe.Pointer(&buf)) - onM(func() { - g0 := getg() - g0.writebuf = buf[0:0:len(buf)] - goroutineheader(gp) - traceback(pc, sp, 0, gp) - if all { - tracebackothers(gp) - } - n = len(g0.writebuf) - g0.writebuf = nil - }) - } - - if all { - gp := getg() - gp.m.gcing = 0 - semrelease(&worldsema) - onM(starttheworld) - } - return n -} - -// Tracing of alloc/free/gc. - -var tracelock mutex - -func tracealloc(p unsafe.Pointer, size uintptr, typ *_type) { - lock(&tracelock) - gp := getg() - gp.m.traceback = 2 - if typ == nil { - print("tracealloc(", p, ", ", hex(size), ")\n") - } else { - print("tracealloc(", p, ", ", hex(size), ", ", *typ._string, ")\n") - } - if gp.m.curg == nil || gp == gp.m.curg { - goroutineheader(gp) - pc := getcallerpc(unsafe.Pointer(&p)) - sp := getcallersp(unsafe.Pointer(&p)) - onM(func() { - traceback(pc, sp, 0, gp) - }) - } else { - goroutineheader(gp.m.curg) - traceback(^uintptr(0), ^uintptr(0), 0, gp.m.curg) - } - print("\n") - gp.m.traceback = 0 - unlock(&tracelock) -} - -func tracefree(p unsafe.Pointer, size uintptr) { - lock(&tracelock) - gp := getg() - gp.m.traceback = 2 - print("tracefree(", p, ", ", hex(size), ")\n") - goroutineheader(gp) - pc := getcallerpc(unsafe.Pointer(&p)) - sp := getcallersp(unsafe.Pointer(&p)) - onM(func() { - traceback(pc, sp, 0, gp) - }) - print("\n") - gp.m.traceback = 0 - unlock(&tracelock) -} - -func tracegc() { - lock(&tracelock) - gp := getg() - gp.m.traceback = 2 - print("tracegc()\n") - // running on m->g0 stack; show all non-g0 goroutines - tracebackothers(gp) - print("end tracegc\n") - print("\n") - gp.m.traceback = 0 - unlock(&tracelock) -} diff --git a/libgo/go/runtime/netpoll.go b/libgo/go/runtime/netpoll.go deleted file mode 100644 index 3456e020810..00000000000 --- a/libgo/go/runtime/netpoll.go +++ /dev/null @@ -1,455 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows - -package runtime - -import "unsafe" - -// Integrated network poller (platform-independent part). -// A particular implementation (epoll/kqueue) must define the following functions: -// func netpollinit() // to initialize the poller -// func netpollopen(fd uintptr, pd *pollDesc) int32 // to arm edge-triggered notifications -// and associate fd with pd. -// An implementation must call the following function to denote that the pd is ready. -// func netpollready(gpp **g, pd *pollDesc, mode int32) - -// pollDesc contains 2 binary semaphores, rg and wg, to park reader and writer -// goroutines respectively. The semaphore can be in the following states: -// pdReady - io readiness notification is pending; -// a goroutine consumes the notification by changing the state to nil. -// pdWait - a goroutine prepares to park on the semaphore, but not yet parked; -// the goroutine commits to park by changing the state to G pointer, -// or, alternatively, concurrent io notification changes the state to READY, -// or, alternatively, concurrent timeout/close changes the state to nil. -// G pointer - the goroutine is blocked on the semaphore; -// io notification or timeout/close changes the state to READY or nil respectively -// and unparks the goroutine. -// nil - nothing of the above. -const ( - pdReady uintptr = 1 - pdWait uintptr = 2 -) - -const pollBlockSize = 4 * 1024 - -// Network poller descriptor. -type pollDesc struct { - link *pollDesc // in pollcache, protected by pollcache.lock - - // The lock protects pollOpen, pollSetDeadline, pollUnblock and deadlineimpl operations. - // This fully covers seq, rt and wt variables. fd is constant throughout the PollDesc lifetime. - // pollReset, pollWait, pollWaitCanceled and runtime·netpollready (IO readiness notification) - // proceed w/o taking the lock. So closing, rg, rd, wg and wd are manipulated - // in a lock-free way by all operations. - // NOTE(dvyukov): the following code uses uintptr to store *g (rg/wg), - // that will blow up when GC starts moving objects. - lock mutex // protectes the following fields - fd uintptr - closing bool - seq uintptr // protects from stale timers and ready notifications - rg uintptr // pdReady, pdWait, G waiting for read or nil - rt timer // read deadline timer (set if rt.f != nil) - rd int64 // read deadline - wg uintptr // pdReady, pdWait, G waiting for write or nil - wt timer // write deadline timer - wd int64 // write deadline - user unsafe.Pointer // user settable cookie -} - -type pollCache struct { - lock mutex - first *pollDesc - // PollDesc objects must be type-stable, - // because we can get ready notification from epoll/kqueue - // after the descriptor is closed/reused. - // Stale notifications are detected using seq variable, - // seq is incremented when deadlines are changed or descriptor is reused. -} - -var pollcache pollCache - -func netpollServerInit() { - onM(netpollinit) -} - -func netpollOpen(fd uintptr) (*pollDesc, int) { - pd := pollcache.alloc() - lock(&pd.lock) - if pd.wg != 0 && pd.wg != pdReady { - gothrow("netpollOpen: blocked write on free descriptor") - } - if pd.rg != 0 && pd.rg != pdReady { - gothrow("netpollOpen: blocked read on free descriptor") - } - pd.fd = fd - pd.closing = false - pd.seq++ - pd.rg = 0 - pd.rd = 0 - pd.wg = 0 - pd.wd = 0 - unlock(&pd.lock) - - var errno int32 - onM(func() { - errno = netpollopen(fd, pd) - }) - return pd, int(errno) -} - -func netpollClose(pd *pollDesc) { - if !pd.closing { - gothrow("netpollClose: close w/o unblock") - } - if pd.wg != 0 && pd.wg != pdReady { - gothrow("netpollClose: blocked write on closing descriptor") - } - if pd.rg != 0 && pd.rg != pdReady { - gothrow("netpollClose: blocked read on closing descriptor") - } - onM(func() { - netpollclose(uintptr(pd.fd)) - }) - pollcache.free(pd) -} - -func (c *pollCache) free(pd *pollDesc) { - lock(&c.lock) - pd.link = c.first - c.first = pd - unlock(&c.lock) -} - -func netpollReset(pd *pollDesc, mode int) int { - err := netpollcheckerr(pd, int32(mode)) - if err != 0 { - return err - } - if mode == 'r' { - pd.rg = 0 - } else if mode == 'w' { - pd.wg = 0 - } - return 0 -} - -func netpollWait(pd *pollDesc, mode int) int { - err := netpollcheckerr(pd, int32(mode)) - if err != 0 { - return err - } - // As for now only Solaris uses level-triggered IO. - if GOOS == "solaris" { - onM(func() { - netpollarm(pd, mode) - }) - } - for !netpollblock(pd, int32(mode), false) { - err = netpollcheckerr(pd, int32(mode)) - if err != 0 { - return err - } - // Can happen if timeout has fired and unblocked us, - // but before we had a chance to run, timeout has been reset. - // Pretend it has not happened and retry. - } - return 0 -} - -func netpollWaitCanceled(pd *pollDesc, mode int) { - // This function is used only on windows after a failed attempt to cancel - // a pending async IO operation. Wait for ioready, ignore closing or timeouts. - for !netpollblock(pd, int32(mode), true) { - } -} - -func netpollSetDeadline(pd *pollDesc, d int64, mode int) { - lock(&pd.lock) - if pd.closing { - unlock(&pd.lock) - return - } - pd.seq++ // invalidate current timers - // Reset current timers. - if pd.rt.f != nil { - deltimer(&pd.rt) - pd.rt.f = nil - } - if pd.wt.f != nil { - deltimer(&pd.wt) - pd.wt.f = nil - } - // Setup new timers. - if d != 0 && d <= nanotime() { - d = -1 - } - if mode == 'r' || mode == 'r'+'w' { - pd.rd = d - } - if mode == 'w' || mode == 'r'+'w' { - pd.wd = d - } - if pd.rd > 0 && pd.rd == pd.wd { - pd.rt.f = netpollDeadline - pd.rt.when = pd.rd - // Copy current seq into the timer arg. - // Timer func will check the seq against current descriptor seq, - // if they differ the descriptor was reused or timers were reset. - pd.rt.arg = pd - pd.rt.seq = pd.seq - addtimer(&pd.rt) - } else { - if pd.rd > 0 { - pd.rt.f = netpollReadDeadline - pd.rt.when = pd.rd - pd.rt.arg = pd - pd.rt.seq = pd.seq - addtimer(&pd.rt) - } - if pd.wd > 0 { - pd.wt.f = netpollWriteDeadline - pd.wt.when = pd.wd - pd.wt.arg = pd - pd.wt.seq = pd.seq - addtimer(&pd.wt) - } - } - // If we set the new deadline in the past, unblock currently pending IO if any. - var rg, wg *g - atomicstorep(unsafe.Pointer(&wg), nil) // full memory barrier between stores to rd/wd and load of rg/wg in netpollunblock - if pd.rd < 0 { - rg = netpollunblock(pd, 'r', false) - } - if pd.wd < 0 { - wg = netpollunblock(pd, 'w', false) - } - unlock(&pd.lock) - if rg != nil { - goready(rg) - } - if wg != nil { - goready(wg) - } -} - -func netpollUnblock(pd *pollDesc) { - lock(&pd.lock) - if pd.closing { - gothrow("netpollUnblock: already closing") - } - pd.closing = true - pd.seq++ - var rg, wg *g - atomicstorep(unsafe.Pointer(&rg), nil) // full memory barrier between store to closing and read of rg/wg in netpollunblock - rg = netpollunblock(pd, 'r', false) - wg = netpollunblock(pd, 'w', false) - if pd.rt.f != nil { - deltimer(&pd.rt) - pd.rt.f = nil - } - if pd.wt.f != nil { - deltimer(&pd.wt) - pd.wt.f = nil - } - unlock(&pd.lock) - if rg != nil { - goready(rg) - } - if wg != nil { - goready(wg) - } -} - -func netpollfd(pd *pollDesc) uintptr { - return pd.fd -} - -func netpolluser(pd *pollDesc) *unsafe.Pointer { - return &pd.user -} - -func netpollclosing(pd *pollDesc) bool { - return pd.closing -} - -func netpolllock(pd *pollDesc) { - lock(&pd.lock) -} - -func netpollunlock(pd *pollDesc) { - unlock(&pd.lock) -} - -// make pd ready, newly runnable goroutines (if any) are returned in rg/wg -func netpollready(gpp **g, pd *pollDesc, mode int32) { - var rg, wg *g - if mode == 'r' || mode == 'r'+'w' { - rg = netpollunblock(pd, 'r', true) - } - if mode == 'w' || mode == 'r'+'w' { - wg = netpollunblock(pd, 'w', true) - } - if rg != nil { - rg.schedlink = *gpp - *gpp = rg - } - if wg != nil { - wg.schedlink = *gpp - *gpp = wg - } -} - -func netpollcheckerr(pd *pollDesc, mode int32) int { - if pd.closing { - return 1 // errClosing - } - if (mode == 'r' && pd.rd < 0) || (mode == 'w' && pd.wd < 0) { - return 2 // errTimeout - } - return 0 -} - -func netpollblockcommit(gp *g, gpp unsafe.Pointer) bool { - return casuintptr((*uintptr)(gpp), pdWait, uintptr(unsafe.Pointer(gp))) -} - -// returns true if IO is ready, or false if timedout or closed -// waitio - wait only for completed IO, ignore errors -func netpollblock(pd *pollDesc, mode int32, waitio bool) bool { - gpp := &pd.rg - if mode == 'w' { - gpp = &pd.wg - } - - // set the gpp semaphore to WAIT - for { - old := *gpp - if old == pdReady { - *gpp = 0 - return true - } - if old != 0 { - gothrow("netpollblock: double wait") - } - if casuintptr(gpp, 0, pdWait) { - break - } - } - - // need to recheck error states after setting gpp to WAIT - // this is necessary because runtime_pollUnblock/runtime_pollSetDeadline/deadlineimpl - // do the opposite: store to closing/rd/wd, membarrier, load of rg/wg - if waitio || netpollcheckerr(pd, mode) == 0 { - f := netpollblockcommit - gopark(**(**unsafe.Pointer)(unsafe.Pointer(&f)), unsafe.Pointer(gpp), "IO wait") - } - // be careful to not lose concurrent READY notification - old := xchguintptr(gpp, 0) - if old > pdWait { - gothrow("netpollblock: corrupted state") - } - return old == pdReady -} - -func netpollunblock(pd *pollDesc, mode int32, ioready bool) *g { - gpp := &pd.rg - if mode == 'w' { - gpp = &pd.wg - } - - for { - old := *gpp - if old == pdReady { - return nil - } - if old == 0 && !ioready { - // Only set READY for ioready. runtime_pollWait - // will check for timeout/cancel before waiting. - return nil - } - var new uintptr - if ioready { - new = pdReady - } - if casuintptr(gpp, old, new) { - if old == pdReady || old == pdWait { - old = 0 - } - return (*g)(unsafe.Pointer(old)) - } - } -} - -func netpolldeadlineimpl(pd *pollDesc, seq uintptr, read, write bool) { - lock(&pd.lock) - // Seq arg is seq when the timer was set. - // If it's stale, ignore the timer event. - if seq != pd.seq { - // The descriptor was reused or timers were reset. - unlock(&pd.lock) - return - } - var rg *g - if read { - if pd.rd <= 0 || pd.rt.f == nil { - gothrow("netpolldeadlineimpl: inconsistent read deadline") - } - pd.rd = -1 - atomicstorep(unsafe.Pointer(&pd.rt.f), nil) // full memory barrier between store to rd and load of rg in netpollunblock - rg = netpollunblock(pd, 'r', false) - } - var wg *g - if write { - if pd.wd <= 0 || pd.wt.f == nil && !read { - gothrow("netpolldeadlineimpl: inconsistent write deadline") - } - pd.wd = -1 - atomicstorep(unsafe.Pointer(&pd.wt.f), nil) // full memory barrier between store to wd and load of wg in netpollunblock - wg = netpollunblock(pd, 'w', false) - } - unlock(&pd.lock) - if rg != nil { - goready(rg) - } - if wg != nil { - goready(wg) - } -} - -func netpollDeadline(arg interface{}, seq uintptr) { - netpolldeadlineimpl(arg.(*pollDesc), seq, true, true) -} - -func netpollReadDeadline(arg interface{}, seq uintptr) { - netpolldeadlineimpl(arg.(*pollDesc), seq, true, false) -} - -func netpollWriteDeadline(arg interface{}, seq uintptr) { - netpolldeadlineimpl(arg.(*pollDesc), seq, false, true) -} - -func (c *pollCache) alloc() *pollDesc { - lock(&c.lock) - if c.first == nil { - const pdSize = unsafe.Sizeof(pollDesc{}) - n := pollBlockSize / pdSize - if n == 0 { - n = 1 - } - // Must be in non-GC memory because can be referenced - // only from epoll/kqueue internals. - mem := persistentalloc(n*pdSize, 0, &memstats.other_sys) - for i := uintptr(0); i < n; i++ { - pd := (*pollDesc)(add(mem, i*pdSize)) - pd.link = c.first - c.first = pd - } - } - pd := c.first - c.first = pd.link - unlock(&c.lock) - return pd -} diff --git a/libgo/go/runtime/netpoll_epoll.go b/libgo/go/runtime/netpoll_epoll.go deleted file mode 100644 index ecfc9cdde8f..00000000000 --- a/libgo/go/runtime/netpoll_epoll.go +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build linux - -package runtime - -import "unsafe" - -func epollcreate(size int32) int32 -func epollcreate1(flags int32) int32 - -//go:noescape -func epollctl(epfd, op, fd int32, ev *epollevent) int32 - -//go:noescape -func epollwait(epfd int32, ev *epollevent, nev, timeout int32) int32 -func closeonexec(fd int32) - -var ( - epfd int32 = -1 // epoll descriptor - netpolllasterr int32 -) - -func netpollinit() { - epfd = epollcreate1(_EPOLL_CLOEXEC) - if epfd >= 0 { - return - } - epfd = epollcreate(1024) - if epfd >= 0 { - closeonexec(epfd) - return - } - println("netpollinit: failed to create epoll descriptor", -epfd) - gothrow("netpollinit: failed to create descriptor") -} - -func netpollopen(fd uintptr, pd *pollDesc) int32 { - var ev epollevent - ev.events = _EPOLLIN | _EPOLLOUT | _EPOLLRDHUP | _EPOLLET - *(**pollDesc)(unsafe.Pointer(&ev.data)) = pd - return -epollctl(epfd, _EPOLL_CTL_ADD, int32(fd), &ev) -} - -func netpollclose(fd uintptr) int32 { - var ev epollevent - return -epollctl(epfd, _EPOLL_CTL_DEL, int32(fd), &ev) -} - -func netpollarm(pd *pollDesc, mode int) { - gothrow("unused") -} - -// polls for ready network connections -// returns list of goroutines that become runnable -func netpoll(block bool) (gp *g) { - if epfd == -1 { - return - } - waitms := int32(-1) - if !block { - waitms = 0 - } - var events [128]epollevent -retry: - n := epollwait(epfd, &events[0], int32(len(events)), waitms) - if n < 0 { - if n != -_EINTR && n != netpolllasterr { - netpolllasterr = n - println("runtime: epollwait on fd", epfd, "failed with", -n) - } - goto retry - } - for i := int32(0); i < n; i++ { - ev := &events[i] - if ev.events == 0 { - continue - } - var mode int32 - if ev.events&(_EPOLLIN|_EPOLLRDHUP|_EPOLLHUP|_EPOLLERR) != 0 { - mode += 'r' - } - if ev.events&(_EPOLLOUT|_EPOLLHUP|_EPOLLERR) != 0 { - mode += 'w' - } - if mode != 0 { - pd := *(**pollDesc)(unsafe.Pointer(&ev.data)) - netpollready((**g)(noescape(unsafe.Pointer(&gp))), pd, mode) - } - } - if block && gp == nil { - goto retry - } - return gp -} diff --git a/libgo/go/runtime/netpoll_kqueue.go b/libgo/go/runtime/netpoll_kqueue.go deleted file mode 100644 index d6d55b97b8d..00000000000 --- a/libgo/go/runtime/netpoll_kqueue.go +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build darwin dragonfly freebsd netbsd openbsd - -package runtime - -// Integrated network poller (kqueue-based implementation). - -import "unsafe" - -func kqueue() int32 - -//go:noescape -func kevent(kq int32, ch *keventt, nch int32, ev *keventt, nev int32, ts *timespec) int32 -func closeonexec(fd int32) - -var ( - kq int32 = -1 - netpolllasterr int32 -) - -func netpollinit() { - kq = kqueue() - if kq < 0 { - println("netpollinit: kqueue failed with", -kq) - gothrow("netpollinit: kqueue failed") - } - closeonexec(kq) -} - -func netpollopen(fd uintptr, pd *pollDesc) int32 { - // Arm both EVFILT_READ and EVFILT_WRITE in edge-triggered mode (EV_CLEAR) - // for the whole fd lifetime. The notifications are automatically unregistered - // when fd is closed. - var ev [2]keventt - *(*uintptr)(unsafe.Pointer(&ev[0].ident)) = fd - ev[0].filter = _EVFILT_READ - ev[0].flags = _EV_ADD | _EV_CLEAR - ev[0].fflags = 0 - ev[0].data = 0 - ev[0].udata = (*byte)(unsafe.Pointer(pd)) - ev[1] = ev[0] - ev[1].filter = _EVFILT_WRITE - n := kevent(kq, &ev[0], 2, nil, 0, nil) - if n < 0 { - return -n - } - return 0 -} - -func netpollclose(fd uintptr) int32 { - // Don't need to unregister because calling close() - // on fd will remove any kevents that reference the descriptor. - return 0 -} - -func netpollarm(pd *pollDesc, mode int) { - gothrow("unused") -} - -// Polls for ready network connections. -// Returns list of goroutines that become runnable. -func netpoll(block bool) (gp *g) { - if kq == -1 { - return - } - var tp *timespec - var ts timespec - if !block { - tp = &ts - } - var events [64]keventt -retry: - n := kevent(kq, nil, 0, &events[0], int32(len(events)), tp) - if n < 0 { - if n != -_EINTR && n != netpolllasterr { - netpolllasterr = n - println("runtime: kevent on fd", kq, "failed with", -n) - } - goto retry - } - for i := 0; i < int(n); i++ { - ev := &events[i] - var mode int32 - if ev.filter == _EVFILT_READ { - mode += 'r' - } - if ev.filter == _EVFILT_WRITE { - mode += 'w' - } - if mode != 0 { - netpollready((**g)(noescape(unsafe.Pointer(&gp))), (*pollDesc)(unsafe.Pointer(ev.udata)), mode) - } - } - if block && gp == nil { - goto retry - } - return gp -} diff --git a/libgo/go/runtime/netpoll_nacl.go b/libgo/go/runtime/netpoll_nacl.go deleted file mode 100644 index 5cbc3003214..00000000000 --- a/libgo/go/runtime/netpoll_nacl.go +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Fake network poller for NaCl. -// Should never be used, because NaCl network connections do not honor "SetNonblock". - -package runtime - -func netpollinit() { -} - -func netpollopen(fd uintptr, pd *pollDesc) int32 { - return 0 -} - -func netpollclose(fd uintptr) int32 { - return 0 -} - -func netpollarm(pd *pollDesc, mode int) { -} - -func netpoll(block bool) *g { - return nil -} diff --git a/libgo/go/runtime/noasm_arm.go b/libgo/go/runtime/noasm_arm.go deleted file mode 100644 index dd3ef826766..00000000000 --- a/libgo/go/runtime/noasm_arm.go +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Routines that are implemented in assembly in asm_{amd64,386}.s -// but are implemented in Go for arm. - -package runtime - -func cmpstring(s1, s2 string) int { - l := len(s1) - if len(s2) < l { - l = len(s2) - } - for i := 0; i < l; i++ { - c1, c2 := s1[i], s2[i] - if c1 < c2 { - return -1 - } - if c1 > c2 { - return +1 - } - } - if len(s1) < len(s2) { - return -1 - } - if len(s1) > len(s2) { - return +1 - } - return 0 -} - -func cmpbytes(s1, s2 []byte) int { - l := len(s1) - if len(s2) < l { - l = len(s2) - } - for i := 0; i < l; i++ { - c1, c2 := s1[i], s2[i] - if c1 < c2 { - return -1 - } - if c1 > c2 { - return +1 - } - } - if len(s1) < len(s2) { - return -1 - } - if len(s1) > len(s2) { - return +1 - } - return 0 -} diff --git a/libgo/go/runtime/norace_test.go b/libgo/go/runtime/norace_test.go index 3b171877a6f..3681bf190d2 100644 --- a/libgo/go/runtime/norace_test.go +++ b/libgo/go/runtime/norace_test.go @@ -34,12 +34,12 @@ func benchmarkSyscall(b *testing.B, work, excess int) { b.RunParallel(func(pb *testing.PB) { foo := 42 for pb.Next() { - runtime.Entersyscall() + runtime.Entersyscall(0) for i := 0; i < work; i++ { foo *= 2 foo /= 2 } - runtime.Exitsyscall() + runtime.Exitsyscall(0) } _ = foo }) diff --git a/libgo/go/runtime/os_darwin.go b/libgo/go/runtime/os_darwin.go deleted file mode 100644 index 4327ced9148..00000000000 --- a/libgo/go/runtime/os_darwin.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -import "unsafe" - -func bsdthread_create(stk, mm, gg, fn unsafe.Pointer) int32 -func bsdthread_register() int32 -func mach_msg_trap(h unsafe.Pointer, op int32, send_size, rcv_size, rcv_name, timeout, notify uint32) int32 -func mach_reply_port() uint32 -func mach_task_self() uint32 -func mach_thread_self() uint32 -func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32 -func sigprocmask(sig int32, new, old unsafe.Pointer) -func sigaction(mode uint32, new, old unsafe.Pointer) -func sigaltstack(new, old unsafe.Pointer) -func sigtramp() -func setitimer(mode int32, new, old unsafe.Pointer) -func mach_semaphore_wait(sema uint32) int32 -func mach_semaphore_timedwait(sema, sec, nsec uint32) int32 -func mach_semaphore_signal(sema uint32) int32 -func mach_semaphore_signal_all(sema uint32) int32 diff --git a/libgo/go/runtime/os_dragonfly.go b/libgo/go/runtime/os_dragonfly.go deleted file mode 100644 index cdaa06986ee..00000000000 --- a/libgo/go/runtime/os_dragonfly.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -import "unsafe" - -func lwp_create(param unsafe.Pointer) int32 -func sigaltstack(new, old unsafe.Pointer) -func sigaction(sig int32, new, old unsafe.Pointer) -func sigprocmask(new, old unsafe.Pointer) -func setitimer(mode int32, new, old unsafe.Pointer) -func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32 -func getrlimit(kind int32, limit unsafe.Pointer) int32 -func raise(sig int32) -func sys_umtx_sleep(addr unsafe.Pointer, val, timeout int32) int32 -func sys_umtx_wakeup(addr unsafe.Pointer, val int32) int32 - -const stackSystem = 0 diff --git a/libgo/go/runtime/os_freebsd.go b/libgo/go/runtime/os_freebsd.go deleted file mode 100644 index 59708049c8a..00000000000 --- a/libgo/go/runtime/os_freebsd.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -import "unsafe" - -func thr_new(param unsafe.Pointer, size int32) -func sigaltstack(new, old unsafe.Pointer) -func sigaction(sig int32, new, old unsafe.Pointer) -func sigprocmask(new, old unsafe.Pointer) -func setitimer(mode int32, new, old unsafe.Pointer) -func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32 -func getrlimit(kind int32, limit unsafe.Pointer) int32 -func raise(sig int32) -func sys_umtx_op(addr unsafe.Pointer, mode int32, val uint32, ptr2, ts unsafe.Pointer) int32 diff --git a/libgo/go/runtime/os_linux.go b/libgo/go/runtime/os_linux.go deleted file mode 100644 index 41123ad5709..00000000000 --- a/libgo/go/runtime/os_linux.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -import "unsafe" - -func futex(addr unsafe.Pointer, op int32, val uint32, ts, addr2 unsafe.Pointer, val3 uint32) int32 -func clone(flags int32, stk, mm, gg, fn unsafe.Pointer) int32 -func rt_sigaction(sig uintptr, new, old unsafe.Pointer, size uintptr) int32 -func sigaltstack(new, old unsafe.Pointer) -func setitimer(mode int32, new, old unsafe.Pointer) -func rtsigprocmask(sig int32, new, old unsafe.Pointer, size int32) -func getrlimit(kind int32, limit unsafe.Pointer) int32 -func raise(sig int32) -func sched_getaffinity(pid, len uintptr, buf *uintptr) int32 diff --git a/libgo/go/runtime/os_nacl.go b/libgo/go/runtime/os_nacl.go deleted file mode 100644 index 8dd43ff06f1..00000000000 --- a/libgo/go/runtime/os_nacl.go +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -import "unsafe" - -func nacl_exception_stack(p unsafe.Pointer, size int32) int32 -func nacl_exception_handler(fn, arg unsafe.Pointer) int32 -func nacl_sem_create(flag int32) int32 -func nacl_sem_wait(sem int32) int32 -func nacl_sem_post(sem int32) int32 -func nacl_mutex_create(flag int32) int32 -func nacl_mutex_lock(mutex int32) int32 -func nacl_mutex_trylock(mutex int32) int32 -func nacl_mutex_unlock(mutex int32) int32 -func nacl_cond_create(flag int32) int32 -func nacl_cond_wait(cond, n int32) int32 -func nacl_cond_signal(cond int32) int32 -func nacl_cond_broadcast(cond int32) int32 -func nacl_cond_timed_wait_abs(cond, lock int32, ts unsafe.Pointer) int32 -func nacl_thread_create(fn, stk, tls, xx unsafe.Pointer) int32 -func nacl_nanosleep(ts, extra unsafe.Pointer) int32 - -func os_sigpipe() { - gothrow("too many writes on closed pipe") -} - -func sigpanic() { - g := getg() - if !canpanic(g) { - gothrow("unexpected signal during runtime execution") - } - - // Native Client only invokes the exception handler for memory faults. - g.sig = _SIGSEGV - panicmem() -} diff --git a/libgo/go/runtime/os_netbsd.go b/libgo/go/runtime/os_netbsd.go deleted file mode 100644 index f000c5e9f64..00000000000 --- a/libgo/go/runtime/os_netbsd.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -import "unsafe" - -func setitimer(mode int32, new, old unsafe.Pointer) -func sigaction(sig int32, new, old unsafe.Pointer) -func sigaltstack(new, old unsafe.Pointer) -func sigprocmask(mode int32, new, old unsafe.Pointer) -func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32 -func lwp_tramp() -func raise(sig int32) -func getcontext(ctxt unsafe.Pointer) -func lwp_create(ctxt unsafe.Pointer, flags uintptr, lwpid unsafe.Pointer) int32 -func lwp_park(abstime unsafe.Pointer, unpark int32, hint, unparkhint unsafe.Pointer) int32 -func lwp_unpark(lwp int32, hint unsafe.Pointer) int32 -func lwp_self() int32 diff --git a/libgo/go/runtime/os_openbsd.go b/libgo/go/runtime/os_openbsd.go deleted file mode 100644 index a000f963e33..00000000000 --- a/libgo/go/runtime/os_openbsd.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -import "unsafe" - -func setitimer(mode int32, new, old unsafe.Pointer) -func sigaction(sig int32, new, old unsafe.Pointer) -func sigaltstack(new, old unsafe.Pointer) -func sigprocmask(mode int32, new uint32) uint32 -func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32 -func raise(sig int32) -func tfork(param unsafe.Pointer, psize uintptr, mm, gg, fn unsafe.Pointer) int32 -func thrsleep(ident unsafe.Pointer, clock_id int32, tsp, lock, abort unsafe.Pointer) int32 -func thrwakeup(ident unsafe.Pointer, n int32) int32 diff --git a/libgo/go/runtime/os_plan9.go b/libgo/go/runtime/os_plan9.go deleted file mode 100644 index 10e5531ecc8..00000000000 --- a/libgo/go/runtime/os_plan9.go +++ /dev/null @@ -1,105 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -import "unsafe" - -const _SIGPROF = 0 // dummy value for badsignal - -func pread(fd int32, buf unsafe.Pointer, nbytes int32, offset int64) int32 -func pwrite(fd int32, buf unsafe.Pointer, nbytes int32, offset int64) int32 -func seek(fd int32, offset int64, whence int32) int64 -func exits(msg *byte) -func brk_(addr unsafe.Pointer) uintptr -func sleep(ms int32) int32 -func rfork(flags int32) int32 -func plan9_semacquire(addr *uint32, block int32) int32 -func plan9_tsemacquire(addr *uint32, ms int32) int32 -func plan9_semrelease(addr *uint32, count int32) int32 -func notify(fn unsafe.Pointer) int32 -func noted(mode int32) int32 -func nsec(*int64) int64 -func sigtramp(ureg, msg unsafe.Pointer) -func setfpmasks() -func tstart_plan9(newm *m) -func errstr() string - -type _Plink uintptr - -func os_sigpipe() { - gothrow("too many writes on closed pipe") -} - -func sigpanic() { - g := getg() - if !canpanic(g) { - gothrow("unexpected signal during runtime execution") - } - - note := gostringnocopy((*byte)(unsafe.Pointer(g.m.notesig))) - switch g.sig { - case _SIGRFAULT, _SIGWFAULT: - addr := note[index(note, "addr=")+5:] - g.sigcode1 = uintptr(atolwhex(addr)) - if g.sigcode1 < 0x1000 || g.paniconfault { - panicmem() - } - print("unexpected fault address ", hex(g.sigcode1), "\n") - gothrow("fault") - case _SIGTRAP: - if g.paniconfault { - panicmem() - } - gothrow(note) - case _SIGINTDIV: - panicdivide() - case _SIGFLOAT: - panicfloat() - default: - panic(errorString(note)) - } -} - -func atolwhex(p string) int64 { - for hasprefix(p, " ") || hasprefix(p, "\t") { - p = p[1:] - } - neg := false - if hasprefix(p, "-") || hasprefix(p, "+") { - neg = p[0] == '-' - p = p[1:] - for hasprefix(p, " ") || hasprefix(p, "\t") { - p = p[1:] - } - } - var n int64 - switch { - case hasprefix(p, "0x"), hasprefix(p, "0X"): - p = p[2:] - for ; len(p) > 0; p = p[1:] { - if '0' <= p[0] && p[0] <= '9' { - n = n*16 + int64(p[0]-'0') - } else if 'a' <= p[0] && p[0] <= 'f' { - n = n*16 + int64(p[0]-'a'+10) - } else if 'A' <= p[0] && p[0] <= 'F' { - n = n*16 + int64(p[0]-'A'+10) - } else { - break - } - } - case hasprefix(p, "0"): - for ; len(p) > 0 && '0' <= p[0] && p[0] <= '7'; p = p[1:] { - n = n*8 + int64(p[0]-'0') - } - default: - for ; len(p) > 0 && '0' <= p[0] && p[0] <= '9'; p = p[1:] { - n = n*10 + int64(p[0]-'0') - } - } - if neg { - n = -n - } - return n -} diff --git a/libgo/go/runtime/os_solaris.go b/libgo/go/runtime/os_solaris.go deleted file mode 100644 index ca13151204a..00000000000 --- a/libgo/go/runtime/os_solaris.go +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -import "unsafe" - -func setitimer(mode int32, new, old unsafe.Pointer) -func sigaction(sig int32, new, old unsafe.Pointer) -func sigaltstack(new, old unsafe.Pointer) -func sigprocmask(mode int32, new, old unsafe.Pointer) -func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32 -func getrlimit(kind int32, limit unsafe.Pointer) -func miniterrno(fn unsafe.Pointer) -func raise(sig int32) -func getcontext(ctxt unsafe.Pointer) -func tstart_sysvicall(mm unsafe.Pointer) uint32 -func nanotime1() int64 -func usleep1(usec uint32) -func osyield1() -func netpollinit() -func netpollopen(fd uintptr, pd *pollDesc) int32 -func netpollclose(fd uintptr) int32 -func netpollarm(pd *pollDesc, mode int) - -type libcFunc byte - -var asmsysvicall6 libcFunc - -//go:nosplit -func sysvicall0(fn *libcFunc) uintptr { - libcall := &getg().m.libcall - libcall.fn = uintptr(unsafe.Pointer(fn)) - libcall.n = 0 - // TODO(rsc): Why is noescape necessary here and below? - libcall.args = uintptr(noescape(unsafe.Pointer(&fn))) // it's unused but must be non-nil, otherwise crashes - asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(libcall)) - return libcall.r1 -} - -//go:nosplit -func sysvicall1(fn *libcFunc, a1 uintptr) uintptr { - libcall := &getg().m.libcall - libcall.fn = uintptr(unsafe.Pointer(fn)) - libcall.n = 1 - libcall.args = uintptr(noescape(unsafe.Pointer(&a1))) - asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(libcall)) - return libcall.r1 -} - -//go:nosplit -func sysvicall2(fn *libcFunc, a1, a2 uintptr) uintptr { - libcall := &getg().m.libcall - libcall.fn = uintptr(unsafe.Pointer(fn)) - libcall.n = 2 - libcall.args = uintptr(noescape(unsafe.Pointer(&a1))) - asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(libcall)) - return libcall.r1 -} - -//go:nosplit -func sysvicall3(fn *libcFunc, a1, a2, a3 uintptr) uintptr { - libcall := &getg().m.libcall - libcall.fn = uintptr(unsafe.Pointer(fn)) - libcall.n = 3 - libcall.args = uintptr(noescape(unsafe.Pointer(&a1))) - asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(libcall)) - return libcall.r1 -} - -//go:nosplit -func sysvicall4(fn *libcFunc, a1, a2, a3, a4 uintptr) uintptr { - libcall := &getg().m.libcall - libcall.fn = uintptr(unsafe.Pointer(fn)) - libcall.n = 4 - libcall.args = uintptr(noescape(unsafe.Pointer(&a1))) - asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(libcall)) - return libcall.r1 -} - -//go:nosplit -func sysvicall5(fn *libcFunc, a1, a2, a3, a4, a5 uintptr) uintptr { - libcall := &getg().m.libcall - libcall.fn = uintptr(unsafe.Pointer(fn)) - libcall.n = 5 - libcall.args = uintptr(noescape(unsafe.Pointer(&a1))) - asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(libcall)) - return libcall.r1 -} - -//go:nosplit -func sysvicall6(fn *libcFunc, a1, a2, a3, a4, a5, a6 uintptr) uintptr { - libcall := &getg().m.libcall - libcall.fn = uintptr(unsafe.Pointer(fn)) - libcall.n = 6 - libcall.args = uintptr(noescape(unsafe.Pointer(&a1))) - asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(libcall)) - return libcall.r1 -} diff --git a/libgo/go/runtime/os_windows.go b/libgo/go/runtime/os_windows.go deleted file mode 100644 index 1528d2fd139..00000000000 --- a/libgo/go/runtime/os_windows.go +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -import "unsafe" - -type stdFunction *byte - -func stdcall0(fn stdFunction) uintptr -func stdcall1(fn stdFunction, a0 uintptr) uintptr -func stdcall2(fn stdFunction, a0, a1 uintptr) uintptr -func stdcall3(fn stdFunction, a0, a1, a2 uintptr) uintptr -func stdcall4(fn stdFunction, a0, a1, a2, a3 uintptr) uintptr -func stdcall5(fn stdFunction, a0, a1, a2, a3, a4 uintptr) uintptr -func stdcall6(fn stdFunction, a0, a1, a2, a3, a4, a5 uintptr) uintptr -func stdcall7(fn stdFunction, a0, a1, a2, a3, a4, a5, a6 uintptr) uintptr - -func asmstdcall(fn unsafe.Pointer) -func getlasterror() uint32 -func setlasterror(err uint32) -func usleep1(usec uint32) -func netpollinit() -func netpollopen(fd uintptr, pd *pollDesc) int32 -func netpollclose(fd uintptr) int32 -func netpollarm(pd *pollDesc, mode int) - -func os_sigpipe() { - gothrow("too many writes on closed pipe") -} - -func sigpanic() { - g := getg() - if !canpanic(g) { - gothrow("unexpected signal during runtime execution") - } - - switch uint32(g.sig) { - case _EXCEPTION_ACCESS_VIOLATION: - if g.sigcode1 < 0x1000 || g.paniconfault { - panicmem() - } - print("unexpected fault address ", hex(g.sigcode1), "\n") - gothrow("fault") - case _EXCEPTION_INT_DIVIDE_BY_ZERO: - panicdivide() - case _EXCEPTION_INT_OVERFLOW: - panicoverflow() - case _EXCEPTION_FLT_DENORMAL_OPERAND, - _EXCEPTION_FLT_DIVIDE_BY_ZERO, - _EXCEPTION_FLT_INEXACT_RESULT, - _EXCEPTION_FLT_OVERFLOW, - _EXCEPTION_FLT_UNDERFLOW: - panicfloat() - } - gothrow("fault") -} diff --git a/libgo/go/runtime/os_windows_386.go b/libgo/go/runtime/os_windows_386.go deleted file mode 100644 index 86a1906c0c9..00000000000 --- a/libgo/go/runtime/os_windows_386.go +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -// contextPC returns the EIP (program counter) register from the context. -func contextPC(r *context) uintptr { return uintptr(r.eip) } - -// contextSP returns the ESP (stack pointer) register from the context. -func contextSP(r *context) uintptr { return uintptr(r.esp) } diff --git a/libgo/go/runtime/os_windows_amd64.go b/libgo/go/runtime/os_windows_amd64.go deleted file mode 100644 index 3f4d4d07cbf..00000000000 --- a/libgo/go/runtime/os_windows_amd64.go +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -// contextPC returns the RIP (program counter) register from the context. -func contextPC(r *context) uintptr { return uintptr(r.rip) } - -// contextSP returns the RSP (stack pointer) register from the context. -func contextSP(r *context) uintptr { return uintptr(r.rsp) } diff --git a/libgo/go/runtime/panic.go b/libgo/go/runtime/panic.go deleted file mode 100644 index 685ff5ca0bc..00000000000 --- a/libgo/go/runtime/panic.go +++ /dev/null @@ -1,505 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -import "unsafe" - -var indexError = error(errorString("index out of range")) - -func panicindex() { - panic(indexError) -} - -var sliceError = error(errorString("slice bounds out of range")) - -func panicslice() { - panic(sliceError) -} - -var divideError = error(errorString("integer divide by zero")) - -func panicdivide() { - panic(divideError) -} - -var overflowError = error(errorString("integer overflow")) - -func panicoverflow() { - panic(overflowError) -} - -var floatError = error(errorString("floating point error")) - -func panicfloat() { - panic(floatError) -} - -var memoryError = error(errorString("invalid memory address or nil pointer dereference")) - -func panicmem() { - panic(memoryError) -} - -func throwreturn() { - gothrow("no return at end of a typed function - compiler is broken") -} - -func throwinit() { - gothrow("recursive call during initialization - linker skew") -} - -// Create a new deferred function fn with siz bytes of arguments. -// The compiler turns a defer statement into a call to this. -//go:nosplit -func deferproc(siz int32, fn *funcval) { // arguments of fn follow fn - // the arguments of fn are in a perilous state. The stack map - // for deferproc does not describe them. So we can't let garbage - // collection or stack copying trigger until we've copied them out - // to somewhere safe. deferproc_m does that. Until deferproc_m, - // we can only call nosplit routines. - argp := uintptr(unsafe.Pointer(&fn)) - argp += unsafe.Sizeof(fn) - if GOARCH == "arm" { - argp += ptrSize // skip caller's saved link register - } - mp := acquirem() - mp.scalararg[0] = uintptr(siz) - mp.ptrarg[0] = unsafe.Pointer(fn) - mp.scalararg[1] = argp - mp.scalararg[2] = getcallerpc(unsafe.Pointer(&siz)) - - if mp.curg != getg() { - // go code on the m stack can't defer - gothrow("defer on m") - } - - onM(deferproc_m) - - releasem(mp) - - // deferproc returns 0 normally. - // a deferred func that stops a panic - // makes the deferproc return 1. - // the code the compiler generates always - // checks the return value and jumps to the - // end of the function if deferproc returns != 0. - return0() - // No code can go here - the C return register has - // been set and must not be clobbered. -} - -// Small malloc size classes >= 16 are the multiples of 16: 16, 32, 48, 64, 80, 96, 112, 128, 144, ... -// Each P holds a pool for defers with small arg sizes. -// Assign defer allocations to pools by rounding to 16, to match malloc size classes. - -const ( - deferHeaderSize = unsafe.Sizeof(_defer{}) - minDeferAlloc = (deferHeaderSize + 15) &^ 15 - minDeferArgs = minDeferAlloc - deferHeaderSize -) - -// defer size class for arg size sz -//go:nosplit -func deferclass(siz uintptr) uintptr { - if siz <= minDeferArgs { - return 0 - } - return (siz - minDeferArgs + 15) / 16 -} - -// total size of memory block for defer with arg size sz -func totaldefersize(siz uintptr) uintptr { - if siz <= minDeferArgs { - return minDeferAlloc - } - return deferHeaderSize + siz -} - -// Ensure that defer arg sizes that map to the same defer size class -// also map to the same malloc size class. -func testdefersizes() { - var m [len(p{}.deferpool)]int32 - - for i := range m { - m[i] = -1 - } - for i := uintptr(0); ; i++ { - defersc := deferclass(i) - if defersc >= uintptr(len(m)) { - break - } - siz := goroundupsize(totaldefersize(i)) - if m[defersc] < 0 { - m[defersc] = int32(siz) - continue - } - if m[defersc] != int32(siz) { - print("bad defer size class: i=", i, " siz=", siz, " defersc=", defersc, "\n") - gothrow("bad defer size class") - } - } -} - -// The arguments associated with a deferred call are stored -// immediately after the _defer header in memory. -//go:nosplit -func deferArgs(d *_defer) unsafe.Pointer { - return add(unsafe.Pointer(d), unsafe.Sizeof(*d)) -} - -var deferType *_type // type of _defer struct - -func init() { - var x interface{} - x = (*_defer)(nil) - deferType = (*(**ptrtype)(unsafe.Pointer(&x))).elem -} - -// Allocate a Defer, usually using per-P pool. -// Each defer must be released with freedefer. -// Note: runs on M stack -func newdefer(siz int32) *_defer { - var d *_defer - sc := deferclass(uintptr(siz)) - mp := acquirem() - if sc < uintptr(len(p{}.deferpool)) { - pp := mp.p - d = pp.deferpool[sc] - if d != nil { - pp.deferpool[sc] = d.link - } - } - if d == nil { - // Allocate new defer+args. - total := goroundupsize(totaldefersize(uintptr(siz))) - d = (*_defer)(mallocgc(total, deferType, 0)) - } - d.siz = siz - gp := mp.curg - d.link = gp._defer - gp._defer = d - releasem(mp) - return d -} - -// Free the given defer. -// The defer cannot be used after this call. -//go:nosplit -func freedefer(d *_defer) { - if d._panic != nil { - freedeferpanic() - } - if d.fn != nil { - freedeferfn() - } - sc := deferclass(uintptr(d.siz)) - if sc < uintptr(len(p{}.deferpool)) { - mp := acquirem() - pp := mp.p - *d = _defer{} - d.link = pp.deferpool[sc] - pp.deferpool[sc] = d - releasem(mp) - } -} - -// Separate function so that it can split stack. -// Windows otherwise runs out of stack space. -func freedeferpanic() { - // _panic must be cleared before d is unlinked from gp. - gothrow("freedefer with d._panic != nil") -} - -func freedeferfn() { - // fn must be cleared before d is unlinked from gp. - gothrow("freedefer with d.fn != nil") -} - -// Run a deferred function if there is one. -// The compiler inserts a call to this at the end of any -// function which calls defer. -// If there is a deferred function, this will call runtime·jmpdefer, -// which will jump to the deferred function such that it appears -// to have been called by the caller of deferreturn at the point -// just before deferreturn was called. The effect is that deferreturn -// is called again and again until there are no more deferred functions. -// Cannot split the stack because we reuse the caller's frame to -// call the deferred function. - -// The single argument isn't actually used - it just has its address -// taken so it can be matched against pending defers. -//go:nosplit -func deferreturn(arg0 uintptr) { - gp := getg() - d := gp._defer - if d == nil { - return - } - argp := uintptr(unsafe.Pointer(&arg0)) - if d.argp != argp { - return - } - - // Moving arguments around. - // Do not allow preemption here, because the garbage collector - // won't know the form of the arguments until the jmpdefer can - // flip the PC over to fn. - mp := acquirem() - memmove(unsafe.Pointer(argp), deferArgs(d), uintptr(d.siz)) - fn := d.fn - d.fn = nil - gp._defer = d.link - freedefer(d) - releasem(mp) - jmpdefer(fn, argp) -} - -// Goexit terminates the goroutine that calls it. No other goroutine is affected. -// Goexit runs all deferred calls before terminating the goroutine. Because Goexit -// is not panic, however, any recover calls in those deferred functions will return nil. -// -// Calling Goexit from the main goroutine terminates that goroutine -// without func main returning. Since func main has not returned, -// the program continues execution of other goroutines. -// If all other goroutines exit, the program crashes. -func Goexit() { - // Run all deferred functions for the current goroutine. - // This code is similar to gopanic, see that implementation - // for detailed comments. - gp := getg() - for { - d := gp._defer - if d == nil { - break - } - if d.started { - if d._panic != nil { - d._panic.aborted = true - d._panic = nil - } - d.fn = nil - gp._defer = d.link - freedefer(d) - continue - } - d.started = true - reflectcall(unsafe.Pointer(d.fn), deferArgs(d), uint32(d.siz), uint32(d.siz)) - if gp._defer != d { - gothrow("bad defer entry in Goexit") - } - d._panic = nil - d.fn = nil - gp._defer = d.link - freedefer(d) - // Note: we ignore recovers here because Goexit isn't a panic - } - goexit() -} - -func canpanic(*g) bool - -// Print all currently active panics. Used when crashing. -func printpanics(p *_panic) { - if p.link != nil { - printpanics(p.link) - print("\t") - } - print("panic: ") - printany(p.arg) - if p.recovered { - print(" [recovered]") - } - print("\n") -} - -// The implementation of the predeclared function panic. -func gopanic(e interface{}) { - gp := getg() - if gp.m.curg != gp { - gothrow("panic on m stack") - } - - // m.softfloat is set during software floating point. - // It increments m.locks to avoid preemption. - // We moved the memory loads out, so there shouldn't be - // any reason for it to panic anymore. - if gp.m.softfloat != 0 { - gp.m.locks-- - gp.m.softfloat = 0 - gothrow("panic during softfloat") - } - if gp.m.mallocing != 0 { - print("panic: ") - printany(e) - print("\n") - gothrow("panic during malloc") - } - if gp.m.gcing != 0 { - print("panic: ") - printany(e) - print("\n") - gothrow("panic during gc") - } - if gp.m.locks != 0 { - print("panic: ") - printany(e) - print("\n") - gothrow("panic holding locks") - } - - var p _panic - p.arg = e - p.link = gp._panic - gp._panic = (*_panic)(noescape(unsafe.Pointer(&p))) - - for { - d := gp._defer - if d == nil { - break - } - - // If defer was started by earlier panic or Goexit (and, since we're back here, that triggered a new panic), - // take defer off list. The earlier panic or Goexit will not continue running. - if d.started { - if d._panic != nil { - d._panic.aborted = true - } - d._panic = nil - d.fn = nil - gp._defer = d.link - freedefer(d) - continue - } - - // Mark defer as started, but keep on list, so that traceback - // can find and update the defer's argument frame if stack growth - // or a garbage collection hapens before reflectcall starts executing d.fn. - d.started = true - - // Record the panic that is running the defer. - // If there is a new panic during the deferred call, that panic - // will find d in the list and will mark d._panic (this panic) aborted. - d._panic = (*_panic)(noescape((unsafe.Pointer)(&p))) - - p.argp = unsafe.Pointer(getargp(0)) - reflectcall(unsafe.Pointer(d.fn), deferArgs(d), uint32(d.siz), uint32(d.siz)) - p.argp = nil - - // reflectcall did not panic. Remove d. - if gp._defer != d { - gothrow("bad defer entry in panic") - } - d._panic = nil - d.fn = nil - gp._defer = d.link - - // trigger shrinkage to test stack copy. See stack_test.go:TestStackPanic - //GC() - - pc := d.pc - argp := unsafe.Pointer(d.argp) // must be pointer so it gets adjusted during stack copy - freedefer(d) - if p.recovered { - gp._panic = p.link - // Aborted panics are marked but remain on the g.panic list. - // Remove them from the list. - for gp._panic != nil && gp._panic.aborted { - gp._panic = gp._panic.link - } - if gp._panic == nil { // must be done with signal - gp.sig = 0 - } - // Pass information about recovering frame to recovery. - gp.sigcode0 = uintptr(argp) - gp.sigcode1 = pc - mcall(recovery_m) - gothrow("recovery failed") // mcall should not return - } - } - - // ran out of deferred calls - old-school panic now - startpanic() - printpanics(gp._panic) - dopanic(0) // should not return - *(*int)(nil) = 0 // not reached -} - -// getargp returns the location where the caller -// writes outgoing function call arguments. -//go:nosplit -func getargp(x int) uintptr { - // x is an argument mainly so that we can return its address. - // However, we need to make the function complex enough - // that it won't be inlined. We always pass x = 0, so this code - // does nothing other than keep the compiler from thinking - // the function is simple enough to inline. - if x > 0 { - return getcallersp(unsafe.Pointer(&x)) * 0 - } - return uintptr(noescape(unsafe.Pointer(&x))) -} - -// The implementation of the predeclared function recover. -// Cannot split the stack because it needs to reliably -// find the stack segment of its caller. -// -// TODO(rsc): Once we commit to CopyStackAlways, -// this doesn't need to be nosplit. -//go:nosplit -func gorecover(argp uintptr) interface{} { - // Must be in a function running as part of a deferred call during the panic. - // Must be called from the topmost function of the call - // (the function used in the defer statement). - // p.argp is the argument pointer of that topmost deferred function call. - // Compare against argp reported by caller. - // If they match, the caller is the one who can recover. - gp := getg() - p := gp._panic - if p != nil && !p.recovered && argp == uintptr(p.argp) { - p.recovered = true - return p.arg - } - return nil -} - -//go:nosplit -func startpanic() { - onM_signalok(startpanic_m) -} - -//go:nosplit -func dopanic(unused int) { - gp := getg() - mp := acquirem() - mp.ptrarg[0] = unsafe.Pointer(gp) - mp.scalararg[0] = getcallerpc((unsafe.Pointer)(&unused)) - mp.scalararg[1] = getcallersp((unsafe.Pointer)(&unused)) - onM_signalok(dopanic_m) // should never return - *(*int)(nil) = 0 -} - -//go:nosplit -func throw(s *byte) { - gp := getg() - if gp.m.throwing == 0 { - gp.m.throwing = 1 - } - startpanic() - print("fatal error: ", gostringnocopy(s), "\n") - dopanic(0) - *(*int)(nil) = 0 // not reached -} - -//go:nosplit -func gothrow(s string) { - gp := getg() - if gp.m.throwing == 0 { - gp.m.throwing = 1 - } - startpanic() - print("fatal error: ", s, "\n") - dopanic(0) - *(*int)(nil) = 0 // not reached -} diff --git a/libgo/go/runtime/parfor_test.go b/libgo/go/runtime/parfor_test.go index de64285b8a8..5d22aecc9bb 100644 --- a/libgo/go/runtime/parfor_test.go +++ b/libgo/go/runtime/parfor_test.go @@ -10,11 +10,8 @@ package runtime_test import ( . "runtime" "testing" - "unsafe" ) -var gdata []uint64 - // Simple serial sanity test for parallelfor. func TestParFor(t *testing.T) { const P = 1 @@ -24,12 +21,7 @@ func TestParFor(t *testing.T) { data[i] = i } desc := NewParFor(P) - // Avoid making func a closure: parfor cannot invoke them. - // Since it doesn't happen in the C code, it's not worth doing - // just for the test. - gdata = data - ParForSetup(desc, P, N, nil, true, func(desc *ParFor, i uint32) { - data := gdata + ParForSetup(desc, P, N, true, func(desc *ParFor, i uint32) { data[i] = data[i]*data[i] + 1 }) ParForDo(desc) @@ -49,9 +41,8 @@ func TestParFor2(t *testing.T) { data[i] = i } desc := NewParFor(P) - ParForSetup(desc, P, N, (*byte)(unsafe.Pointer(&data)), false, func(desc *ParFor, i uint32) { - d := *(*[]uint64)(unsafe.Pointer(desc.Ctx)) - d[i] = d[i]*d[i] + 1 + ParForSetup(desc, P, N, false, func(desc *ParFor, i uint32) { + data[i] = data[i]*data[i] + 1 }) for p := 0; p < P; p++ { ParForDo(desc) @@ -70,7 +61,7 @@ func TestParForSetup(t *testing.T) { desc := NewParFor(P) for n := uint32(0); n < N; n++ { for p := uint32(1); p <= P; p++ { - ParForSetup(desc, p, n, nil, true, func(desc *ParFor, i uint32) {}) + ParForSetup(desc, p, n, true, func(desc *ParFor, i uint32) {}) sum := uint32(0) size0 := uint32(0) end0 := uint32(0) @@ -113,9 +104,7 @@ func TestParForParallel(t *testing.T) { P := GOMAXPROCS(-1) c := make(chan bool, P) desc := NewParFor(uint32(P)) - gdata = data - ParForSetup(desc, uint32(P), uint32(N), nil, false, func(desc *ParFor, i uint32) { - data := gdata + ParForSetup(desc, uint32(P), uint32(N), false, func(desc *ParFor, i uint32) { data[i] = data[i]*data[i] + 1 }) for p := 1; p < P; p++ { diff --git a/libgo/go/runtime/pprof/pprof.go b/libgo/go/runtime/pprof/pprof.go index 38593afb6f2..dcf67cd573f 100644 --- a/libgo/go/runtime/pprof/pprof.go +++ b/libgo/go/runtime/pprof/pprof.go @@ -21,7 +21,7 @@ import ( ) // BUG(rsc): Profiles are incomplete and inaccurate on NetBSD and OS X. -// See http://golang.org/issue/6047 for details. +// See https://golang.org/issue/6047 for details. // A Profile is a collection of stack traces showing the call sequences // that led to instances of a particular event, such as allocation. @@ -41,6 +41,13 @@ import ( // These predefined profiles maintain themselves and panic on an explicit // Add or Remove method call. // +// The heap profile reports statistics as of the most recently completed +// garbage collection; it elides more recent allocation to avoid skewing +// the profile away from live data and toward garbage. +// If there has been no garbage collection at all, the heap profile reports +// all known allocations. This exception helps mainly in programs running +// without garbage collection enabled, usually for debugging purposes. +// // The CPU profile is not available as a Profile. It has a special API, // the StartCPUProfile and StopCPUProfile functions, because it streams // output to a writer during profiling. @@ -454,35 +461,33 @@ func writeHeap(w io.Writer, debug int) error { // Print memstats information too. // Pprof will ignore, but useful for people - if debug > 0 { - s := new(runtime.MemStats) - runtime.ReadMemStats(s) - fmt.Fprintf(w, "\n# runtime.MemStats\n") - fmt.Fprintf(w, "# Alloc = %d\n", s.Alloc) - fmt.Fprintf(w, "# TotalAlloc = %d\n", s.TotalAlloc) - fmt.Fprintf(w, "# Sys = %d\n", s.Sys) - fmt.Fprintf(w, "# Lookups = %d\n", s.Lookups) - fmt.Fprintf(w, "# Mallocs = %d\n", s.Mallocs) - fmt.Fprintf(w, "# Frees = %d\n", s.Frees) - - fmt.Fprintf(w, "# HeapAlloc = %d\n", s.HeapAlloc) - fmt.Fprintf(w, "# HeapSys = %d\n", s.HeapSys) - fmt.Fprintf(w, "# HeapIdle = %d\n", s.HeapIdle) - fmt.Fprintf(w, "# HeapInuse = %d\n", s.HeapInuse) - fmt.Fprintf(w, "# HeapReleased = %d\n", s.HeapReleased) - fmt.Fprintf(w, "# HeapObjects = %d\n", s.HeapObjects) - - fmt.Fprintf(w, "# Stack = %d / %d\n", s.StackInuse, s.StackSys) - fmt.Fprintf(w, "# MSpan = %d / %d\n", s.MSpanInuse, s.MSpanSys) - fmt.Fprintf(w, "# MCache = %d / %d\n", s.MCacheInuse, s.MCacheSys) - fmt.Fprintf(w, "# BuckHashSys = %d\n", s.BuckHashSys) - - fmt.Fprintf(w, "# NextGC = %d\n", s.NextGC) - fmt.Fprintf(w, "# PauseNs = %d\n", s.PauseNs) - fmt.Fprintf(w, "# NumGC = %d\n", s.NumGC) - fmt.Fprintf(w, "# EnableGC = %v\n", s.EnableGC) - fmt.Fprintf(w, "# DebugGC = %v\n", s.DebugGC) - } + s := new(runtime.MemStats) + runtime.ReadMemStats(s) + fmt.Fprintf(w, "\n# runtime.MemStats\n") + fmt.Fprintf(w, "# Alloc = %d\n", s.Alloc) + fmt.Fprintf(w, "# TotalAlloc = %d\n", s.TotalAlloc) + fmt.Fprintf(w, "# Sys = %d\n", s.Sys) + fmt.Fprintf(w, "# Lookups = %d\n", s.Lookups) + fmt.Fprintf(w, "# Mallocs = %d\n", s.Mallocs) + fmt.Fprintf(w, "# Frees = %d\n", s.Frees) + + fmt.Fprintf(w, "# HeapAlloc = %d\n", s.HeapAlloc) + fmt.Fprintf(w, "# HeapSys = %d\n", s.HeapSys) + fmt.Fprintf(w, "# HeapIdle = %d\n", s.HeapIdle) + fmt.Fprintf(w, "# HeapInuse = %d\n", s.HeapInuse) + fmt.Fprintf(w, "# HeapReleased = %d\n", s.HeapReleased) + fmt.Fprintf(w, "# HeapObjects = %d\n", s.HeapObjects) + + fmt.Fprintf(w, "# Stack = %d / %d\n", s.StackInuse, s.StackSys) + fmt.Fprintf(w, "# MSpan = %d / %d\n", s.MSpanInuse, s.MSpanSys) + fmt.Fprintf(w, "# MCache = %d / %d\n", s.MCacheInuse, s.MCacheSys) + fmt.Fprintf(w, "# BuckHashSys = %d\n", s.BuckHashSys) + + fmt.Fprintf(w, "# NextGC = %d\n", s.NextGC) + fmt.Fprintf(w, "# PauseNs = %d\n", s.PauseNs) + fmt.Fprintf(w, "# NumGC = %d\n", s.NumGC) + fmt.Fprintf(w, "# EnableGC = %v\n", s.EnableGC) + fmt.Fprintf(w, "# DebugGC = %v\n", s.DebugGC) if tw != nil { tw.Flush() diff --git a/libgo/go/runtime/pprof/pprof_test.go b/libgo/go/runtime/pprof/pprof_test.go index 10699637205..c32b84758a8 100644 --- a/libgo/go/runtime/pprof/pprof_test.go +++ b/libgo/go/runtime/pprof/pprof_test.go @@ -9,7 +9,9 @@ package pprof_test import ( "bytes" "fmt" + "internal/testenv" "math/big" + "os" "os/exec" "regexp" "runtime" @@ -121,15 +123,19 @@ func parseProfile(t *testing.T, bytes []byte, f func(uintptr, []uintptr)) { func testCPUProfile(t *testing.T, need []string, f func()) { switch runtime.GOOS { case "darwin": - out, err := exec.Command("uname", "-a").CombinedOutput() - if err != nil { - t.Fatal(err) + switch runtime.GOARCH { + case "arm", "arm64": + // nothing + default: + out, err := exec.Command("uname", "-a").CombinedOutput() + if err != nil { + t.Fatal(err) + } + vers := string(out) + t.Logf("uname -a: %v", vers) } - vers := string(out) - t.Logf("uname -a: %v", vers) case "plan9": - // unimplemented - return + t.Skip("skipping on plan9") } var prof bytes.Buffer @@ -141,7 +147,9 @@ func testCPUProfile(t *testing.T, need []string, f func()) { // Check that profile is well formed and contains need. have := make([]uintptr, len(need)) + var samples uintptr parseProfile(t, prof.Bytes(), func(count uintptr, stk []uintptr) { + samples += count for _, pc := range stk { f := runtime.FuncForPC(pc) if f == nil { @@ -155,6 +163,14 @@ func testCPUProfile(t *testing.T, need []string, f func()) { } } }) + t.Logf("total %d CPU profile samples collected", samples) + + if samples < 10 && runtime.GOOS == "windows" { + // On some windows machines we end up with + // not enough samples due to coarse timer + // resolution. Let it go. + t.Skip("too few samples on Windows (golang.org/issue/10842)") + } if len(need) == 0 { return @@ -187,14 +203,28 @@ func testCPUProfile(t *testing.T, need []string, f func()) { t.Skipf("ignoring failure on %s; see golang.org/issue/6047", runtime.GOOS) return } + // Ignore the failure if the tests are running in a QEMU-based emulator, + // QEMU is not perfect at emulating everything. + // IN_QEMU environmental variable is set by some of the Go builders. + // IN_QEMU=1 indicates that the tests are running in QEMU. See issue 9605. + if os.Getenv("IN_QEMU") == "1" { + t.Skip("ignore the failure in QEMU; see golang.org/issue/9605") + return + } t.FailNow() } } +// Fork can hang if preempted with signals frequently enough (see issue 5517). +// Ensure that we do not do this. func TestCPUProfileWithFork(t *testing.T) { - // Fork can hang if preempted with signals frequently enough (see issue 5517). - // Ensure that we do not do this. + testenv.MustHaveExec(t) + heap := 1 << 30 + if runtime.GOOS == "android" { + // Use smaller size for Android to avoid crash. + heap = 100 << 20 + } if testing.Short() { heap = 100 << 20 } @@ -217,7 +247,7 @@ func TestCPUProfileWithFork(t *testing.T) { defer StopCPUProfile() for i := 0; i < 10; i++ { - exec.Command("go").CombinedOutput() + exec.Command(os.Args[0], "-h").CombinedOutput() } } @@ -250,7 +280,7 @@ func TestGoroutineSwitch(t *testing.T) { // exists to record a PC without a traceback. Those are okay. if len(stk) == 2 { f := runtime.FuncForPC(stk[1]) - if f != nil && (f.Name() == "System" || f.Name() == "ExternalCode" || f.Name() == "GC") { + if f != nil && (f.Name() == "runtime._System" || f.Name() == "runtime._ExternalCode" || f.Name() == "runtime._GC") { return } } @@ -368,7 +398,7 @@ func TestBlockProfile(t *testing.T) { } for _, test := range tests { - if !regexp.MustCompile(test.re).MatchString(prof) { + if !regexp.MustCompile(strings.Replace(test.re, "\t", "\t+", -1)).MatchString(prof) { t.Fatalf("Bad %v entry, expect:\n%v\ngot:\n%v", test.name, test.re, prof) } } diff --git a/libgo/go/runtime/print1.go b/libgo/go/runtime/print1.go deleted file mode 100644 index 8f8268873b2..00000000000 --- a/libgo/go/runtime/print1.go +++ /dev/null @@ -1,323 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -import "unsafe" - -// The compiler knows that a print of a value of this type -// should use printhex instead of printuint (decimal). -type hex uint64 - -func bytes(s string) (ret []byte) { - rp := (*slice)(unsafe.Pointer(&ret)) - sp := (*_string)(noescape(unsafe.Pointer(&s))) - rp.array = sp.str - rp.len = uint(sp.len) - rp.cap = uint(sp.len) - return -} - -// printf is only called from C code. It has no type information for the args, -// but C stacks are ignored by the garbage collector anyway, so having -// type information would not add anything. -//go:nosplit -func printf(s *byte) { - vprintf(gostringnocopy(s), add(unsafe.Pointer(&s), unsafe.Sizeof(s))) -} - -// sprintf is only called from C code. It has no type information for the args, -// but C stacks are ignored by the garbage collector anyway, so having -// type information would not add anything. -//go:nosplit -func snprintf(dst *byte, n int32, s *byte) { - buf := (*[1 << 30]byte)(unsafe.Pointer(dst))[0:n:n] - - gp := getg() - gp.writebuf = buf[0:0 : n-1] // leave room for NUL, this is called from C - vprintf(gostringnocopy(s), add(unsafe.Pointer(&s), unsafe.Sizeof(s))) - buf[len(gp.writebuf)] = '\x00' - gp.writebuf = nil -} - -//var debuglock mutex - -// write to goroutine-local buffer if diverting output, -// or else standard error. -func gwrite(b []byte) { - if len(b) == 0 { - return - } - gp := getg() - if gp == nil || gp.writebuf == nil { - write(2, unsafe.Pointer(&b[0]), int32(len(b))) - return - } - - n := copy(gp.writebuf[len(gp.writebuf):cap(gp.writebuf)], b) - gp.writebuf = gp.writebuf[:len(gp.writebuf)+n] -} - -func prints(s *byte) { - b := (*[1 << 30]byte)(unsafe.Pointer(s)) - for i := 0; ; i++ { - if b[i] == 0 { - gwrite(b[:i]) - return - } - } -} - -func printsp() { - print(" ") -} - -func printnl() { - print("\n") -} - -// Very simple printf. Only for debugging prints. -// Do not add to this without checking with Rob. -func vprintf(str string, arg unsafe.Pointer) { - //lock(&debuglock); - - s := bytes(str) - start := 0 - i := 0 - for ; i < len(s); i++ { - if s[i] != '%' { - continue - } - if i > start { - gwrite(s[start:i]) - } - if i++; i >= len(s) { - break - } - var siz uintptr - switch s[i] { - case 't', 'c': - siz = 1 - case 'd', 'x': // 32-bit - arg = roundup(arg, 4) - siz = 4 - case 'D', 'U', 'X', 'f': // 64-bit - arg = roundup(arg, unsafe.Sizeof(uintreg(0))) - siz = 8 - case 'C': - arg = roundup(arg, unsafe.Sizeof(uintreg(0))) - siz = 16 - case 'p', 's': // pointer-sized - arg = roundup(arg, unsafe.Sizeof(uintptr(0))) - siz = unsafe.Sizeof(uintptr(0)) - case 'S': // pointer-aligned but bigger - arg = roundup(arg, unsafe.Sizeof(uintptr(0))) - siz = unsafe.Sizeof(string("")) - case 'a': // pointer-aligned but bigger - arg = roundup(arg, unsafe.Sizeof(uintptr(0))) - siz = unsafe.Sizeof([]byte{}) - case 'i', 'e': // pointer-aligned but bigger - arg = roundup(arg, unsafe.Sizeof(uintptr(0))) - siz = unsafe.Sizeof(interface{}(nil)) - } - switch s[i] { - case 'a': - printslice(*(*[]byte)(arg)) - case 'c': - printbyte(*(*byte)(arg)) - case 'd': - printint(int64(*(*int32)(arg))) - case 'D': - printint(int64(*(*int64)(arg))) - case 'e': - printeface(*(*interface{})(arg)) - case 'f': - printfloat(*(*float64)(arg)) - case 'C': - printcomplex(*(*complex128)(arg)) - case 'i': - printiface(*(*fInterface)(arg)) - case 'p': - printpointer(*(*unsafe.Pointer)(arg)) - case 's': - prints(*(**byte)(arg)) - case 'S': - printstring(*(*string)(arg)) - case 't': - printbool(*(*bool)(arg)) - case 'U': - printuint(*(*uint64)(arg)) - case 'x': - printhex(uint64(*(*uint32)(arg))) - case 'X': - printhex(*(*uint64)(arg)) - } - arg = add(arg, siz) - start = i + 1 - } - if start < i { - gwrite(s[start:i]) - } - - //unlock(&debuglock); -} - -func printpc(p unsafe.Pointer) { - print("PC=", hex(uintptr(p))) -} - -func printbool(v bool) { - if v { - print("true") - } else { - print("false") - } -} - -func printbyte(c byte) { - gwrite((*[1]byte)(unsafe.Pointer(&c))[:]) -} - -func printfloat(v float64) { - switch { - case v != v: - print("NaN") - return - case v+v == v && v > 0: - print("+Inf") - return - case v+v == v && v < 0: - print("-Inf") - return - } - - const n = 7 // digits printed - var buf [n + 7]byte - buf[0] = '+' - e := 0 // exp - if v == 0 { - if 1/v < 0 { - buf[0] = '-' - } - } else { - if v < 0 { - v = -v - buf[0] = '-' - } - - // normalize - for v >= 10 { - e++ - v /= 10 - } - for v < 1 { - e-- - v *= 10 - } - - // round - h := 5.0 - for i := 0; i < n; i++ { - h /= 10 - } - v += h - if v >= 10 { - e++ - v /= 10 - } - } - - // format +d.dddd+edd - for i := 0; i < n; i++ { - s := int(v) - buf[i+2] = byte(s + '0') - v -= float64(s) - v *= 10 - } - buf[1] = buf[2] - buf[2] = '.' - - buf[n+2] = 'e' - buf[n+3] = '+' - if e < 0 { - e = -e - buf[n+3] = '-' - } - - buf[n+4] = byte(e/100) + '0' - buf[n+5] = byte(e/10)%10 + '0' - buf[n+6] = byte(e%10) + '0' - gwrite(buf[:]) -} - -func printcomplex(c complex128) { - print("(", real(c), imag(c), "i)") -} - -func printuint(v uint64) { - var buf [100]byte - i := len(buf) - for i--; i > 0; i-- { - buf[i] = byte(v%10 + '0') - if v < 10 { - break - } - v /= 10 - } - gwrite(buf[i:]) -} - -func printint(v int64) { - if v < 0 { - print("-") - v = -v - } - printuint(uint64(v)) -} - -func printhex(v uint64) { - const dig = "0123456789abcdef" - var buf [100]byte - i := len(buf) - for i--; i > 0; i-- { - buf[i] = dig[v%16] - if v < 16 { - break - } - v /= 16 - } - i-- - buf[i] = 'x' - i-- - buf[i] = '0' - gwrite(buf[i:]) -} - -func printpointer(p unsafe.Pointer) { - printhex(uint64(uintptr(p))) -} - -func printstring(s string) { - if uintptr(len(s)) > maxstring { - gwrite(bytes("[string too long]")) - return - } - gwrite(bytes(s)) -} - -func printslice(s []byte) { - sp := (*slice)(unsafe.Pointer(&s)) - print("[", len(s), "/", cap(s), "]") - printpointer(unsafe.Pointer(sp.array)) -} - -func printeface(e interface{}) { - ep := (*eface)(unsafe.Pointer(&e)) - print("(", ep._type, ",", ep.data, ")") -} - -func printiface(i fInterface) { - ip := (*iface)(unsafe.Pointer(&i)) - print("(", ip.tab, ",", ip.data, ")") -} diff --git a/libgo/go/runtime/proc.go b/libgo/go/runtime/proc.go deleted file mode 100644 index 517ca03df64..00000000000 --- a/libgo/go/runtime/proc.go +++ /dev/null @@ -1,246 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -import "unsafe" - -func newsysmon() - -func runtime_init() -func main_init() -func main_main() - -// The main goroutine. -func main() { - g := getg() - - // Racectx of m0->g0 is used only as the parent of the main goroutine. - // It must not be used for anything else. - g.m.g0.racectx = 0 - - // Max stack size is 1 GB on 64-bit, 250 MB on 32-bit. - // Using decimal instead of binary GB and MB because - // they look nicer in the stack overflow failure message. - if ptrSize == 8 { - maxstacksize = 1000000000 - } else { - maxstacksize = 250000000 - } - - onM(newsysmon) - - // Lock the main goroutine onto this, the main OS thread, - // during initialization. Most programs won't care, but a few - // do require certain calls to be made by the main thread. - // Those can arrange for main.main to run in the main thread - // by calling runtime.LockOSThread during initialization - // to preserve the lock. - lockOSThread() - - if g.m != &m0 { - gothrow("runtime.main not on m0") - } - - runtime_init() // must be before defer - - // Defer unlock so that runtime.Goexit during init does the unlock too. - needUnlock := true - defer func() { - if needUnlock { - unlockOSThread() - } - }() - - memstats.enablegc = true // now that runtime is initialized, GC is okay - - main_init() - - needUnlock = false - unlockOSThread() - - main_main() - if raceenabled { - racefini() - } - - // Make racy client program work: if panicking on - // another goroutine at the same time as main returns, - // let the other goroutine finish printing the panic trace. - // Once it does, it will exit. See issue 3934. - if panicking != 0 { - gopark(nil, nil, "panicwait") - } - - exit(0) - for { - var x *int32 - *x = 0 - } -} - -var parkunlock_c byte - -// start forcegc helper goroutine -func init() { - go forcegchelper() -} - -func forcegchelper() { - forcegc.g = getg() - forcegc.g.issystem = true - for { - lock(&forcegc.lock) - if forcegc.idle != 0 { - gothrow("forcegc: phase error") - } - atomicstore(&forcegc.idle, 1) - goparkunlock(&forcegc.lock, "force gc (idle)") - // this goroutine is explicitly resumed by sysmon - if debug.gctrace > 0 { - println("GC forced") - } - gogc(1) - } -} - -//go:nosplit - -// Gosched yields the processor, allowing other goroutines to run. It does not -// suspend the current goroutine, so execution resumes automatically. -func Gosched() { - mcall(gosched_m) -} - -// Puts the current goroutine into a waiting state and calls unlockf. -// If unlockf returns false, the goroutine is resumed. -func gopark(unlockf unsafe.Pointer, lock unsafe.Pointer, reason string) { - mp := acquirem() - gp := mp.curg - status := readgstatus(gp) - if status != _Grunning && status != _Gscanrunning { - gothrow("gopark: bad g status") - } - mp.waitlock = lock - mp.waitunlockf = unlockf - gp.waitreason = reason - releasem(mp) - // can't do anything that might move the G between Ms here. - mcall(park_m) -} - -// Puts the current goroutine into a waiting state and unlocks the lock. -// The goroutine can be made runnable again by calling goready(gp). -func goparkunlock(lock *mutex, reason string) { - gopark(unsafe.Pointer(&parkunlock_c), unsafe.Pointer(lock), reason) -} - -func goready(gp *g) { - mp := acquirem() - mp.ptrarg[0] = unsafe.Pointer(gp) - onM(ready_m) - releasem(mp) -} - -//go:nosplit -func acquireSudog() *sudog { - c := gomcache() - s := c.sudogcache - if s != nil { - if s.elem != nil { - gothrow("acquireSudog: found s.elem != nil in cache") - } - c.sudogcache = s.next - s.next = nil - return s - } - - // Delicate dance: the semaphore implementation calls - // acquireSudog, acquireSudog calls new(sudog), - // new calls malloc, malloc can call the garbage collector, - // and the garbage collector calls the semaphore implementation - // in stoptheworld. - // Break the cycle by doing acquirem/releasem around new(sudog). - // The acquirem/releasem increments m.locks during new(sudog), - // which keeps the garbage collector from being invoked. - mp := acquirem() - p := new(sudog) - releasem(mp) - return p -} - -//go:nosplit -func releaseSudog(s *sudog) { - if s.elem != nil { - gothrow("runtime: sudog with non-nil elem") - } - if s.selectdone != nil { - gothrow("runtime: sudog with non-nil selectdone") - } - if s.next != nil { - gothrow("runtime: sudog with non-nil next") - } - if s.prev != nil { - gothrow("runtime: sudog with non-nil prev") - } - if s.waitlink != nil { - gothrow("runtime: sudog with non-nil waitlink") - } - gp := getg() - if gp.param != nil { - gothrow("runtime: releaseSudog with non-nil gp.param") - } - c := gomcache() - s.next = c.sudogcache - c.sudogcache = s -} - -// funcPC returns the entry PC of the function f. -// It assumes that f is a func value. Otherwise the behavior is undefined. -//go:nosplit -func funcPC(f interface{}) uintptr { - return **(**uintptr)(add(unsafe.Pointer(&f), ptrSize)) -} - -// called from assembly -func badmcall(fn func(*g)) { - gothrow("runtime: mcall called on m->g0 stack") -} - -func badmcall2(fn func(*g)) { - gothrow("runtime: mcall function returned") -} - -func badreflectcall() { - panic("runtime: arg size to reflect.call more than 1GB") -} - -func lockedOSThread() bool { - gp := getg() - return gp.lockedm != nil && gp.m.lockedg != nil -} - -func newP() *p { - return new(p) -} - -func newM() *m { - return new(m) -} - -func newG() *g { - return new(g) -} - -func allgadd(gp *g) { - if readgstatus(gp) == _Gidle { - gothrow("allgadd: bad status Gidle") - } - - lock(&allglock) - allgs = append(allgs, gp) - allg = &allgs[0] - allglen = uintptr(len(allgs)) - unlock(&allglock) -} diff --git a/libgo/go/runtime/proc_test.go b/libgo/go/runtime/proc_test.go index 4f364dc4636..4350e8f89d2 100644 --- a/libgo/go/runtime/proc_test.go +++ b/libgo/go/runtime/proc_test.go @@ -7,6 +7,8 @@ package runtime_test import ( "math" "runtime" + "runtime/debug" + "sync" "sync/atomic" "syscall" "testing" @@ -94,6 +96,10 @@ func TestYieldLocked(t *testing.T) { } func TestGoroutineParallelism(t *testing.T) { + if runtime.NumCPU() == 1 { + // Takes too long, too easy to deadlock, etc. + t.Skip("skipping on uniprocessor") + } P := 4 N := 10 if testing.Short() { @@ -101,6 +107,10 @@ func TestGoroutineParallelism(t *testing.T) { N = 3 } defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(P)) + // If runtime triggers a forced GC during this test then it will deadlock, + // since the goroutines can't be stopped/preempted. + // Disable GC for this test (see issue #10958). + defer debug.SetGCPercent(debug.SetGCPercent(-1)) for try := 0; try < N; try++ { done := make(chan bool) x := uint32(0) @@ -289,6 +299,98 @@ func main() { } ` +func TestPingPongHog(t *testing.T) { + if testing.Short() { + t.Skip("skipping in -short mode") + } + + defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1)) + done := make(chan bool) + hogChan, lightChan := make(chan bool), make(chan bool) + hogCount, lightCount := 0, 0 + + run := func(limit int, counter *int, wake chan bool) { + for { + select { + case <-done: + return + + case <-wake: + for i := 0; i < limit; i++ { + *counter++ + } + wake <- true + } + } + } + + // Start two co-scheduled hog goroutines. + for i := 0; i < 2; i++ { + go run(1e6, &hogCount, hogChan) + } + + // Start two co-scheduled light goroutines. + for i := 0; i < 2; i++ { + go run(1e3, &lightCount, lightChan) + } + + // Start goroutine pairs and wait for a few preemption rounds. + hogChan <- true + lightChan <- true + time.Sleep(100 * time.Millisecond) + close(done) + <-hogChan + <-lightChan + + // Check that hogCount and lightCount are within a factor of + // 2, which indicates that both pairs of goroutines handed off + // the P within a time-slice to their buddy. + if hogCount > lightCount*2 || lightCount > hogCount*2 { + t.Fatalf("want hogCount/lightCount in [0.5, 2]; got %d/%d = %g", hogCount, lightCount, float64(hogCount)/float64(lightCount)) + } +} + +func BenchmarkPingPongHog(b *testing.B) { + defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1)) + + // Create a CPU hog + stop, done := make(chan bool), make(chan bool) + go func() { + for { + select { + case <-stop: + done <- true + return + default: + } + } + }() + + // Ping-pong b.N times + ping, pong := make(chan bool), make(chan bool) + go func() { + for j := 0; j < b.N; j++ { + pong <- <-ping + } + close(stop) + done <- true + }() + go func() { + for i := 0; i < b.N; i++ { + ping <- <-pong + } + done <- true + }() + b.ResetTimer() + ping <- true // Start ping-pong + <-stop + b.StopTimer() + <-ping // Let last ponger exit + <-done // Make sure goroutines exit + <-done + <-done +} + func stackGrowthRecursive(i int) { var pad [128]uint64 if i != 0 && pad[0] == 0 { @@ -364,13 +466,17 @@ func nonleaf(stop chan int) bool { } } +/* func TestSchedLocalQueue(t *testing.T) { runtime.TestSchedLocalQueue1() } +*/ +/* func TestSchedLocalQueueSteal(t *testing.T) { runtime.TestSchedLocalQueueSteal1() } +*/ func benchmarkStackGrowth(b *testing.B, rec int) { b.RunParallel(func(pb *testing.PB) { @@ -414,6 +520,37 @@ func benchmarkCreateGoroutines(b *testing.B, procs int) { } } +func BenchmarkCreateGoroutinesCapture(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + const N = 4 + var wg sync.WaitGroup + wg.Add(N) + for i := 0; i < N; i++ { + i := i + go func() { + if i >= N { + b.Logf("bad") // just to capture b + } + wg.Done() + }() + } + wg.Wait() + } +} + +func BenchmarkClosureCall(b *testing.B) { + sum := 0 + off1 := 1 + for i := 0; i < b.N; i++ { + off2 := 2 + func() { + sum += i + off1 + off2 + }() + } + _ = sum +} + type Matrix [][]float64 func BenchmarkMatmult(b *testing.B) { diff --git a/libgo/go/runtime/race0.go b/libgo/go/runtime/race0.go deleted file mode 100644 index 5d90cc859a2..00000000000 --- a/libgo/go/runtime/race0.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build !race - -// Dummy race detection API, used when not built with -race. - -package runtime - -import ( - "unsafe" -) - -const raceenabled = false - -// Because raceenabled is false, none of these functions should be called. - -func raceReadObjectPC(t *_type, addr unsafe.Pointer, callerpc, pc uintptr) { gothrow("race") } -func raceWriteObjectPC(t *_type, addr unsafe.Pointer, callerpc, pc uintptr) { gothrow("race") } -func raceinit() { gothrow("race") } -func racefini() { gothrow("race") } -func racemapshadow(addr unsafe.Pointer, size uintptr) { gothrow("race") } -func racewritepc(addr unsafe.Pointer, callerpc, pc uintptr) { gothrow("race") } -func racereadpc(addr unsafe.Pointer, callerpc, pc uintptr) { gothrow("race") } -func racereadrangepc(addr unsafe.Pointer, sz, callerpc, pc uintptr) { gothrow("race") } -func racewriterangepc(addr unsafe.Pointer, sz, callerpc, pc uintptr) { gothrow("race") } -func raceacquire(addr unsafe.Pointer) { gothrow("race") } -func raceacquireg(gp *g, addr unsafe.Pointer) { gothrow("race") } -func racerelease(addr unsafe.Pointer) { gothrow("race") } -func racereleaseg(gp *g, addr unsafe.Pointer) { gothrow("race") } -func racereleasemerge(addr unsafe.Pointer) { gothrow("race") } -func racereleasemergeg(gp *g, addr unsafe.Pointer) { gothrow("race") } -func racefingo() { gothrow("race") } -func racemalloc(p unsafe.Pointer, sz uintptr) { gothrow("race") } -func racegostart(pc uintptr) uintptr { gothrow("race"); return 0 } -func racegoend() { gothrow("race") } diff --git a/libgo/go/runtime/rdebug.go b/libgo/go/runtime/rdebug.go deleted file mode 100644 index e5e691122c6..00000000000 --- a/libgo/go/runtime/rdebug.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -func setMaxStack(in int) (out int) { - out = int(maxstacksize) - maxstacksize = uintptr(in) - return out -} - -func setGCPercent(in int32) (out int32) { - mp := acquirem() - mp.scalararg[0] = uintptr(int(in)) - onM(setgcpercent_m) - out = int32(int(mp.scalararg[0])) - releasem(mp) - return out -} - -func setPanicOnFault(new bool) (old bool) { - mp := acquirem() - old = mp.curg.paniconfault - mp.curg.paniconfault = new - releasem(mp) - return old -} - -func setMaxThreads(in int) (out int) { - mp := acquirem() - mp.scalararg[0] = uintptr(in) - onM(setmaxthreads_m) - out = int(mp.scalararg[0]) - releasem(mp) - return out -} diff --git a/libgo/go/runtime/rune.go b/libgo/go/runtime/rune.go deleted file mode 100644 index a9f6835818d..00000000000 --- a/libgo/go/runtime/rune.go +++ /dev/null @@ -1,219 +0,0 @@ -/* - * The authors of this software are Rob Pike and Ken Thompson. - * Copyright (c) 2002 by Lucent Technologies. - * Portions Copyright 2009 The Go Authors. All rights reserved. - * Permission to use, copy, modify, and distribute this software for any - * purpose without fee is hereby granted, provided that this entire notice - * is included in all copies of any software which is or includes a copy - * or modification of this software and in all copies of the supporting - * documentation for such software. - * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY - * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY - * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. - */ - -/* - * This code is copied, with slight editing due to type differences, - * from a subset of ../lib9/utf/rune.c - */ - -package runtime - -const ( - bit1 = 7 - bitx = 6 - bit2 = 5 - bit3 = 4 - bit4 = 3 - bit5 = 2 - - t1 = ((1 << (bit1 + 1)) - 1) ^ 0xFF /* 0000 0000 */ - tx = ((1 << (bitx + 1)) - 1) ^ 0xFF /* 1000 0000 */ - t2 = ((1 << (bit2 + 1)) - 1) ^ 0xFF /* 1100 0000 */ - t3 = ((1 << (bit3 + 1)) - 1) ^ 0xFF /* 1110 0000 */ - t4 = ((1 << (bit4 + 1)) - 1) ^ 0xFF /* 1111 0000 */ - t5 = ((1 << (bit5 + 1)) - 1) ^ 0xFF /* 1111 1000 */ - - rune1 = (1 << (bit1 + 0*bitx)) - 1 /* 0000 0000 0111 1111 */ - rune2 = (1 << (bit2 + 1*bitx)) - 1 /* 0000 0111 1111 1111 */ - rune3 = (1 << (bit3 + 2*bitx)) - 1 /* 1111 1111 1111 1111 */ - rune4 = (1 << (bit4 + 3*bitx)) - 1 /* 0001 1111 1111 1111 1111 1111 */ - - maskx = (1 << bitx) - 1 /* 0011 1111 */ - testx = maskx ^ 0xFF /* 1100 0000 */ - - runeerror = 0xFFFD - runeself = 0x80 - - surrogateMin = 0xD800 - surrogateMax = 0xDFFF - - bad = runeerror - - runemax = 0x10FFFF /* maximum rune value */ -) - -/* - * Modified by Wei-Hwa Huang, Google Inc., on 2004-09-24 - * This is a slower but "safe" version of the old chartorune - * that works on strings that are not necessarily null-terminated. - * - * If you know for sure that your string is null-terminated, - * chartorune will be a bit faster. - * - * It is guaranteed not to attempt to access "length" - * past the incoming pointer. This is to avoid - * possible access violations. If the string appears to be - * well-formed but incomplete (i.e., to get the whole Rune - * we'd need to read past str+length) then we'll set the Rune - * to Bad and return 0. - * - * Note that if we have decoding problems for other - * reasons, we return 1 instead of 0. - */ -func charntorune(s string) (rune, int) { - /* When we're not allowed to read anything */ - if len(s) <= 0 { - return bad, 1 - } - - /* - * one character sequence (7-bit value) - * 00000-0007F => T1 - */ - c := s[0] - if c < tx { - return rune(c), 1 - } - - // If we can't read more than one character we must stop - if len(s) <= 1 { - return bad, 1 - } - - /* - * two character sequence (11-bit value) - * 0080-07FF => t2 tx - */ - c1 := s[1] ^ tx - if (c1 & testx) != 0 { - return bad, 1 - } - if c < t3 { - if c < t2 { - return bad, 1 - } - l := ((rune(c) << bitx) | rune(c1)) & rune2 - if l <= rune1 { - return bad, 1 - } - return l, 2 - } - - // If we can't read more than two characters we must stop - if len(s) <= 2 { - return bad, 1 - } - - /* - * three character sequence (16-bit value) - * 0800-FFFF => t3 tx tx - */ - c2 := s[2] ^ tx - if (c2 & testx) != 0 { - return bad, 1 - } - if c < t4 { - l := ((((rune(c) << bitx) | rune(c1)) << bitx) | rune(c2)) & rune3 - if l <= rune2 { - return bad, 1 - } - if surrogateMin <= l && l <= surrogateMax { - return bad, 1 - } - return l, 3 - } - - if len(s) <= 3 { - return bad, 1 - } - - /* - * four character sequence (21-bit value) - * 10000-1FFFFF => t4 tx tx tx - */ - c3 := s[3] ^ tx - if (c3 & testx) != 0 { - return bad, 1 - } - if c < t5 { - l := ((((((rune(c) << bitx) | rune(c1)) << bitx) | rune(c2)) << bitx) | rune(c3)) & rune4 - if l <= rune3 || l > runemax { - return bad, 1 - } - return l, 4 - } - - // Support for 5-byte or longer UTF-8 would go here, but - // since we don't have that, we'll just return bad. - return bad, 1 -} - -// runetochar converts r to bytes and writes the result to str. -// returns the number of bytes generated. -func runetochar(str []byte, r rune) int { - /* runes are signed, so convert to unsigned for range check. */ - c := uint32(r) - /* - * one character sequence - * 00000-0007F => 00-7F - */ - if c <= rune1 { - str[0] = byte(c) - return 1 - } - /* - * two character sequence - * 0080-07FF => t2 tx - */ - if c <= rune2 { - str[0] = byte(t2 | (c >> (1 * bitx))) - str[1] = byte(tx | (c & maskx)) - return 2 - } - - /* - * If the rune is out of range or a surrogate half, convert it to the error rune. - * Do this test here because the error rune encodes to three bytes. - * Doing it earlier would duplicate work, since an out of range - * rune wouldn't have fit in one or two bytes. - */ - if c > runemax { - c = runeerror - } - if surrogateMin <= c && c <= surrogateMax { - c = runeerror - } - - /* - * three character sequence - * 0800-FFFF => t3 tx tx - */ - if c <= rune3 { - str[0] = byte(t3 | (c >> (2 * bitx))) - str[1] = byte(tx | ((c >> (1 * bitx)) & maskx)) - str[2] = byte(tx | (c & maskx)) - return 3 - } - - /* - * four character sequence (21-bit value) - * 10000-1FFFFF => t4 tx tx tx - */ - str[0] = byte(t4 | (c >> (3 * bitx))) - str[1] = byte(tx | ((c >> (2 * bitx)) & maskx)) - str[2] = byte(tx | ((c >> (1 * bitx)) & maskx)) - str[3] = byte(tx | (c & maskx)) - return 4 -} diff --git a/libgo/go/runtime/runtime.go b/libgo/go/runtime/runtime.go deleted file mode 100644 index 4e4e1d17a5c..00000000000 --- a/libgo/go/runtime/runtime.go +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -var ticks struct { - lock mutex - val uint64 -} - -var tls0 [8]uintptr // available storage for m0's TLS; not necessarily used; opaque to GC - -// Note: Called by runtime/pprof in addition to runtime code. -func tickspersecond() int64 { - r := int64(atomicload64(&ticks.val)) - if r != 0 { - return r - } - lock(&ticks.lock) - r = int64(ticks.val) - if r == 0 { - t0 := nanotime() - c0 := cputicks() - usleep(100 * 1000) - t1 := nanotime() - c1 := cputicks() - if t1 == t0 { - t1++ - } - r = (c1 - c0) * 1000 * 1000 * 1000 / (t1 - t0) - if r == 0 { - r++ - } - atomicstore64(&ticks.val, uint64(r)) - } - unlock(&ticks.lock) - return r -} - -func makeStringSlice(n int) []string { - return make([]string, n) -} - -// TODO: Move to parfor.go when parfor.c becomes parfor.go. -func parforalloc(nthrmax uint32) *parfor { - return &parfor{ - thr: &make([]parforthread, nthrmax)[0], - nthrmax: nthrmax, - } -} - -var envs []string -var argslice []string - -// called from syscall -func runtime_envs() []string { return envs } - -// called from os -func runtime_args() []string { return argslice } diff --git a/libgo/go/runtime/runtime_test.go b/libgo/go/runtime/runtime_test.go index 8059d1ad9a1..bb8ff718313 100644 --- a/libgo/go/runtime/runtime_test.go +++ b/libgo/go/runtime/runtime_test.go @@ -6,13 +6,8 @@ package runtime_test import ( "io" - // "io/ioutil" - // "os" - // "os/exec" . "runtime" "runtime/debug" - // "strconv" - // "strings" "testing" "unsafe" ) @@ -88,51 +83,6 @@ func BenchmarkDeferMany(b *testing.B) { } } -/* The go tool is not present in gccgo. - -// The profiling signal handler needs to know whether it is executing runtime.gogo. -// The constant RuntimeGogoBytes in arch_*.h gives the size of the function; -// we don't have a way to obtain it from the linker (perhaps someday). -// Test that the constant matches the size determined by 'go tool nm -S'. -// The value reported will include the padding between runtime.gogo and the -// next function in memory. That's fine. -func TestRuntimeGogoBytes(t *testing.T) { - switch GOOS { - case "android", "nacl": - t.Skipf("skipping on %s", GOOS) - } - - dir, err := ioutil.TempDir("", "go-build") - if err != nil { - t.Fatalf("failed to create temp directory: %v", err) - } - defer os.RemoveAll(dir) - - out, err := exec.Command("go", "build", "-o", dir+"/hello", "../../test/helloworld.go").CombinedOutput() - if err != nil { - t.Fatalf("building hello world: %v\n%s", err, out) - } - - out, err = exec.Command("go", "tool", "nm", "-size", dir+"/hello").CombinedOutput() - if err != nil { - t.Fatalf("go tool nm: %v\n%s", err, out) - } - - for _, line := range strings.Split(string(out), "\n") { - f := strings.Fields(line) - if len(f) == 4 && f[3] == "runtime.gogo" { - size, _ := strconv.Atoi(f[1]) - if GogoBytes() != int32(size) { - t.Fatalf("RuntimeGogoBytes = %d, should be %d", GogoBytes(), size) - } - return - } - } - - t.Fatalf("go tool nm did not report size for runtime.gogo") -} -*/ - // golang.org/issue/7063 func TestStopCPUProfilingWithProfilerOff(t *testing.T) { SetCPUProfileRate(0) @@ -176,12 +126,6 @@ var faultAddrs = []uint64{ } func TestSetPanicOnFault(t *testing.T) { - // This currently results in a fault in the signal trampoline on - // dragonfly/386 - see issue 7421. - if GOOS == "dragonfly" && GOARCH == "386" { - t.Skip("skipping test on dragonfly/386") - } - old := debug.SetPanicOnFault(true) defer debug.SetPanicOnFault(old) @@ -250,3 +194,112 @@ func TestEqString(t *testing.T) { } } } + +/* +func TestTrailingZero(t *testing.T) { + // make sure we add padding for structs with trailing zero-sized fields + type T1 struct { + n int32 + z [0]byte + } + if unsafe.Sizeof(T1{}) != 8 { + t.Errorf("sizeof(%#v)==%d, want 8", T1{}, unsafe.Sizeof(T1{})) + } + type T2 struct { + n int64 + z struct{} + } + if unsafe.Sizeof(T2{}) != 8+unsafe.Sizeof(Uintreg(0)) { + t.Errorf("sizeof(%#v)==%d, want %d", T2{}, unsafe.Sizeof(T2{}), 8+unsafe.Sizeof(Uintreg(0))) + } + type T3 struct { + n byte + z [4]struct{} + } + if unsafe.Sizeof(T3{}) != 2 { + t.Errorf("sizeof(%#v)==%d, want 2", T3{}, unsafe.Sizeof(T3{})) + } + // make sure padding can double for both zerosize and alignment + type T4 struct { + a int32 + b int16 + c int8 + z struct{} + } + if unsafe.Sizeof(T4{}) != 8 { + t.Errorf("sizeof(%#v)==%d, want 8", T4{}, unsafe.Sizeof(T4{})) + } + // make sure we don't pad a zero-sized thing + type T5 struct { + } + if unsafe.Sizeof(T5{}) != 0 { + t.Errorf("sizeof(%#v)==%d, want 0", T5{}, unsafe.Sizeof(T5{})) + } +} +*/ + +func TestBadOpen(t *testing.T) { + if GOOS == "windows" || GOOS == "nacl" { + t.Skip("skipping OS that doesn't have open/read/write/close") + } + // make sure we get the correct error code if open fails. Same for + // read/write/close on the resulting -1 fd. See issue 10052. + nonfile := []byte("/notreallyafile") + fd := Open(&nonfile[0], 0, 0) + if fd != -1 { + t.Errorf("open(\"%s\")=%d, want -1", string(nonfile), fd) + } + var buf [32]byte + r := Read(-1, unsafe.Pointer(&buf[0]), int32(len(buf))) + if r != -1 { + t.Errorf("read()=%d, want -1", r) + } + w := Write(^uintptr(0), unsafe.Pointer(&buf[0]), int32(len(buf))) + if w != -1 { + t.Errorf("write()=%d, want -1", w) + } + c := Close(-1) + if c != -1 { + t.Errorf("close()=%d, want -1", c) + } +} + +func TestAppendGrowth(t *testing.T) { + var x []int64 + check := func(want int) { + if cap(x) != want { + t.Errorf("len=%d, cap=%d, want cap=%d", len(x), cap(x), want) + } + } + + check(0) + want := 1 + for i := 1; i <= 100; i++ { + x = append(x, 1) + check(want) + if i&(i-1) == 0 { + want = 2 * i + } + } +} + +var One = []int64{1} + +func TestAppendSliceGrowth(t *testing.T) { + var x []int64 + check := func(want int) { + if cap(x) != want { + t.Errorf("len=%d, cap=%d, want cap=%d", len(x), cap(x), want) + } + } + + check(0) + want := 1 + for i := 1; i <= 100; i++ { + x = append(x, One...) + check(want) + if i&(i-1) == 0 { + want = 2 * i + } + } +} diff --git a/libgo/go/runtime/runtime_unix_test.go b/libgo/go/runtime/runtime_unix_test.go index 963de8cdb82..cfec3326bd7 100644 --- a/libgo/go/runtime/runtime_unix_test.go +++ b/libgo/go/runtime/runtime_unix_test.go @@ -42,7 +42,7 @@ func TestGoroutineProfile(t *testing.T) { if testing.Short() { max = 100 } - stk := make([]runtime.StackRecord, 100) + stk := make([]runtime.StackRecord, 128) for n := 0; n < max; n++ { _, ok := runtime.GoroutineProfile(stk) if !ok { diff --git a/libgo/go/runtime/select.go b/libgo/go/runtime/select.go deleted file mode 100644 index f735a71e2f5..00000000000 --- a/libgo/go/runtime/select.go +++ /dev/null @@ -1,651 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -// This file contains the implementation of Go select statements. - -import "unsafe" - -const ( - debugSelect = false -) - -var ( - chansendpc = funcPC(chansend) - chanrecvpc = funcPC(chanrecv) -) - -func selectsize(size uintptr) uintptr { - selsize := unsafe.Sizeof(_select{}) + - (size-1)*unsafe.Sizeof(_select{}.scase[0]) + - size*unsafe.Sizeof(*_select{}.lockorder) + - size*unsafe.Sizeof(*_select{}.pollorder) - return round(selsize, _Int64Align) -} - -func newselect(sel *_select, selsize int64, size int32) { - if selsize != int64(selectsize(uintptr(size))) { - print("runtime: bad select size ", selsize, ", want ", selectsize(uintptr(size)), "\n") - gothrow("bad select size") - } - sel.tcase = uint16(size) - sel.ncase = 0 - sel.lockorder = (**hchan)(add(unsafe.Pointer(&sel.scase), uintptr(size)*unsafe.Sizeof(_select{}.scase[0]))) - sel.pollorder = (*uint16)(add(unsafe.Pointer(sel.lockorder), uintptr(size)*unsafe.Sizeof(*_select{}.lockorder))) - - if debugSelect { - print("newselect s=", sel, " size=", size, "\n") - } -} - -//go:nosplit -func selectsend(sel *_select, c *hchan, elem unsafe.Pointer) (selected bool) { - // nil cases do not compete - if c != nil { - selectsendImpl(sel, c, getcallerpc(unsafe.Pointer(&sel)), elem, uintptr(unsafe.Pointer(&selected))-uintptr(unsafe.Pointer(&sel))) - } - return -} - -// cut in half to give stack a chance to split -func selectsendImpl(sel *_select, c *hchan, pc uintptr, elem unsafe.Pointer, so uintptr) { - i := sel.ncase - if i >= sel.tcase { - gothrow("selectsend: too many cases") - } - sel.ncase = i + 1 - cas := (*scase)(add(unsafe.Pointer(&sel.scase), uintptr(i)*unsafe.Sizeof(sel.scase[0]))) - - cas.pc = pc - cas._chan = c - cas.so = uint16(so) - cas.kind = _CaseSend - cas.elem = elem - - if debugSelect { - print("selectsend s=", sel, " pc=", hex(cas.pc), " chan=", cas._chan, " so=", cas.so, "\n") - } -} - -//go:nosplit -func selectrecv(sel *_select, c *hchan, elem unsafe.Pointer) (selected bool) { - // nil cases do not compete - if c != nil { - selectrecvImpl(sel, c, getcallerpc(unsafe.Pointer(&sel)), elem, nil, uintptr(unsafe.Pointer(&selected))-uintptr(unsafe.Pointer(&sel))) - } - return -} - -//go:nosplit -func selectrecv2(sel *_select, c *hchan, elem unsafe.Pointer, received *bool) (selected bool) { - // nil cases do not compete - if c != nil { - selectrecvImpl(sel, c, getcallerpc(unsafe.Pointer(&sel)), elem, received, uintptr(unsafe.Pointer(&selected))-uintptr(unsafe.Pointer(&sel))) - } - return -} - -func selectrecvImpl(sel *_select, c *hchan, pc uintptr, elem unsafe.Pointer, received *bool, so uintptr) { - i := sel.ncase - if i >= sel.tcase { - gothrow("selectrecv: too many cases") - } - sel.ncase = i + 1 - cas := (*scase)(add(unsafe.Pointer(&sel.scase), uintptr(i)*unsafe.Sizeof(sel.scase[0]))) - cas.pc = pc - cas._chan = c - cas.so = uint16(so) - cas.kind = _CaseRecv - cas.elem = elem - cas.receivedp = received - - if debugSelect { - print("selectrecv s=", sel, " pc=", hex(cas.pc), " chan=", cas._chan, " so=", cas.so, "\n") - } -} - -//go:nosplit -func selectdefault(sel *_select) (selected bool) { - selectdefaultImpl(sel, getcallerpc(unsafe.Pointer(&sel)), uintptr(unsafe.Pointer(&selected))-uintptr(unsafe.Pointer(&sel))) - return -} - -func selectdefaultImpl(sel *_select, callerpc uintptr, so uintptr) { - i := sel.ncase - if i >= sel.tcase { - gothrow("selectdefault: too many cases") - } - sel.ncase = i + 1 - cas := (*scase)(add(unsafe.Pointer(&sel.scase), uintptr(i)*unsafe.Sizeof(sel.scase[0]))) - cas.pc = callerpc - cas._chan = nil - cas.so = uint16(so) - cas.kind = _CaseDefault - - if debugSelect { - print("selectdefault s=", sel, " pc=", hex(cas.pc), " so=", cas.so, "\n") - } -} - -func sellock(sel *_select) { - lockslice := sliceStruct{unsafe.Pointer(sel.lockorder), int(sel.ncase), int(sel.ncase)} - lockorder := *(*[]*hchan)(unsafe.Pointer(&lockslice)) - var c *hchan - for _, c0 := range lockorder { - if c0 != nil && c0 != c { - c = c0 - lock(&c.lock) - } - } -} - -func selunlock(sel *_select) { - // We must be very careful here to not touch sel after we have unlocked - // the last lock, because sel can be freed right after the last unlock. - // Consider the following situation. - // First M calls runtime·park() in runtime·selectgo() passing the sel. - // Once runtime·park() has unlocked the last lock, another M makes - // the G that calls select runnable again and schedules it for execution. - // When the G runs on another M, it locks all the locks and frees sel. - // Now if the first M touches sel, it will access freed memory. - n := int(sel.ncase) - r := 0 - lockslice := sliceStruct{unsafe.Pointer(sel.lockorder), n, n} - lockorder := *(*[]*hchan)(unsafe.Pointer(&lockslice)) - // skip the default case - if n > 0 && lockorder[0] == nil { - r = 1 - } - for i := n - 1; i >= r; i-- { - c := lockorder[i] - if i > 0 && c == lockorder[i-1] { - continue // will unlock it on the next iteration - } - unlock(&c.lock) - } -} - -func selparkcommit(gp *g, sel *_select) bool { - selunlock(sel) - return true -} - -func block() { - gopark(nil, nil, "select (no cases)") // forever -} - -// overwrites return pc on stack to signal which case of the select -// to run, so cannot appear at the top of a split stack. -//go:nosplit -func selectgo(sel *_select) { - pc, offset := selectgoImpl(sel) - *(*bool)(add(unsafe.Pointer(&sel), uintptr(offset))) = true - setcallerpc(unsafe.Pointer(&sel), pc) -} - -// selectgoImpl returns scase.pc and scase.so for the select -// case which fired. -func selectgoImpl(sel *_select) (uintptr, uint16) { - if debugSelect { - print("select: sel=", sel, "\n") - } - - scaseslice := sliceStruct{unsafe.Pointer(&sel.scase), int(sel.ncase), int(sel.ncase)} - scases := *(*[]scase)(unsafe.Pointer(&scaseslice)) - - var t0 int64 - if blockprofilerate > 0 { - t0 = cputicks() - for i := 0; i < int(sel.ncase); i++ { - scases[i].releasetime = -1 - } - } - - // The compiler rewrites selects that statically have - // only 0 or 1 cases plus default into simpler constructs. - // The only way we can end up with such small sel.ncase - // values here is for a larger select in which most channels - // have been nilled out. The general code handles those - // cases correctly, and they are rare enough not to bother - // optimizing (and needing to test). - - // generate permuted order - pollslice := sliceStruct{unsafe.Pointer(sel.pollorder), int(sel.ncase), int(sel.ncase)} - pollorder := *(*[]uint16)(unsafe.Pointer(&pollslice)) - for i := 0; i < int(sel.ncase); i++ { - pollorder[i] = uint16(i) - } - for i := 1; i < int(sel.ncase); i++ { - o := pollorder[i] - j := int(fastrand1()) % (i + 1) - pollorder[i] = pollorder[j] - pollorder[j] = o - } - - // sort the cases by Hchan address to get the locking order. - // simple heap sort, to guarantee n log n time and constant stack footprint. - lockslice := sliceStruct{unsafe.Pointer(sel.lockorder), int(sel.ncase), int(sel.ncase)} - lockorder := *(*[]*hchan)(unsafe.Pointer(&lockslice)) - for i := 0; i < int(sel.ncase); i++ { - j := i - c := scases[j]._chan - for j > 0 && lockorder[(j-1)/2].sortkey() < c.sortkey() { - k := (j - 1) / 2 - lockorder[j] = lockorder[k] - j = k - } - lockorder[j] = c - } - for i := int(sel.ncase) - 1; i >= 0; i-- { - c := lockorder[i] - lockorder[i] = lockorder[0] - j := 0 - for { - k := j*2 + 1 - if k >= i { - break - } - if k+1 < i && lockorder[k].sortkey() < lockorder[k+1].sortkey() { - k++ - } - if c.sortkey() < lockorder[k].sortkey() { - lockorder[j] = lockorder[k] - j = k - continue - } - break - } - lockorder[j] = c - } - /* - for i := 0; i+1 < int(sel.ncase); i++ { - if lockorder[i].sortkey() > lockorder[i+1].sortkey() { - print("i=", i, " x=", lockorder[i], " y=", lockorder[i+1], "\n") - gothrow("select: broken sort") - } - } - */ - - // lock all the channels involved in the select - sellock(sel) - - var ( - gp *g - done uint32 - sg *sudog - c *hchan - k *scase - sglist *sudog - sgnext *sudog - ) - -loop: - // pass 1 - look for something already waiting - var dfl *scase - var cas *scase - for i := 0; i < int(sel.ncase); i++ { - cas = &scases[pollorder[i]] - c = cas._chan - - switch cas.kind { - case _CaseRecv: - if c.dataqsiz > 0 { - if c.qcount > 0 { - goto asyncrecv - } - } else { - sg = c.sendq.dequeue() - if sg != nil { - goto syncrecv - } - } - if c.closed != 0 { - goto rclose - } - - case _CaseSend: - if raceenabled { - racereadpc(unsafe.Pointer(c), cas.pc, chansendpc) - } - if c.closed != 0 { - goto sclose - } - if c.dataqsiz > 0 { - if c.qcount < c.dataqsiz { - goto asyncsend - } - } else { - sg = c.recvq.dequeue() - if sg != nil { - goto syncsend - } - } - - case _CaseDefault: - dfl = cas - } - } - - if dfl != nil { - selunlock(sel) - cas = dfl - goto retc - } - - // pass 2 - enqueue on all chans - gp = getg() - done = 0 - for i := 0; i < int(sel.ncase); i++ { - cas = &scases[pollorder[i]] - c = cas._chan - sg := acquireSudog() - sg.g = gp - // Note: selectdone is adjusted for stack copies in stack.c:adjustsudogs - sg.selectdone = (*uint32)(noescape(unsafe.Pointer(&done))) - sg.elem = cas.elem - sg.releasetime = 0 - if t0 != 0 { - sg.releasetime = -1 - } - sg.waitlink = gp.waiting - gp.waiting = sg - - switch cas.kind { - case _CaseRecv: - c.recvq.enqueue(sg) - - case _CaseSend: - c.sendq.enqueue(sg) - } - } - - // wait for someone to wake us up - gp.param = nil - gopark(unsafe.Pointer(funcPC(selparkcommit)), unsafe.Pointer(sel), "select") - - // someone woke us up - sellock(sel) - sg = (*sudog)(gp.param) - gp.param = nil - - // pass 3 - dequeue from unsuccessful chans - // otherwise they stack up on quiet channels - // record the successful case, if any. - // We singly-linked up the SudoGs in case order, so when - // iterating through the linked list they are in reverse order. - cas = nil - sglist = gp.waiting - // Clear all selectdone and elem before unlinking from gp.waiting. - // They must be cleared before being put back into the sudog cache. - // Clear before unlinking, because if a stack copy happens after the unlink, - // they will not be updated, they will be left pointing to the old stack, - // which creates dangling pointers, which may be detected by the - // garbage collector. - for sg1 := gp.waiting; sg1 != nil; sg1 = sg1.waitlink { - sg1.selectdone = nil - sg1.elem = nil - } - gp.waiting = nil - for i := int(sel.ncase) - 1; i >= 0; i-- { - k = &scases[pollorder[i]] - if sglist.releasetime > 0 { - k.releasetime = sglist.releasetime - } - if sg == sglist { - cas = k - } else { - c = k._chan - if k.kind == _CaseSend { - c.sendq.dequeueSudoG(sglist) - } else { - c.recvq.dequeueSudoG(sglist) - } - } - sgnext = sglist.waitlink - sglist.waitlink = nil - releaseSudog(sglist) - sglist = sgnext - } - - if cas == nil { - goto loop - } - - c = cas._chan - - if c.dataqsiz > 0 { - gothrow("selectgo: shouldn't happen") - } - - if debugSelect { - print("wait-return: sel=", sel, " c=", c, " cas=", cas, " kind=", cas.kind, "\n") - } - - if cas.kind == _CaseRecv { - if cas.receivedp != nil { - *cas.receivedp = true - } - } - - if raceenabled { - if cas.kind == _CaseRecv && cas.elem != nil { - raceWriteObjectPC(c.elemtype, cas.elem, cas.pc, chanrecvpc) - } else if cas.kind == _CaseSend { - raceReadObjectPC(c.elemtype, cas.elem, cas.pc, chansendpc) - } - } - - selunlock(sel) - goto retc - -asyncrecv: - // can receive from buffer - if raceenabled { - if cas.elem != nil { - raceWriteObjectPC(c.elemtype, cas.elem, cas.pc, chanrecvpc) - } - raceacquire(chanbuf(c, c.recvx)) - racerelease(chanbuf(c, c.recvx)) - } - if cas.receivedp != nil { - *cas.receivedp = true - } - if cas.elem != nil { - memmove(cas.elem, chanbuf(c, c.recvx), uintptr(c.elemsize)) - } - memclr(chanbuf(c, c.recvx), uintptr(c.elemsize)) - c.recvx++ - if c.recvx == c.dataqsiz { - c.recvx = 0 - } - c.qcount-- - sg = c.sendq.dequeue() - if sg != nil { - gp = sg.g - selunlock(sel) - if sg.releasetime != 0 { - sg.releasetime = cputicks() - } - goready(gp) - } else { - selunlock(sel) - } - goto retc - -asyncsend: - // can send to buffer - if raceenabled { - raceacquire(chanbuf(c, c.sendx)) - racerelease(chanbuf(c, c.sendx)) - raceReadObjectPC(c.elemtype, cas.elem, cas.pc, chansendpc) - } - memmove(chanbuf(c, c.sendx), cas.elem, uintptr(c.elemsize)) - c.sendx++ - if c.sendx == c.dataqsiz { - c.sendx = 0 - } - c.qcount++ - sg = c.recvq.dequeue() - if sg != nil { - gp = sg.g - selunlock(sel) - if sg.releasetime != 0 { - sg.releasetime = cputicks() - } - goready(gp) - } else { - selunlock(sel) - } - goto retc - -syncrecv: - // can receive from sleeping sender (sg) - if raceenabled { - if cas.elem != nil { - raceWriteObjectPC(c.elemtype, cas.elem, cas.pc, chanrecvpc) - } - racesync(c, sg) - } - selunlock(sel) - if debugSelect { - print("syncrecv: sel=", sel, " c=", c, "\n") - } - if cas.receivedp != nil { - *cas.receivedp = true - } - if cas.elem != nil { - memmove(cas.elem, sg.elem, uintptr(c.elemsize)) - } - sg.elem = nil - gp = sg.g - gp.param = unsafe.Pointer(sg) - if sg.releasetime != 0 { - sg.releasetime = cputicks() - } - goready(gp) - goto retc - -rclose: - // read at end of closed channel - selunlock(sel) - if cas.receivedp != nil { - *cas.receivedp = false - } - if cas.elem != nil { - memclr(cas.elem, uintptr(c.elemsize)) - } - if raceenabled { - raceacquire(unsafe.Pointer(c)) - } - goto retc - -syncsend: - // can send to sleeping receiver (sg) - if raceenabled { - raceReadObjectPC(c.elemtype, cas.elem, cas.pc, chansendpc) - racesync(c, sg) - } - selunlock(sel) - if debugSelect { - print("syncsend: sel=", sel, " c=", c, "\n") - } - if sg.elem != nil { - memmove(sg.elem, cas.elem, uintptr(c.elemsize)) - } - sg.elem = nil - gp = sg.g - gp.param = unsafe.Pointer(sg) - if sg.releasetime != 0 { - sg.releasetime = cputicks() - } - goready(gp) - -retc: - if cas.releasetime > 0 { - blockevent(cas.releasetime-t0, 2) - } - return cas.pc, cas.so - -sclose: - // send on closed channel - selunlock(sel) - panic("send on closed channel") -} - -func (c *hchan) sortkey() uintptr { - // TODO(khr): if we have a moving garbage collector, we'll need to - // change this function. - return uintptr(unsafe.Pointer(c)) -} - -// A runtimeSelect is a single case passed to rselect. -// This must match ../reflect/value.go:/runtimeSelect -type runtimeSelect struct { - dir selectDir - typ unsafe.Pointer // channel type (not used here) - ch *hchan // channel - val unsafe.Pointer // ptr to data (SendDir) or ptr to receive buffer (RecvDir) -} - -// These values must match ../reflect/value.go:/SelectDir. -type selectDir int - -const ( - _ selectDir = iota - selectSend // case Chan <- Send - selectRecv // case <-Chan: - selectDefault // default -) - -func reflect_rselect(cases []runtimeSelect) (chosen int, recvOK bool) { - // flagNoScan is safe here, because all objects are also referenced from cases. - size := selectsize(uintptr(len(cases))) - sel := (*_select)(mallocgc(size, nil, flagNoScan)) - newselect(sel, int64(size), int32(len(cases))) - r := new(bool) - for i := range cases { - rc := &cases[i] - switch rc.dir { - case selectDefault: - selectdefaultImpl(sel, uintptr(i), 0) - case selectSend: - if rc.ch == nil { - break - } - selectsendImpl(sel, rc.ch, uintptr(i), rc.val, 0) - case selectRecv: - if rc.ch == nil { - break - } - selectrecvImpl(sel, rc.ch, uintptr(i), rc.val, r, 0) - } - } - - pc, _ := selectgoImpl(sel) - chosen = int(pc) - recvOK = *r - return -} - -func (q *waitq) dequeueSudoG(s *sudog) { - var prevsgp *sudog - l := &q.first - for { - sgp := *l - if sgp == nil { - return - } - if sgp == s { - *l = sgp.next - if q.last == sgp { - q.last = prevsgp - } - s.next = nil - return - } - l = &sgp.next - prevsgp = sgp - } -} diff --git a/libgo/go/runtime/sema.go b/libgo/go/runtime/sema.go deleted file mode 100644 index 26dbd30ea3f..00000000000 --- a/libgo/go/runtime/sema.go +++ /dev/null @@ -1,275 +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. - -// Semaphore implementation exposed to Go. -// Intended use is provide a sleep and wakeup -// primitive that can be used in the contended case -// of other synchronization primitives. -// Thus it targets the same goal as Linux's futex, -// but it has much simpler semantics. -// -// That is, don't think of these as semaphores. -// Think of them as a way to implement sleep and wakeup -// such that every sleep is paired with a single wakeup, -// even if, due to races, the wakeup happens before the sleep. -// -// See Mullender and Cox, ``Semaphores in Plan 9,'' -// http://swtch.com/semaphore.pdf - -package runtime - -import "unsafe" - -// Asynchronous semaphore for sync.Mutex. - -type semaRoot struct { - lock mutex - head *sudog - tail *sudog - nwait uint32 // Number of waiters. Read w/o the lock. -} - -// Prime to not correlate with any user patterns. -const semTabSize = 251 - -var semtable [semTabSize]struct { - root semaRoot - pad [_CacheLineSize - unsafe.Sizeof(semaRoot{})]byte -} - -// Called from sync/net packages. -func asyncsemacquire(addr *uint32) { - semacquire(addr, true) -} - -func asyncsemrelease(addr *uint32) { - semrelease(addr) -} - -// Called from runtime. -func semacquire(addr *uint32, profile bool) { - gp := getg() - if gp != gp.m.curg { - gothrow("semacquire not on the G stack") - } - - // Easy case. - if cansemacquire(addr) { - return - } - - // Harder case: - // increment waiter count - // try cansemacquire one more time, return if succeeded - // enqueue itself as a waiter - // sleep - // (waiter descriptor is dequeued by signaler) - s := acquireSudog() - root := semroot(addr) - t0 := int64(0) - s.releasetime = 0 - if profile && blockprofilerate > 0 { - t0 = cputicks() - s.releasetime = -1 - } - for { - lock(&root.lock) - // Add ourselves to nwait to disable "easy case" in semrelease. - xadd(&root.nwait, 1) - // Check cansemacquire to avoid missed wakeup. - if cansemacquire(addr) { - xadd(&root.nwait, -1) - unlock(&root.lock) - break - } - // Any semrelease after the cansemacquire knows we're waiting - // (we set nwait above), so go to sleep. - root.queue(addr, s) - goparkunlock(&root.lock, "semacquire") - if cansemacquire(addr) { - break - } - } - if s.releasetime > 0 { - blockevent(int64(s.releasetime)-t0, 3) - } - releaseSudog(s) -} - -func semrelease(addr *uint32) { - root := semroot(addr) - xadd(addr, 1) - - // Easy case: no waiters? - // This check must happen after the xadd, to avoid a missed wakeup - // (see loop in semacquire). - if atomicload(&root.nwait) == 0 { - return - } - - // Harder case: search for a waiter and wake it. - lock(&root.lock) - if atomicload(&root.nwait) == 0 { - // The count is already consumed by another goroutine, - // so no need to wake up another goroutine. - unlock(&root.lock) - return - } - s := root.head - for ; s != nil; s = s.next { - if s.elem == unsafe.Pointer(addr) { - xadd(&root.nwait, -1) - root.dequeue(s) - break - } - } - unlock(&root.lock) - if s != nil { - if s.releasetime != 0 { - s.releasetime = cputicks() - } - goready(s.g) - } -} - -func semroot(addr *uint32) *semaRoot { - return &semtable[(uintptr(unsafe.Pointer(addr))>>3)%semTabSize].root -} - -func cansemacquire(addr *uint32) bool { - for { - v := atomicload(addr) - if v == 0 { - return false - } - if cas(addr, v, v-1) { - return true - } - } -} - -func (root *semaRoot) queue(addr *uint32, s *sudog) { - s.g = getg() - s.elem = unsafe.Pointer(addr) - s.next = nil - s.prev = root.tail - if root.tail != nil { - root.tail.next = s - } else { - root.head = s - } - root.tail = s -} - -func (root *semaRoot) dequeue(s *sudog) { - if s.next != nil { - s.next.prev = s.prev - } else { - root.tail = s.prev - } - if s.prev != nil { - s.prev.next = s.next - } else { - root.head = s.next - } - s.elem = nil - s.next = nil - s.prev = nil -} - -// Synchronous semaphore for sync.Cond. -type syncSema struct { - lock mutex - head *sudog - tail *sudog -} - -// Syncsemacquire waits for a pairing syncsemrelease on the same semaphore s. -func syncsemacquire(s *syncSema) { - lock(&s.lock) - if s.head != nil && s.head.nrelease > 0 { - // Have pending release, consume it. - var wake *sudog - s.head.nrelease-- - if s.head.nrelease == 0 { - wake = s.head - s.head = wake.next - if s.head == nil { - s.tail = nil - } - } - unlock(&s.lock) - if wake != nil { - wake.next = nil - goready(wake.g) - } - } else { - // Enqueue itself. - w := acquireSudog() - w.g = getg() - w.nrelease = -1 - w.next = nil - w.releasetime = 0 - t0 := int64(0) - if blockprofilerate > 0 { - t0 = cputicks() - w.releasetime = -1 - } - if s.tail == nil { - s.head = w - } else { - s.tail.next = w - } - s.tail = w - goparkunlock(&s.lock, "semacquire") - if t0 != 0 { - blockevent(int64(w.releasetime)-t0, 2) - } - releaseSudog(w) - } -} - -// Syncsemrelease waits for n pairing syncsemacquire on the same semaphore s. -func syncsemrelease(s *syncSema, n uint32) { - lock(&s.lock) - for n > 0 && s.head != nil && s.head.nrelease < 0 { - // Have pending acquire, satisfy it. - wake := s.head - s.head = wake.next - if s.head == nil { - s.tail = nil - } - if wake.releasetime != 0 { - wake.releasetime = cputicks() - } - wake.next = nil - goready(wake.g) - n-- - } - if n > 0 { - // enqueue itself - w := acquireSudog() - w.g = getg() - w.nrelease = int32(n) - w.next = nil - w.releasetime = 0 - if s.tail == nil { - s.head = w - } else { - s.tail.next = w - } - s.tail = w - goparkunlock(&s.lock, "semarelease") - releaseSudog(w) - } else { - unlock(&s.lock) - } -} - -func syncsemcheck(sz uintptr) { - if sz != unsafe.Sizeof(syncSema{}) { - print("runtime: bad syncSema size - sync=", sz, " runtime=", unsafe.Sizeof(syncSema{}), "\n") - gothrow("bad syncSema size") - } -} diff --git a/libgo/go/runtime/signal_unix.go b/libgo/go/runtime/signal_unix.go deleted file mode 100644 index ba77b6e7be1..00000000000 --- a/libgo/go/runtime/signal_unix.go +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build darwin dragonfly freebsd linux netbsd openbsd solaris - -package runtime - -func sigpipe() - -func os_sigpipe() { - onM(sigpipe) -} diff --git a/libgo/go/runtime/sigpanic_unix.go b/libgo/go/runtime/sigpanic_unix.go deleted file mode 100644 index 68079859b06..00000000000 --- a/libgo/go/runtime/sigpanic_unix.go +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build darwin dragonfly freebsd linux netbsd openbsd solaris - -package runtime - -func signame(int32) *byte - -func sigpanic() { - g := getg() - if !canpanic(g) { - gothrow("unexpected signal during runtime execution") - } - - switch g.sig { - case _SIGBUS: - if g.sigcode0 == _BUS_ADRERR && g.sigcode1 < 0x1000 || g.paniconfault { - panicmem() - } - print("unexpected fault address ", hex(g.sigcode1), "\n") - gothrow("fault") - case _SIGSEGV: - if (g.sigcode0 == 0 || g.sigcode0 == _SEGV_MAPERR || g.sigcode0 == _SEGV_ACCERR) && g.sigcode1 < 0x1000 || g.paniconfault { - panicmem() - } - print("unexpected fault address ", hex(g.sigcode1), "\n") - gothrow("fault") - case _SIGFPE: - switch g.sigcode0 { - case _FPE_INTDIV: - panicdivide() - case _FPE_INTOVF: - panicoverflow() - } - panicfloat() - } - panic(errorString(gostringnocopy(signame(g.sig)))) -} diff --git a/libgo/go/runtime/sigqueue.go b/libgo/go/runtime/sigqueue.go deleted file mode 100644 index fed4560fe33..00000000000 --- a/libgo/go/runtime/sigqueue.go +++ /dev/null @@ -1,182 +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 runtime support for signal handling. -// -// Most synchronization primitives are not available from -// the signal handler (it cannot block, allocate memory, or use locks) -// so the handler communicates with a processing goroutine -// via struct sig, below. -// -// sigsend is called by the signal handler to queue a new signal. -// signal_recv is called by the Go program to receive a newly queued signal. -// Synchronization between sigsend and signal_recv is based on the sig.state -// variable. It can be in 3 states: sigIdle, sigReceiving and sigSending. -// sigReceiving means that signal_recv is blocked on sig.Note and there are no -// new pending signals. -// sigSending means that sig.mask *may* contain new pending signals, -// signal_recv can't be blocked in this state. -// sigIdle means that there are no new pending signals and signal_recv is not blocked. -// Transitions between states are done atomically with CAS. -// When signal_recv is unblocked, it resets sig.Note and rechecks sig.mask. -// If several sigsends and signal_recv execute concurrently, it can lead to -// unnecessary rechecks of sig.mask, but it cannot lead to missed signals -// nor deadlocks. - -package runtime - -import "unsafe" - -var sig struct { - note note - mask [(_NSIG + 31) / 32]uint32 - wanted [(_NSIG + 31) / 32]uint32 - recv [(_NSIG + 31) / 32]uint32 - state uint32 - inuse bool -} - -const ( - sigIdle = iota - sigReceiving - sigSending -) - -// Called from sighandler to send a signal back out of the signal handling thread. -// Reports whether the signal was sent. If not, the caller typically crashes the program. -func sigsend(s int32) bool { - bit := uint32(1) << uint(s&31) - if !sig.inuse || s < 0 || int(s) >= 32*len(sig.wanted) || sig.wanted[s/32]&bit == 0 { - return false - } - - // Add signal to outgoing queue. - for { - mask := sig.mask[s/32] - if mask&bit != 0 { - return true // signal already in queue - } - if cas(&sig.mask[s/32], mask, mask|bit) { - break - } - } - - // Notify receiver that queue has new bit. -Send: - for { - switch atomicload(&sig.state) { - default: - gothrow("sigsend: inconsistent state") - case sigIdle: - if cas(&sig.state, sigIdle, sigSending) { - break Send - } - case sigSending: - // notification already pending - break Send - case sigReceiving: - if cas(&sig.state, sigReceiving, sigIdle) { - notewakeup(&sig.note) - break Send - } - } - } - - return true -} - -// Called to receive the next queued signal. -// Must only be called from a single goroutine at a time. -func signal_recv() uint32 { - for { - // Serve any signals from local copy. - for i := uint32(0); i < _NSIG; i++ { - if sig.recv[i/32]&(1<<(i&31)) != 0 { - sig.recv[i/32] &^= 1 << (i & 31) - return i - } - } - - // Wait for updates to be available from signal sender. - Receive: - for { - switch atomicload(&sig.state) { - default: - gothrow("signal_recv: inconsistent state") - case sigIdle: - if cas(&sig.state, sigIdle, sigReceiving) { - notetsleepg(&sig.note, -1) - noteclear(&sig.note) - break Receive - } - case sigSending: - if cas(&sig.state, sigSending, sigIdle) { - break Receive - } - } - } - - // Incorporate updates from sender into local copy. - for i := range sig.mask { - sig.recv[i] = xchg(&sig.mask[i], 0) - } - } -} - -// Must only be called from a single goroutine at a time. -func signal_enable(s uint32) { - if !sig.inuse { - // The first call to signal_enable is for us - // to use for initialization. It does not pass - // signal information in m. - sig.inuse = true // enable reception of signals; cannot disable - noteclear(&sig.note) - return - } - - if int(s) >= len(sig.wanted)*32 { - return - } - sig.wanted[s/32] |= 1 << (s & 31) - sigenable_go(s) -} - -// Must only be called from a single goroutine at a time. -func signal_disable(s uint32) { - if int(s) >= len(sig.wanted)*32 { - return - } - sig.wanted[s/32] &^= 1 << (s & 31) - sigdisable_go(s) -} - -// This runs on a foreign stack, without an m or a g. No stack split. -//go:nosplit -func badsignal(sig uintptr) { - // Some external libraries, for example, OpenBLAS, create worker threads in - // a global constructor. If we're doing cpu profiling, and the SIGPROF signal - // comes to one of the foreign threads before we make our first cgo call, the - // call to cgocallback below will bring down the whole process. - // It's better to miss a few SIGPROF signals than to abort in this case. - // See http://golang.org/issue/9456. - if _SIGPROF != 0 && sig == _SIGPROF && needextram != 0 { - return - } - cgocallback(unsafe.Pointer(funcPC(sigsend)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig)) -} - -func sigenable_m() -func sigdisable_m() - -func sigenable_go(s uint32) { - g := getg() - g.m.scalararg[0] = uintptr(s) - onM(sigenable_m) -} - -func sigdisable_go(s uint32) { - g := getg() - g.m.scalararg[0] = uintptr(s) - onM(sigdisable_m) -} diff --git a/libgo/go/runtime/slice.go b/libgo/go/runtime/slice.go deleted file mode 100644 index 171087d7f6f..00000000000 --- a/libgo/go/runtime/slice.go +++ /dev/null @@ -1,139 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -import ( - "unsafe" -) - -type sliceStruct struct { - array unsafe.Pointer - len int - cap int -} - -// TODO: take uintptrs instead of int64s? -func makeslice(t *slicetype, len64 int64, cap64 int64) sliceStruct { - // NOTE: The len > MaxMem/elemsize check here is not strictly necessary, - // but it produces a 'len out of range' error instead of a 'cap out of range' error - // when someone does make([]T, bignumber). 'cap out of range' is true too, - // but since the cap is only being supplied implicitly, saying len is clearer. - // See issue 4085. - len := int(len64) - if len64 < 0 || int64(len) != len64 || t.elem.size > 0 && uintptr(len) > maxmem/uintptr(t.elem.size) { - panic(errorString("makeslice: len out of range")) - } - cap := int(cap64) - if cap < len || int64(cap) != cap64 || t.elem.size > 0 && uintptr(cap) > maxmem/uintptr(t.elem.size) { - panic(errorString("makeslice: cap out of range")) - } - p := newarray(t.elem, uintptr(cap)) - return sliceStruct{p, len, cap} -} - -// TODO: take uintptr instead of int64? -func growslice(t *slicetype, old sliceStruct, n int64) sliceStruct { - if n < 1 { - panic(errorString("growslice: invalid n")) - } - - cap64 := int64(old.cap) + n - cap := int(cap64) - - if int64(cap) != cap64 || cap < old.cap || t.elem.size > 0 && uintptr(cap) > maxmem/uintptr(t.elem.size) { - panic(errorString("growslice: cap out of range")) - } - - if raceenabled { - callerpc := getcallerpc(unsafe.Pointer(&t)) - racereadrangepc(old.array, uintptr(old.len*int(t.elem.size)), callerpc, funcPC(growslice)) - } - - et := t.elem - if et.size == 0 { - return sliceStruct{old.array, old.len, cap} - } - - newcap := old.cap - if newcap+newcap < cap { - newcap = cap - } else { - for { - if old.len < 1024 { - newcap += newcap - } else { - newcap += newcap / 4 - } - if newcap >= cap { - break - } - } - } - - if uintptr(newcap) >= maxmem/uintptr(et.size) { - panic(errorString("growslice: cap out of range")) - } - lenmem := uintptr(old.len) * uintptr(et.size) - capmem := goroundupsize(uintptr(newcap) * uintptr(et.size)) - newcap = int(capmem / uintptr(et.size)) - var p unsafe.Pointer - if et.kind&kindNoPointers != 0 { - p = rawmem(capmem) - memclr(add(p, lenmem), capmem-lenmem) - } else { - // Note: can't use rawmem (which avoids zeroing of memory), because then GC can scan unitialized memory - p = newarray(et, uintptr(newcap)) - } - memmove(p, old.array, lenmem) - - return sliceStruct{p, old.len, newcap} -} - -func slicecopy(to sliceStruct, fm sliceStruct, width uintptr) int { - if fm.len == 0 || to.len == 0 || width == 0 { - return 0 - } - - n := fm.len - if to.len < n { - n = to.len - } - - if raceenabled { - callerpc := getcallerpc(unsafe.Pointer(&to)) - pc := funcPC(slicecopy) - racewriterangepc(to.array, uintptr(n*int(width)), callerpc, pc) - racereadrangepc(fm.array, uintptr(n*int(width)), callerpc, pc) - } - - size := uintptr(n) * width - if size == 1 { // common case worth about 2x to do here - // TODO: is this still worth it with new memmove impl? - *(*byte)(to.array) = *(*byte)(fm.array) // known to be a byte pointer - } else { - memmove(to.array, fm.array, size) - } - return int(n) -} - -func slicestringcopy(to []byte, fm string) int { - if len(fm) == 0 || len(to) == 0 { - return 0 - } - - n := len(fm) - if len(to) < n { - n = len(to) - } - - if raceenabled { - callerpc := getcallerpc(unsafe.Pointer(&to)) - pc := funcPC(slicestringcopy) - racewriterangepc(unsafe.Pointer(&to[0]), uintptr(n), callerpc, pc) - } - - memmove(unsafe.Pointer(&to[0]), unsafe.Pointer((*stringStruct)(unsafe.Pointer(&fm)).str), uintptr(n)) - return n -} diff --git a/libgo/go/runtime/softfloat64.go b/libgo/go/runtime/softfloat64.go deleted file mode 100644 index 4fcf8f26901..00000000000 --- a/libgo/go/runtime/softfloat64.go +++ /dev/null @@ -1,498 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Software IEEE754 64-bit floating point. -// Only referred to (and thus linked in) by arm port -// and by tests in this directory. - -package runtime - -const ( - mantbits64 uint = 52 - expbits64 uint = 11 - bias64 = -1<<(expbits64-1) + 1 - - nan64 uint64 = (1<>mantbits64) & (1<>mantbits32) & (1<= 4<>= 1 - exp++ - } - if mant >= 2<= 4<>= 1 - exp++ - } - } - mant >>= 1 - exp++ - } - if exp >= 1<>= 1 - exp++ - } - if mant&1 != 0 && (trunc != 0 || mant&2 != 0) { - mant++ - } - mant >>= 1 - exp++ - if mant < 1<= 4<>= 1 - exp++ - } - if mant >= 2<= 4<>= 1 - exp++ - } - } - mant >>= 1 - exp++ - } - if exp >= 1<>= 1 - exp++ - } - if mant&1 != 0 && (trunc != 0 || mant&2 != 0) { - mant++ - } - mant >>= 1 - exp++ - if mant < 1<>= shift - if fs == gs { - fm += gm - } else { - fm -= gm - if trunc != 0 { - fm-- - } - } - if fm == 0 { - fs = 0 - } - return fpack64(fs, fm, fe-2, trunc) -} - -func fsub64(f, g uint64) uint64 { - return fadd64(f, fneg64(g)) -} - -func fneg64(f uint64) uint64 { - return f ^ (1 << (mantbits64 + expbits64)) -} - -func fmul64(f, g uint64) uint64 { - fs, fm, fe, fi, fn := funpack64(f) - gs, gm, ge, gi, gn := funpack64(g) - - // Special cases. - switch { - case fn || gn: // NaN * g or f * NaN = NaN - return nan64 - - case fi && gi: // Inf * Inf = Inf (with sign adjusted) - return f ^ gs - - case fi && gm == 0, fm == 0 && gi: // 0 * Inf = Inf * 0 = NaN - return nan64 - - case fm == 0: // 0 * x = 0 (with sign adjusted) - return f ^ gs - - case gm == 0: // x * 0 = 0 (with sign adjusted) - return g ^ fs - } - - // 53-bit * 53-bit = 107- or 108-bit - lo, hi := mullu(fm, gm) - shift := mantbits64 - 1 - trunc := lo & (1<>shift - return fpack64(fs^gs, mant, fe+ge-1, trunc) -} - -func fdiv64(f, g uint64) uint64 { - fs, fm, fe, fi, fn := funpack64(f) - gs, gm, ge, gi, gn := funpack64(g) - - // Special cases. - switch { - case fn || gn: // NaN / g = f / NaN = NaN - return nan64 - - case fi && gi: // ±Inf / ±Inf = NaN - return nan64 - - case !fi && !gi && fm == 0 && gm == 0: // 0 / 0 = NaN - return nan64 - - case fi, !gi && gm == 0: // Inf / g = f / 0 = Inf - return fs ^ gs ^ inf64 - - case gi, fm == 0: // f / Inf = 0 / g = Inf - return fs ^ gs ^ 0 - } - _, _, _, _ = fi, fn, gi, gn - - // 53-bit<<54 / 53-bit = 53- or 54-bit. - shift := mantbits64 + 2 - q, r := divlu(fm>>(64-shift), fm<> 32) - if fi { - return fs32 ^ inf32 - } - const d = mantbits64 - mantbits32 - 1 - return fpack32(fs32, uint32(fm>>d), fe-1, uint32(fm&(1< gs: // f < 0, g > 0 - return -1, false - - case fs < gs: // f > 0, g < 0 - return +1, false - - // Same sign, not NaN. - // Can compare encodings directly now. - // Reverse for sign. - case fs == 0 && f < g, fs != 0 && f > g: - return -1, false - - case fs == 0 && f > g, fs != 0 && f < g: - return +1, false - } - - // f == g - return 0, false -} - -func f64toint(f uint64) (val int64, ok bool) { - fs, fm, fe, fi, fn := funpack64(f) - - switch { - case fi, fn: // NaN - return 0, false - - case fe < -1: // f < 0.5 - return 0, false - - case fe > 63: // f >= 2^63 - if fs != 0 && fm == 0 { // f == -2^63 - return -1 << 63, true - } - if fs != 0 { - return 0, false - } - return 0, false - } - - for fe > int(mantbits64) { - fe-- - fm <<= 1 - } - for fe < int(mantbits64) { - fe++ - fm >>= 1 - } - val = int64(fm) - if fs != 0 { - val = -val - } - return val, true -} - -func fintto64(val int64) (f uint64) { - fs := uint64(val) & (1 << 63) - mant := uint64(val) - if fs != 0 { - mant = -mant - } - return fpack64(fs, mant, int(mantbits64), 0) -} - -// 64x64 -> 128 multiply. -// adapted from hacker's delight. -func mullu(u, v uint64) (lo, hi uint64) { - const ( - s = 32 - mask = 1<> s - v0 := v & mask - v1 := v >> s - w0 := u0 * v0 - t := u1*v0 + w0>>s - w1 := t & mask - w2 := t >> s - w1 += u0 * v1 - return u * v, u1*v1 + w2 + w1>>s -} - -// 128/64 -> 64 quotient, 64 remainder. -// adapted from hacker's delight -func divlu(u1, u0, v uint64) (q, r uint64) { - const b = 1 << 32 - - if u1 >= v { - return 1<<64 - 1, 1<<64 - 1 - } - - // s = nlz(v); v <<= s - s := uint(0) - for v&(1<<63) == 0 { - s++ - v <<= 1 - } - - vn1 := v >> 32 - vn0 := v & (1<<32 - 1) - un32 := u1<>(64-s) - un10 := u0 << s - un1 := un10 >> 32 - un0 := un10 & (1<<32 - 1) - q1 := un32 / vn1 - rhat := un32 - q1*vn1 - -again1: - if q1 >= b || q1*vn0 > b*rhat+un1 { - q1-- - rhat += vn1 - if rhat < b { - goto again1 - } - } - - un21 := un32*b + un1 - q1*v - q0 := un21 / vn1 - rhat = un21 - q0*vn1 - -again2: - if q0 >= b || q0*vn0 > b*rhat+un0 { - q0-- - rhat += vn1 - if rhat < b { - goto again2 - } - } - - return q1*b + q0, (un21*b + un0 - q0*v) >> s -} - -// callable from C - -func fadd64c(f, g uint64, ret *uint64) { *ret = fadd64(f, g) } -func fsub64c(f, g uint64, ret *uint64) { *ret = fsub64(f, g) } -func fmul64c(f, g uint64, ret *uint64) { *ret = fmul64(f, g) } -func fdiv64c(f, g uint64, ret *uint64) { *ret = fdiv64(f, g) } -func fneg64c(f uint64, ret *uint64) { *ret = fneg64(f) } -func f32to64c(f uint32, ret *uint64) { *ret = f32to64(f) } -func f64to32c(f uint64, ret *uint32) { *ret = f64to32(f) } -func fcmp64c(f, g uint64, ret *int, retnan *bool) { *ret, *retnan = fcmp64(f, g) } -func fintto64c(val int64, ret *uint64) { *ret = fintto64(val) } -func f64tointc(f uint64, ret *int64, retok *bool) { *ret, *retok = f64toint(f) } diff --git a/libgo/go/runtime/softfloat64_test.go b/libgo/go/runtime/softfloat64_test.go deleted file mode 100644 index df63010fbd5..00000000000 --- a/libgo/go/runtime/softfloat64_test.go +++ /dev/null @@ -1,198 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime_test - -import ( - "math" - "math/rand" - . "runtime" - "testing" -) - -// turn uint64 op into float64 op -func fop(f func(x, y uint64) uint64) func(x, y float64) float64 { - return func(x, y float64) float64 { - bx := math.Float64bits(x) - by := math.Float64bits(y) - return math.Float64frombits(f(bx, by)) - } -} - -func add(x, y float64) float64 { return x + y } -func sub(x, y float64) float64 { return x - y } -func mul(x, y float64) float64 { return x * y } -func div(x, y float64) float64 { return x / y } - -func TestFloat64(t *testing.T) { - base := []float64{ - 0, - math.Copysign(0, -1), - -1, - 1, - math.NaN(), - math.Inf(+1), - math.Inf(-1), - 0.1, - 1.5, - 1.9999999999999998, // all 1s mantissa - 1.3333333333333333, // 1.010101010101... - 1.1428571428571428, // 1.001001001001... - 1.112536929253601e-308, // first normal - 2, - 4, - 8, - 16, - 32, - 64, - 128, - 256, - 3, - 12, - 1234, - 123456, - -0.1, - -1.5, - -1.9999999999999998, - -1.3333333333333333, - -1.1428571428571428, - -2, - -3, - 1e-200, - 1e-300, - 1e-310, - 5e-324, - 1e-105, - 1e-305, - 1e+200, - 1e+306, - 1e+307, - 1e+308, - } - all := make([]float64, 200) - copy(all, base) - for i := len(base); i < len(all); i++ { - all[i] = rand.NormFloat64() - } - - test(t, "+", add, fop(Fadd64), all) - test(t, "-", sub, fop(Fsub64), all) - if GOARCH != "386" { // 386 is not precise! - test(t, "*", mul, fop(Fmul64), all) - test(t, "/", div, fop(Fdiv64), all) - } -} - -// 64 -hw-> 32 -hw-> 64 -func trunc32(f float64) float64 { - return float64(float32(f)) -} - -// 64 -sw->32 -hw-> 64 -func to32sw(f float64) float64 { - return float64(math.Float32frombits(F64to32(math.Float64bits(f)))) -} - -// 64 -hw->32 -sw-> 64 -func to64sw(f float64) float64 { - return math.Float64frombits(F32to64(math.Float32bits(float32(f)))) -} - -// float64 -hw-> int64 -hw-> float64 -func hwint64(f float64) float64 { - return float64(int64(f)) -} - -// float64 -hw-> int32 -hw-> float64 -func hwint32(f float64) float64 { - return float64(int32(f)) -} - -// float64 -sw-> int64 -hw-> float64 -func toint64sw(f float64) float64 { - i, ok := F64toint(math.Float64bits(f)) - if !ok { - // There's no right answer for out of range. - // Match the hardware to pass the test. - i = int64(f) - } - return float64(i) -} - -// float64 -hw-> int64 -sw-> float64 -func fromint64sw(f float64) float64 { - return math.Float64frombits(Fintto64(int64(f))) -} - -var nerr int - -func err(t *testing.T, format string, args ...interface{}) { - t.Errorf(format, args...) - - // cut errors off after a while. - // otherwise we spend all our time - // allocating memory to hold the - // formatted output. - if nerr++; nerr >= 10 { - t.Fatal("too many errors") - } -} - -func test(t *testing.T, op string, hw, sw func(float64, float64) float64, all []float64) { - for _, f := range all { - for _, g := range all { - h := hw(f, g) - s := sw(f, g) - if !same(h, s) { - err(t, "%g %s %g = sw %g, hw %g\n", f, op, g, s, h) - } - testu(t, "to32", trunc32, to32sw, h) - testu(t, "to64", trunc32, to64sw, h) - testu(t, "toint64", hwint64, toint64sw, h) - testu(t, "fromint64", hwint64, fromint64sw, h) - testcmp(t, f, h) - testcmp(t, h, f) - testcmp(t, g, h) - testcmp(t, h, g) - } - } -} - -func testu(t *testing.T, op string, hw, sw func(float64) float64, v float64) { - h := hw(v) - s := sw(v) - if !same(h, s) { - err(t, "%s %g = sw %g, hw %g\n", op, v, s, h) - } -} - -func hwcmp(f, g float64) (cmp int, isnan bool) { - switch { - case f < g: - return -1, false - case f > g: - return +1, false - case f == g: - return 0, false - } - return 0, true // must be NaN -} - -func testcmp(t *testing.T, f, g float64) { - hcmp, hisnan := hwcmp(f, g) - scmp, sisnan := Fcmp64(math.Float64bits(f), math.Float64bits(g)) - if hcmp != scmp || hisnan != sisnan { - err(t, "cmp(%g, %g) = sw %v, %v, hw %v, %v\n", f, g, scmp, sisnan, hcmp, hisnan) - } -} - -func same(f, g float64) bool { - if math.IsNaN(f) && math.IsNaN(g) { - return true - } - if math.Copysign(1, f) != math.Copysign(1, g) { - return false - } - return f == g -} diff --git a/libgo/go/runtime/stack.go b/libgo/go/runtime/stack.go deleted file mode 100644 index f1b7d32d205..00000000000 --- a/libgo/go/runtime/stack.go +++ /dev/null @@ -1,13 +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 runtime - -const ( - // Goroutine preemption request. - // Stored into g->stackguard0 to cause split stack check failure. - // Must be greater than any real sp. - // 0xfffffade in hex. - stackPreempt = ^uintptr(1313) -) diff --git a/libgo/go/runtime/string.go b/libgo/go/runtime/string.go deleted file mode 100644 index 0809f89bc1f..00000000000 --- a/libgo/go/runtime/string.go +++ /dev/null @@ -1,298 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -import ( - "unsafe" -) - -func concatstrings(a []string) string { - idx := 0 - l := 0 - count := 0 - for i, x := range a { - n := len(x) - if n == 0 { - continue - } - if l+n < l { - gothrow("string concatenation too long") - } - l += n - count++ - idx = i - } - if count == 0 { - return "" - } - if count == 1 { - return a[idx] - } - s, b := rawstring(l) - l = 0 - for _, x := range a { - copy(b[l:], x) - l += len(x) - } - return s -} - -//go:nosplit -func concatstring2(a [2]string) string { - return concatstrings(a[:]) -} - -//go:nosplit -func concatstring3(a [3]string) string { - return concatstrings(a[:]) -} - -//go:nosplit -func concatstring4(a [4]string) string { - return concatstrings(a[:]) -} - -//go:nosplit -func concatstring5(a [5]string) string { - return concatstrings(a[:]) -} - -func slicebytetostring(b []byte) string { - if raceenabled && len(b) > 0 { - racereadrangepc(unsafe.Pointer(&b[0]), - uintptr(len(b)), - getcallerpc(unsafe.Pointer(&b)), - funcPC(slicebytetostring)) - } - s, c := rawstring(len(b)) - copy(c, b) - return s -} - -func slicebytetostringtmp(b []byte) string { - // Return a "string" referring to the actual []byte bytes. - // This is only for use by internal compiler optimizations - // that know that the string form will be discarded before - // the calling goroutine could possibly modify the original - // slice or synchronize with another goroutine. - // Today, the only such case is a m[string(k)] lookup where - // m is a string-keyed map and k is a []byte. - - if raceenabled && len(b) > 0 { - racereadrangepc(unsafe.Pointer(&b[0]), - uintptr(len(b)), - getcallerpc(unsafe.Pointer(&b)), - funcPC(slicebytetostringtmp)) - } - return *(*string)(unsafe.Pointer(&b)) -} - -func stringtoslicebyte(s string) []byte { - b := rawbyteslice(len(s)) - copy(b, s) - return b -} - -func stringtoslicerune(s string) []rune { - // two passes. - // unlike slicerunetostring, no race because strings are immutable. - n := 0 - t := s - for len(s) > 0 { - _, k := charntorune(s) - s = s[k:] - n++ - } - a := rawruneslice(n) - n = 0 - for len(t) > 0 { - r, k := charntorune(t) - t = t[k:] - a[n] = r - n++ - } - return a -} - -func slicerunetostring(a []rune) string { - if raceenabled && len(a) > 0 { - racereadrangepc(unsafe.Pointer(&a[0]), - uintptr(len(a))*unsafe.Sizeof(a[0]), - getcallerpc(unsafe.Pointer(&a)), - funcPC(slicerunetostring)) - } - var dum [4]byte - size1 := 0 - for _, r := range a { - size1 += runetochar(dum[:], r) - } - s, b := rawstring(size1 + 3) - size2 := 0 - for _, r := range a { - // check for race - if size2 >= size1 { - break - } - size2 += runetochar(b[size2:], r) - } - return s[:size2] -} - -type stringStruct struct { - str unsafe.Pointer - len int -} - -func intstring(v int64) string { - s, b := rawstring(4) - n := runetochar(b, rune(v)) - return s[:n] -} - -// stringiter returns the index of the next -// rune after the rune that starts at s[k]. -func stringiter(s string, k int) int { - if k >= len(s) { - // 0 is end of iteration - return 0 - } - - c := s[k] - if c < runeself { - return k + 1 - } - - // multi-char rune - _, n := charntorune(s[k:]) - return k + n -} - -// stringiter2 returns the rune that starts at s[k] -// and the index where the next rune starts. -func stringiter2(s string, k int) (int, rune) { - if k >= len(s) { - // 0 is end of iteration - return 0, 0 - } - - c := s[k] - if c < runeself { - return k + 1, rune(c) - } - - // multi-char rune - r, n := charntorune(s[k:]) - return k + n, r -} - -// rawstring allocates storage for a new string. The returned -// string and byte slice both refer to the same storage. -// The storage is not zeroed. Callers should use -// b to set the string contents and then drop b. -func rawstring(size int) (s string, b []byte) { - p := mallocgc(uintptr(size), nil, flagNoScan|flagNoZero) - - (*stringStruct)(unsafe.Pointer(&s)).str = p - (*stringStruct)(unsafe.Pointer(&s)).len = size - - (*slice)(unsafe.Pointer(&b)).array = (*uint8)(p) - (*slice)(unsafe.Pointer(&b)).len = uint(size) - (*slice)(unsafe.Pointer(&b)).cap = uint(size) - - for { - ms := maxstring - if uintptr(size) <= uintptr(ms) || casuintptr((*uintptr)(unsafe.Pointer(&maxstring)), uintptr(ms), uintptr(size)) { - return - } - } -} - -// rawbyteslice allocates a new byte slice. The byte slice is not zeroed. -func rawbyteslice(size int) (b []byte) { - cap := goroundupsize(uintptr(size)) - p := mallocgc(cap, nil, flagNoScan|flagNoZero) - if cap != uintptr(size) { - memclr(add(p, uintptr(size)), cap-uintptr(size)) - } - - (*slice)(unsafe.Pointer(&b)).array = (*uint8)(p) - (*slice)(unsafe.Pointer(&b)).len = uint(size) - (*slice)(unsafe.Pointer(&b)).cap = uint(cap) - return -} - -// rawruneslice allocates a new rune slice. The rune slice is not zeroed. -func rawruneslice(size int) (b []rune) { - if uintptr(size) > maxmem/4 { - gothrow("out of memory") - } - mem := goroundupsize(uintptr(size) * 4) - p := mallocgc(mem, nil, flagNoScan|flagNoZero) - if mem != uintptr(size)*4 { - memclr(add(p, uintptr(size)*4), mem-uintptr(size)*4) - } - - (*slice)(unsafe.Pointer(&b)).array = (*uint8)(p) - (*slice)(unsafe.Pointer(&b)).len = uint(size) - (*slice)(unsafe.Pointer(&b)).cap = uint(mem / 4) - return -} - -// used by cmd/cgo -func gobytes(p *byte, n int) []byte { - if n == 0 { - return make([]byte, 0) - } - x := make([]byte, n) - memmove(unsafe.Pointer(&x[0]), unsafe.Pointer(p), uintptr(n)) - return x -} - -func gostringsize(n int) string { - s, _ := rawstring(n) - return s -} - -//go:noescape -func findnull(*byte) int - -func gostring(p *byte) string { - l := findnull(p) - if l == 0 { - return "" - } - s, b := rawstring(l) - memmove(unsafe.Pointer(&b[0]), unsafe.Pointer(p), uintptr(l)) - return s -} - -func gostringn(p *byte, l int) string { - if l == 0 { - return "" - } - s, b := rawstring(l) - memmove(unsafe.Pointer(&b[0]), unsafe.Pointer(p), uintptr(l)) - return s -} - -func index(s, t string) int { - if len(t) == 0 { - return 0 - } - for i := 0; i < len(s); i++ { - if s[i] == t[0] && hasprefix(s[i:], t) { - return i - } - } - return -1 -} - -func contains(s, t string) bool { - return index(s, t) >= 0 -} - -func hasprefix(s, t string) bool { - return len(s) >= len(t) && s[:len(t)] == t -} diff --git a/libgo/go/runtime/string_test.go b/libgo/go/runtime/string_test.go index df3ff06a7dd..71bd8307dfd 100644 --- a/libgo/go/runtime/string_test.go +++ b/libgo/go/runtime/string_test.go @@ -5,6 +5,7 @@ package runtime_test import ( + "strings" "testing" ) @@ -75,3 +76,165 @@ func BenchmarkCompareStringBig(b *testing.B) { } b.SetBytes(int64(len(s1))) } + +func BenchmarkRuneIterate(b *testing.B) { + bytes := make([]byte, 100) + for i := range bytes { + bytes[i] = byte('A') + } + s := string(bytes) + for i := 0; i < b.N; i++ { + for range s { + } + } +} + +func BenchmarkRuneIterate2(b *testing.B) { + bytes := make([]byte, 100) + for i := range bytes { + bytes[i] = byte('A') + } + s := string(bytes) + for i := 0; i < b.N; i++ { + for range s { + } + } +} + +/* +func TestStringW(t *testing.T) { + strings := []string{ + "hello", + "a\u5566\u7788b", + } + + for _, s := range strings { + var b []uint16 + for _, c := range s { + b = append(b, uint16(c)) + if c != rune(uint16(c)) { + t.Errorf("bad test: stringW can't handle >16 bit runes") + } + } + b = append(b, 0) + r := runtime.GostringW(b) + if r != s { + t.Errorf("gostringW(%v) = %s, want %s", b, r, s) + } + } +} +*/ + +func TestLargeStringConcat(t *testing.T) { + output := executeTest(t, largeStringConcatSource, nil) + want := "panic: " + strings.Repeat("0", 1<<10) + strings.Repeat("1", 1<<10) + + strings.Repeat("2", 1<<10) + strings.Repeat("3", 1<<10) + if !strings.HasPrefix(output, want) { + t.Fatalf("output does not start with %q:\n%s", want, output) + } +} + +var largeStringConcatSource = ` +package main +import "strings" +func main() { + s0 := strings.Repeat("0", 1<<10) + s1 := strings.Repeat("1", 1<<10) + s2 := strings.Repeat("2", 1<<10) + s3 := strings.Repeat("3", 1<<10) + s := s0 + s1 + s2 + s3 + panic(s) +} +` + +/* +func TestGostringnocopy(t *testing.T) { + max := *runtime.Maxstring + b := make([]byte, max+10) + for i := uintptr(0); i < max+9; i++ { + b[i] = 'a' + } + _ = runtime.Gostringnocopy(&b[0]) + newmax := *runtime.Maxstring + if newmax != max+9 { + t.Errorf("want %d, got %d", max+9, newmax) + } +} +*/ + +func TestCompareTempString(t *testing.T) { + s := "foo" + b := []byte(s) + n := testing.AllocsPerRun(1000, func() { + if string(b) != s { + t.Fatalf("strings are not equal: '%v' and '%v'", string(b), s) + } + if string(b) == s { + } else { + t.Fatalf("strings are not equal: '%v' and '%v'", string(b), s) + } + }) + if n != 0 { + t.Fatalf("want 0 allocs, got %v", n) + } +} + +func TestStringOnStack(t *testing.T) { + s := "" + for i := 0; i < 3; i++ { + s = "a" + s + "b" + s + "c" + } + + if want := "aaabcbabccbaabcbabccc"; s != want { + t.Fatalf("want: '%v', got '%v'", want, s) + } +} + +func TestIntString(t *testing.T) { + // Non-escaping result of intstring. + s := "" + for i := 0; i < 4; i++ { + s += string(i+'0') + string(i+'0'+1) + } + if want := "01122334"; s != want { + t.Fatalf("want '%v', got '%v'", want, s) + } + + // Escaping result of intstring. + var a [4]string + for i := 0; i < 4; i++ { + a[i] = string(i + '0') + } + s = a[0] + a[1] + a[2] + a[3] + if want := "0123"; s != want { + t.Fatalf("want '%v', got '%v'", want, s) + } +} + +func TestIntStringAllocs(t *testing.T) { + unknown := '0' + n := testing.AllocsPerRun(1000, func() { + s1 := string(unknown) + s2 := string(unknown + 1) + if s1 == s2 { + t.Fatalf("bad") + } + }) + if n != 0 { + t.Fatalf("want 0 allocs, got %v", n) + } +} + +func TestRangeStringCast(t *testing.T) { + s := "abc" + n := testing.AllocsPerRun(1000, func() { + for i, c := range []byte(s) { + if c != s[i] { + t.Fatalf("want '%c' at pos %v, got '%c'", s[i], i, c) + } + } + }) + if n != 0 { + t.Fatalf("want 0 allocs, got %v", n) + } +} diff --git a/libgo/go/runtime/stubs.go b/libgo/go/runtime/stubs.go deleted file mode 100644 index fe8f9c9222a..00000000000 --- a/libgo/go/runtime/stubs.go +++ /dev/null @@ -1,316 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -import "unsafe" - -// Declarations for runtime services implemented in C or assembly. - -const ptrSize = 4 << (^uintptr(0) >> 63) // unsafe.Sizeof(uintptr(0)) but an ideal const -const regSize = 4 << (^uintreg(0) >> 63) // unsafe.Sizeof(uintreg(0)) but an ideal const - -// Should be a built-in for unsafe.Pointer? -//go:nosplit -func add(p unsafe.Pointer, x uintptr) unsafe.Pointer { - return unsafe.Pointer(uintptr(p) + x) -} - -// n must be a power of 2 -func roundup(p unsafe.Pointer, n uintptr) unsafe.Pointer { - delta := -uintptr(p) & (n - 1) - return unsafe.Pointer(uintptr(p) + delta) -} - -// in runtime.c -func getg() *g -func acquirem() *m -func releasem(mp *m) -func gomcache() *mcache -func readgstatus(*g) uint32 // proc.c - -// mcall switches from the g to the g0 stack and invokes fn(g), -// where g is the goroutine that made the call. -// mcall saves g's current PC/SP in g->sched so that it can be restored later. -// It is up to fn to arrange for that later execution, typically by recording -// g in a data structure, causing something to call ready(g) later. -// mcall returns to the original goroutine g later, when g has been rescheduled. -// fn must not return at all; typically it ends by calling schedule, to let the m -// run other goroutines. -// -// mcall can only be called from g stacks (not g0, not gsignal). -//go:noescape -func mcall(fn func(*g)) - -// onM switches from the g to the g0 stack and invokes fn(). -// When fn returns, onM switches back to the g and returns, -// continuing execution on the g stack. -// If arguments must be passed to fn, they can be written to -// g->m->ptrarg (pointers) and g->m->scalararg (non-pointers) -// before the call and then consulted during fn. -// Similarly, fn can pass return values back in those locations. -// If fn is written in Go, it can be a closure, which avoids the need for -// ptrarg and scalararg entirely. -// After reading values out of ptrarg and scalararg it is conventional -// to zero them to avoid (memory or information) leaks. -// -// If onM is called from a g0 stack, it invokes fn and returns, -// without any stack switches. -// -// If onM is called from a gsignal stack, it crashes the program. -// The implication is that functions used in signal handlers must -// not use onM. -// -// NOTE(rsc): We could introduce a separate onMsignal that is -// like onM but if called from a gsignal stack would just run fn on -// that stack. The caller of onMsignal would be required to save the -// old values of ptrarg/scalararg and restore them when the call -// was finished, in case the signal interrupted an onM sequence -// in progress on the g or g0 stacks. Until there is a clear need for this, -// we just reject onM in signal handling contexts entirely. -// -//go:noescape -func onM(fn func()) - -// onMsignal is like onM but is allowed to be used in code that -// might run on the gsignal stack. Code running on a signal stack -// may be interrupting an onM sequence on the main stack, so -// if the onMsignal calling sequence writes to ptrarg/scalararg, -// it must first save the old values and then restore them when -// finished. As an exception to the rule, it is fine not to save and -// restore the values if the program is trying to crash rather than -// return from the signal handler. -// Once all the runtime is written in Go, there will be no ptrarg/scalararg -// and the distinction between onM and onMsignal (and perhaps mcall) -// can go away. -// -// If onMsignal is called from a gsignal stack, it invokes fn directly, -// without a stack switch. Otherwise onMsignal behaves like onM. -// -//go:noescape -func onM_signalok(fn func()) - -func badonm() { - gothrow("onM called from signal goroutine") -} - -// C functions that run on the M stack. -// Call using mcall. -func gosched_m(*g) -func park_m(*g) -func recovery_m(*g) - -// More C functions that run on the M stack. -// Call using onM. -func mcacheRefill_m() -func largeAlloc_m() -func gc_m() -func scavenge_m() -func setFinalizer_m() -func removeFinalizer_m() -func markallocated_m() -func unrollgcprog_m() -func unrollgcproginplace_m() -func setgcpercent_m() -func setmaxthreads_m() -func ready_m() -func deferproc_m() -func goexit_m() -func startpanic_m() -func dopanic_m() -func readmemstats_m() -func writeheapdump_m() - -// memclr clears n bytes starting at ptr. -// in memclr_*.s -//go:noescape -func memclr(ptr unsafe.Pointer, n uintptr) - -// memmove copies n bytes from "from" to "to". -// in memmove_*.s -//go:noescape -func memmove(to unsafe.Pointer, from unsafe.Pointer, n uintptr) - -func starttheworld() -func stoptheworld() -func newextram() -func lockOSThread() -func unlockOSThread() - -// exported value for testing -var hashLoad = loadFactor - -// in asm_*.s -func fastrand1() uint32 - -// in asm_*.s -//go:noescape -func memeq(a, b unsafe.Pointer, size uintptr) bool - -// noescape hides a pointer from escape analysis. noescape is -// the identity function but escape analysis doesn't think the -// output depends on the input. noescape is inlined and currently -// compiles down to a single xor instruction. -// USE CAREFULLY! -//go:nosplit -func noescape(p unsafe.Pointer) unsafe.Pointer { - x := uintptr(p) - return unsafe.Pointer(x ^ 0) -} - -func entersyscall() -func reentersyscall(pc uintptr, sp unsafe.Pointer) -func entersyscallblock() -func exitsyscall() - -func cgocallback(fn, frame unsafe.Pointer, framesize uintptr) -func gogo(buf *gobuf) -func gosave(buf *gobuf) -func read(fd int32, p unsafe.Pointer, n int32) int32 -func close(fd int32) int32 -func mincore(addr unsafe.Pointer, n uintptr, dst *byte) int32 - -//go:noescape -func jmpdefer(fv *funcval, argp uintptr) -func exit1(code int32) -func asminit() -func setg(gg *g) -func exit(code int32) -func breakpoint() -func nanotime() int64 -func usleep(usec uint32) - -// careful: cputicks is not guaranteed to be monotonic! In particular, we have -// noticed drift between cpus on certain os/arch combinations. See issue 8976. -func cputicks() int64 - -func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) unsafe.Pointer -func munmap(addr unsafe.Pointer, n uintptr) -func madvise(addr unsafe.Pointer, n uintptr, flags int32) -func reflectcall(fn, arg unsafe.Pointer, n uint32, retoffset uint32) -func osyield() -func procyield(cycles uint32) -func cgocallback_gofunc(fv *funcval, frame unsafe.Pointer, framesize uintptr) -func readgogc() int32 -func purgecachedstats(c *mcache) -func gostringnocopy(b *byte) string -func goexit() - -//go:noescape -func write(fd uintptr, p unsafe.Pointer, n int32) int32 - -//go:noescape -func cas(ptr *uint32, old, new uint32) bool - -//go:noescape -func casp(ptr *unsafe.Pointer, old, new unsafe.Pointer) bool - -//go:noescape -func casuintptr(ptr *uintptr, old, new uintptr) bool - -//go:noescape -func atomicstoreuintptr(ptr *uintptr, new uintptr) - -//go:noescape -func atomicloaduintptr(ptr *uintptr) uintptr - -//go:noescape -func atomicloaduint(ptr *uint) uint - -//go:noescape -func setcallerpc(argp unsafe.Pointer, pc uintptr) - -// getcallerpc returns the program counter (PC) of its caller's caller. -// getcallersp returns the stack pointer (SP) of its caller's caller. -// For both, the argp must be a pointer to the caller's first function argument. -// The implementation may or may not use argp, depending on -// the architecture. -// -// For example: -// -// func f(arg1, arg2, arg3 int) { -// pc := getcallerpc(unsafe.Pointer(&arg1)) -// sp := getcallerpc(unsafe.Pointer(&arg2)) -// } -// -// These two lines find the PC and SP immediately following -// the call to f (where f will return). -// -// The call to getcallerpc and getcallersp must be done in the -// frame being asked about. It would not be correct for f to pass &arg1 -// to another function g and let g call getcallerpc/getcallersp. -// The call inside g might return information about g's caller or -// information about f's caller or complete garbage. -// -// The result of getcallersp is correct at the time of the return, -// but it may be invalidated by any subsequent call to a function -// that might relocate the stack in order to grow or shrink it. -// A general rule is that the result of getcallersp should be used -// immediately and can only be passed to nosplit functions. - -//go:noescape -func getcallerpc(argp unsafe.Pointer) uintptr - -//go:noescape -func getcallersp(argp unsafe.Pointer) uintptr - -//go:noescape -func asmcgocall(fn, arg unsafe.Pointer) - -//go:noescape -func asmcgocall_errno(fn, arg unsafe.Pointer) int32 - -//go:noescape -func open(name *byte, mode, perm int32) int32 - -//go:noescape -func gotraceback(*bool) int32 - -const _NoArgs = ^uintptr(0) - -func newstack() -func newproc() -func morestack() -func mstart() -func rt0_go() - -// return0 is a stub used to return 0 from deferproc. -// It is called at the very end of deferproc to signal -// the calling Go function that it should not jump -// to deferreturn. -// in asm_*.s -func return0() - -// thunk to call time.now. -func timenow() (sec int64, nsec int32) - -// in asm_*.s -// not called directly; definitions here supply type information for traceback. -func call16(fn, arg unsafe.Pointer, n, retoffset uint32) -func call32(fn, arg unsafe.Pointer, n, retoffset uint32) -func call64(fn, arg unsafe.Pointer, n, retoffset uint32) -func call128(fn, arg unsafe.Pointer, n, retoffset uint32) -func call256(fn, arg unsafe.Pointer, n, retoffset uint32) -func call512(fn, arg unsafe.Pointer, n, retoffset uint32) -func call1024(fn, arg unsafe.Pointer, n, retoffset uint32) -func call2048(fn, arg unsafe.Pointer, n, retoffset uint32) -func call4096(fn, arg unsafe.Pointer, n, retoffset uint32) -func call8192(fn, arg unsafe.Pointer, n, retoffset uint32) -func call16384(fn, arg unsafe.Pointer, n, retoffset uint32) -func call32768(fn, arg unsafe.Pointer, n, retoffset uint32) -func call65536(fn, arg unsafe.Pointer, n, retoffset uint32) -func call131072(fn, arg unsafe.Pointer, n, retoffset uint32) -func call262144(fn, arg unsafe.Pointer, n, retoffset uint32) -func call524288(fn, arg unsafe.Pointer, n, retoffset uint32) -func call1048576(fn, arg unsafe.Pointer, n, retoffset uint32) -func call2097152(fn, arg unsafe.Pointer, n, retoffset uint32) -func call4194304(fn, arg unsafe.Pointer, n, retoffset uint32) -func call8388608(fn, arg unsafe.Pointer, n, retoffset uint32) -func call16777216(fn, arg unsafe.Pointer, n, retoffset uint32) -func call33554432(fn, arg unsafe.Pointer, n, retoffset uint32) -func call67108864(fn, arg unsafe.Pointer, n, retoffset uint32) -func call134217728(fn, arg unsafe.Pointer, n, retoffset uint32) -func call268435456(fn, arg unsafe.Pointer, n, retoffset uint32) -func call536870912(fn, arg unsafe.Pointer, n, retoffset uint32) -func call1073741824(fn, arg unsafe.Pointer, n, retoffset uint32) diff --git a/libgo/go/runtime/symtab_test.go b/libgo/go/runtime/symtab_test.go index 0db63c347fd..8c8281f78a1 100644 --- a/libgo/go/runtime/symtab_test.go +++ b/libgo/go/runtime/symtab_test.go @@ -12,9 +12,8 @@ import ( var _ = runtime.Caller var _ = strings.HasSuffix -type _ testing.T -/* runtime.Caller is not fully implemented for gccgo. +type _ testing.T func TestCaller(t *testing.T) { procs := runtime.GOMAXPROCS(-1) @@ -42,8 +41,9 @@ func testCallerBar(t *testing.T) { f := runtime.FuncForPC(pc) if !ok || !strings.HasSuffix(file, "symtab_test.go") || - (i == 0 && !strings.HasSuffix(f.Name(), "testCallerBar")) || - (i == 1 && !strings.HasSuffix(f.Name(), "testCallerFoo")) || + // FuncForPC doesn't work gccgo, because of inlining. + // (i == 0 && !strings.HasSuffix(f.Name(), "testCallerBar")) || + // (i == 1 && !strings.HasSuffix(f.Name(), "testCallerFoo")) || line < 5 || line > 1000 || f.Entry() >= pc { t.Errorf("incorrect symbol info %d: %t %d %d %s %s %d", @@ -52,4 +52,107 @@ func testCallerBar(t *testing.T) { } } -*/ +func lineNumber() int { + _, _, line, _ := runtime.Caller(1) + return line // return 0 for error +} + +// Do not add/remove lines in this block without updating the line numbers. +var firstLine = lineNumber() // 0 +var ( // 1 + lineVar1 = lineNumber() // 2 + lineVar2a, lineVar2b = lineNumber(), lineNumber() // 3 +) // 4 +var compLit = []struct { // 5 + lineA, lineB int // 6 +}{ // 7 + { // 8 + lineNumber(), lineNumber(), // 9 + }, // 10 + { // 11 + lineNumber(), // 12 + lineNumber(), // 13 + }, // 14 + { // 15 + lineB: lineNumber(), // 16 + lineA: lineNumber(), // 17 + }, // 18 +} // 19 +var arrayLit = [...]int{lineNumber(), // 20 + lineNumber(), lineNumber(), // 21 + lineNumber(), // 22 +} // 23 +var sliceLit = []int{lineNumber(), // 24 + lineNumber(), lineNumber(), // 25 + lineNumber(), // 26 +} // 27 +var mapLit = map[int]int{ // 28 + 29: lineNumber(), // 29 + 30: lineNumber(), // 30 + lineNumber(): 31, // 31 + lineNumber(): 32, // 32 +} // 33 +var intLit = lineNumber() + // 34 + lineNumber() + // 35 + lineNumber() // 36 +func trythis() { // 37 + recordLines(lineNumber(), // 38 + lineNumber(), // 39 + lineNumber()) // 40 +} + +// Modifications below this line are okay. + +var l38, l39, l40 int + +func recordLines(a, b, c int) { + l38 = a + l39 = b + l40 = c +} + +func TestLineNumber(t *testing.T) { + trythis() + for _, test := range []struct { + name string + val int + want int + }{ + {"firstLine", firstLine, 0}, + {"lineVar1", lineVar1, 2}, + {"lineVar2a", lineVar2a, 3}, + {"lineVar2b", lineVar2b, 3}, + {"compLit[0].lineA", compLit[0].lineA, 9}, + {"compLit[0].lineB", compLit[0].lineB, 9}, + {"compLit[1].lineA", compLit[1].lineA, 12}, + {"compLit[1].lineB", compLit[1].lineB, 13}, + {"compLit[2].lineA", compLit[2].lineA, 17}, + {"compLit[2].lineB", compLit[2].lineB, 16}, + + {"arrayLit[0]", arrayLit[0], 20}, + {"arrayLit[1]", arrayLit[1], 21}, + {"arrayLit[2]", arrayLit[2], 21}, + {"arrayLit[3]", arrayLit[3], 22}, + + {"sliceLit[0]", sliceLit[0], 24}, + {"sliceLit[1]", sliceLit[1], 25}, + {"sliceLit[2]", sliceLit[2], 25}, + {"sliceLit[3]", sliceLit[3], 26}, + + {"mapLit[29]", mapLit[29], 29}, + {"mapLit[30]", mapLit[30], 30}, + {"mapLit[31]", mapLit[31+firstLine] + firstLine, 31}, // nb it's the key not the value + {"mapLit[32]", mapLit[32+firstLine] + firstLine, 32}, // nb it's the key not the value + + {"intLit", intLit - 2*firstLine, 34 + 35 + 36}, + + {"l38", l38, 38}, + {"l39", l39, 39}, + {"l40", l40, 40}, + } { + if got := test.val - firstLine; got != test.want { + t.Errorf("%s on firstLine+%d want firstLine+%d (firstLine=%d, val=%d)", + test.name, got, test.want, firstLine, test.val) + } + } +} diff --git a/libgo/go/runtime/syscall_windows.go b/libgo/go/runtime/syscall_windows.go deleted file mode 100644 index 51004b78a02..00000000000 --- a/libgo/go/runtime/syscall_windows.go +++ /dev/null @@ -1,174 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -import ( - "unsafe" -) - -const _SIGPROF = 0 // dummy value for badsignal - -type callbacks struct { - lock mutex - ctxt [cb_max]*wincallbackcontext - n int -} - -func (c *wincallbackcontext) isCleanstack() bool { - return c.cleanstack -} - -func (c *wincallbackcontext) setCleanstack(cleanstack bool) { - c.cleanstack = cleanstack -} - -var ( - cbs callbacks - cbctxts **wincallbackcontext = &cbs.ctxt[0] // to simplify access to cbs.ctxt in sys_windows_*.s - - callbackasm byte // type isn't really byte, it's code in runtime -) - -// callbackasmAddr returns address of runtime.callbackasm -// function adjusted by i. -// runtime.callbackasm is just a series of CALL instructions -// (each is 5 bytes long), and we want callback to arrive at -// correspondent call instruction instead of start of -// runtime.callbackasm. -func callbackasmAddr(i int) uintptr { - return uintptr(add(unsafe.Pointer(&callbackasm), uintptr(i*5))) -} - -func compileCallback(fn eface, cleanstack bool) (code uintptr) { - if fn._type == nil || (fn._type.kind&kindMask) != kindFunc { - panic("compilecallback: not a function") - } - ft := (*functype)(unsafe.Pointer(fn._type)) - if len(ft.out) != 1 { - panic("compilecallback: function must have one output parameter") - } - uintptrSize := unsafe.Sizeof(uintptr(0)) - if t := (**_type)(unsafe.Pointer(&ft.out[0])); (*t).size != uintptrSize { - panic("compilecallback: output parameter size is wrong") - } - argsize := uintptr(0) - if len(ft.in) > 0 { - for _, t := range (*[1024](*_type))(unsafe.Pointer(&ft.in[0]))[:len(ft.in)] { - if (*t).size > uintptrSize { - panic("compilecallback: input parameter size is wrong") - } - argsize += uintptrSize - } - } - - lock(&cbs.lock) - defer unlock(&cbs.lock) - - n := cbs.n - for i := 0; i < n; i++ { - if cbs.ctxt[i].gobody == fn.data && cbs.ctxt[i].isCleanstack() == cleanstack { - return callbackasmAddr(i) - } - } - if n >= cb_max { - gothrow("too many callback functions") - } - - c := new(wincallbackcontext) - c.gobody = fn.data - c.argsize = argsize - c.setCleanstack(cleanstack) - if cleanstack && argsize != 0 { - c.restorestack = argsize - } else { - c.restorestack = 0 - } - cbs.ctxt[n] = c - cbs.n++ - - return callbackasmAddr(n) -} - -func getLoadLibrary() uintptr - -//go:nosplit -func syscall_loadlibrary(filename *uint16) (handle, err uintptr) { - var c libcall - c.fn = getLoadLibrary() - c.n = 1 - c.args = uintptr(unsafe.Pointer(&filename)) - cgocall_errno(unsafe.Pointer(funcPC(asmstdcall)), unsafe.Pointer(&c)) - handle = c.r1 - if handle == 0 { - err = c.err - } - return -} - -func getGetProcAddress() uintptr - -//go:nosplit -func syscall_getprocaddress(handle uintptr, procname *byte) (outhandle, err uintptr) { - var c libcall - c.fn = getGetProcAddress() - c.n = 2 - c.args = uintptr(unsafe.Pointer(&handle)) - cgocall_errno(unsafe.Pointer(funcPC(asmstdcall)), unsafe.Pointer(&c)) - outhandle = c.r1 - if outhandle == 0 { - err = c.err - } - return -} - -//go:nosplit -func syscall_Syscall(fn, nargs, a1, a2, a3 uintptr) (r1, r2, err uintptr) { - var c libcall - c.fn = fn - c.n = nargs - c.args = uintptr(unsafe.Pointer(&a1)) - cgocall_errno(unsafe.Pointer(funcPC(asmstdcall)), unsafe.Pointer(&c)) - return c.r1, c.r2, c.err -} - -//go:nosplit -func syscall_Syscall6(fn, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) { - var c libcall - c.fn = fn - c.n = nargs - c.args = uintptr(unsafe.Pointer(&a1)) - cgocall_errno(unsafe.Pointer(funcPC(asmstdcall)), unsafe.Pointer(&c)) - return c.r1, c.r2, c.err -} - -//go:nosplit -func syscall_Syscall9(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, err uintptr) { - var c libcall - c.fn = fn - c.n = nargs - c.args = uintptr(unsafe.Pointer(&a1)) - cgocall_errno(unsafe.Pointer(funcPC(asmstdcall)), unsafe.Pointer(&c)) - return c.r1, c.r2, c.err -} - -//go:nosplit -func syscall_Syscall12(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 uintptr) (r1, r2, err uintptr) { - var c libcall - c.fn = fn - c.n = nargs - c.args = uintptr(unsafe.Pointer(&a1)) - cgocall_errno(unsafe.Pointer(funcPC(asmstdcall)), unsafe.Pointer(&c)) - return c.r1, c.r2, c.err -} - -//go:nosplit -func syscall_Syscall15(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 uintptr) (r1, r2, err uintptr) { - var c libcall - c.fn = fn - c.n = nargs - c.args = uintptr(unsafe.Pointer(&a1)) - cgocall_errno(unsafe.Pointer(funcPC(asmstdcall)), unsafe.Pointer(&c)) - return c.r1, c.r2, c.err -} diff --git a/libgo/go/runtime/time.go b/libgo/go/runtime/time.go deleted file mode 100644 index 11862c7e235..00000000000 --- a/libgo/go/runtime/time.go +++ /dev/null @@ -1,289 +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. - -// Time-related runtime and pieces of package time. - -package runtime - -import "unsafe" - -// Package time knows the layout of this structure. -// If this struct changes, adjust ../time/sleep.go:/runtimeTimer. -// For GOOS=nacl, package syscall knows the layout of this structure. -// If this struct changes, adjust ../syscall/net_nacl.go:/runtimeTimer. -type timer struct { - i int // heap index - - // Timer wakes up at when, and then at when+period, ... (period > 0 only) - // each time calling f(now, arg) in the timer goroutine, so f must be - // a well-behaved function and not block. - when int64 - period int64 - f func(interface{}, uintptr) - arg interface{} - seq uintptr -} - -var timers struct { - lock mutex - gp *g - created bool - sleeping bool - rescheduling bool - waitnote note - t []*timer -} - -// nacl fake time support - time in nanoseconds since 1970 -var faketime int64 - -// Package time APIs. -// Godoc uses the comments in package time, not these. - -// time.now is implemented in assembly. - -// Sleep puts the current goroutine to sleep for at least ns nanoseconds. -func timeSleep(ns int64) { - if ns <= 0 { - return - } - - t := new(timer) - t.when = nanotime() + ns - t.f = goroutineReady - t.arg = getg() - lock(&timers.lock) - addtimerLocked(t) - goparkunlock(&timers.lock, "sleep") -} - -// startTimer adds t to the timer heap. -func startTimer(t *timer) { - if raceenabled { - racerelease(unsafe.Pointer(t)) - } - addtimer(t) -} - -// stopTimer removes t from the timer heap if it is there. -// It returns true if t was removed, false if t wasn't even there. -func stopTimer(t *timer) bool { - return deltimer(t) -} - -// Go runtime. - -// Ready the goroutine arg. -func goroutineReady(arg interface{}, seq uintptr) { - goready(arg.(*g)) -} - -func addtimer(t *timer) { - lock(&timers.lock) - addtimerLocked(t) - unlock(&timers.lock) -} - -// Add a timer to the heap and start or kick the timer proc. -// If the new timer is earlier than any of the others. -// Timers are locked. -func addtimerLocked(t *timer) { - // when must never be negative; otherwise timerproc will overflow - // during its delta calculation and never expire other runtime·timers. - if t.when < 0 { - t.when = 1<<63 - 1 - } - t.i = len(timers.t) - timers.t = append(timers.t, t) - siftupTimer(t.i) - if t.i == 0 { - // siftup moved to top: new earliest deadline. - if timers.sleeping { - timers.sleeping = false - notewakeup(&timers.waitnote) - } - if timers.rescheduling { - timers.rescheduling = false - goready(timers.gp) - } - } - if !timers.created { - timers.created = true - go timerproc() - } -} - -// Delete timer t from the heap. -// Do not need to update the timerproc: if it wakes up early, no big deal. -func deltimer(t *timer) bool { - // Dereference t so that any panic happens before the lock is held. - // Discard result, because t might be moving in the heap. - _ = t.i - - lock(&timers.lock) - // t may not be registered anymore and may have - // a bogus i (typically 0, if generated by Go). - // Verify it before proceeding. - i := t.i - last := len(timers.t) - 1 - if i < 0 || i > last || timers.t[i] != t { - unlock(&timers.lock) - return false - } - if i != last { - timers.t[i] = timers.t[last] - timers.t[i].i = i - } - timers.t[last] = nil - timers.t = timers.t[:last] - if i != last { - siftupTimer(i) - siftdownTimer(i) - } - unlock(&timers.lock) - return true -} - -// Timerproc runs the time-driven events. -// It sleeps until the next event in the timers heap. -// If addtimer inserts a new earlier event, addtimer1 wakes timerproc early. -func timerproc() { - timers.gp = getg() - timers.gp.issystem = true - for { - lock(&timers.lock) - timers.sleeping = false - now := nanotime() - delta := int64(-1) - for { - if len(timers.t) == 0 { - delta = -1 - break - } - t := timers.t[0] - delta = t.when - now - if delta > 0 { - break - } - if t.period > 0 { - // leave in heap but adjust next time to fire - t.when += t.period * (1 + -delta/t.period) - siftdownTimer(0) - } else { - // remove from heap - last := len(timers.t) - 1 - if last > 0 { - timers.t[0] = timers.t[last] - timers.t[0].i = 0 - } - timers.t[last] = nil - timers.t = timers.t[:last] - if last > 0 { - siftdownTimer(0) - } - t.i = -1 // mark as removed - } - f := t.f - arg := t.arg - seq := t.seq - unlock(&timers.lock) - if raceenabled { - raceacquire(unsafe.Pointer(t)) - } - f(arg, seq) - lock(&timers.lock) - } - if delta < 0 || faketime > 0 { - // No timers left - put goroutine to sleep. - timers.rescheduling = true - goparkunlock(&timers.lock, "timer goroutine (idle)") - continue - } - // At least one timer pending. Sleep until then. - timers.sleeping = true - noteclear(&timers.waitnote) - unlock(&timers.lock) - notetsleepg(&timers.waitnote, delta) - } -} - -func timejump() *g { - if faketime == 0 { - return nil - } - - lock(&timers.lock) - if !timers.created || len(timers.t) == 0 { - unlock(&timers.lock) - return nil - } - - var gp *g - if faketime < timers.t[0].when { - faketime = timers.t[0].when - if timers.rescheduling { - timers.rescheduling = false - gp = timers.gp - } - } - unlock(&timers.lock) - return gp -} - -// Heap maintenance algorithms. - -func siftupTimer(i int) { - t := timers.t - when := t[i].when - tmp := t[i] - for i > 0 { - p := (i - 1) / 4 // parent - if when >= t[p].when { - break - } - t[i] = t[p] - t[i].i = i - t[p] = tmp - t[p].i = p - i = p - } -} - -func siftdownTimer(i int) { - t := timers.t - n := len(t) - when := t[i].when - tmp := t[i] - for { - c := i*4 + 1 // left child - c3 := c + 2 // mid child - if c >= n { - break - } - w := t[c].when - if c+1 < n && t[c+1].when < w { - w = t[c+1].when - c++ - } - if c3 < n { - w3 := t[c3].when - if c3+1 < n && t[c3+1].when < w3 { - w3 = t[c3+1].when - c3++ - } - if w3 < w { - w = w3 - c = c3 - } - } - if w >= when { - break - } - t[i] = t[c] - t[i].i = i - t[c] = tmp - t[c].i = c - i = c - } -} diff --git a/libgo/go/runtime/typekind.go b/libgo/go/runtime/typekind.go deleted file mode 100644 index b64ec44f9ec..00000000000 --- a/libgo/go/runtime/typekind.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -const ( - kindBool = _KindBool - kindInt = _KindInt - kindInt8 = _KindInt8 - kindInt16 = _KindInt16 - kindInt32 = _KindInt32 - kindInt64 = _KindInt64 - kindUint = _KindUint - kindUint8 = _KindUint8 - kindUint16 = _KindUint16 - kindUint32 = _KindUint32 - kindUint64 = _KindUint64 - kindUintptr = _KindUintptr - kindFloat32 = _KindFloat32 - kindFloat64 = _KindFloat64 - kindComplex64 = _KindComplex64 - kindComplex128 = _KindComplex128 - kindArray = _KindArray - kindChan = _KindChan - kindFunc = _KindFunc - kindInterface = _KindInterface - kindMap = _KindMap - kindPtr = _KindPtr - kindSlice = _KindSlice - kindString = _KindString - kindStruct = _KindStruct - kindUnsafePointer = _KindUnsafePointer - - kindDirectIface = _KindDirectIface - kindGCProg = _KindGCProg - kindNoPointers = _KindNoPointers - kindMask = _KindMask -) - -// isDirectIface reports whether t is stored directly in an interface value. -func isDirectIface(t *_type) bool { - return t.kind&kindDirectIface != 0 -} diff --git a/libgo/go/runtime/vlop_arm_test.go b/libgo/go/runtime/vlop_arm_test.go deleted file mode 100644 index cd28419adfa..00000000000 --- a/libgo/go/runtime/vlop_arm_test.go +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2012 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime_test - -import "testing" - -// arm soft division benchmarks adapted from -// http://ridiculousfish.com/files/division_benchmarks.tar.gz - -const numeratorsSize = 1 << 21 - -var numerators = randomNumerators() - -type randstate struct { - hi, lo uint32 -} - -func (r *randstate) rand() uint32 { - r.hi = r.hi<<16 + r.hi>>16 - r.hi += r.lo - r.lo += r.hi - return r.hi -} - -func randomNumerators() []uint32 { - numerators := make([]uint32, numeratorsSize) - random := &randstate{2147483563, 2147483563 ^ 0x49616E42} - for i := range numerators { - numerators[i] = random.rand() - } - return numerators -} - -func bmUint32Div(divisor uint32, b *testing.B) { - var sum uint32 - for i := 0; i < b.N; i++ { - sum += numerators[i&(numeratorsSize-1)] / divisor - } -} - -func BenchmarkUint32Div7(b *testing.B) { bmUint32Div(7, b) } -func BenchmarkUint32Div37(b *testing.B) { bmUint32Div(37, b) } -func BenchmarkUint32Div123(b *testing.B) { bmUint32Div(123, b) } -func BenchmarkUint32Div763(b *testing.B) { bmUint32Div(763, b) } -func BenchmarkUint32Div1247(b *testing.B) { bmUint32Div(1247, b) } -func BenchmarkUint32Div9305(b *testing.B) { bmUint32Div(9305, b) } -func BenchmarkUint32Div13307(b *testing.B) { bmUint32Div(13307, b) } -func BenchmarkUint32Div52513(b *testing.B) { bmUint32Div(52513, b) } -func BenchmarkUint32Div60978747(b *testing.B) { bmUint32Div(60978747, b) } -func BenchmarkUint32Div106956295(b *testing.B) { bmUint32Div(106956295, b) } - -func bmUint32Mod(divisor uint32, b *testing.B) { - var sum uint32 - for i := 0; i < b.N; i++ { - sum += numerators[i&(numeratorsSize-1)] % divisor - } -} - -func BenchmarkUint32Mod7(b *testing.B) { bmUint32Mod(7, b) } -func BenchmarkUint32Mod37(b *testing.B) { bmUint32Mod(37, b) } -func BenchmarkUint32Mod123(b *testing.B) { bmUint32Mod(123, b) } -func BenchmarkUint32Mod763(b *testing.B) { bmUint32Mod(763, b) } -func BenchmarkUint32Mod1247(b *testing.B) { bmUint32Mod(1247, b) } -func BenchmarkUint32Mod9305(b *testing.B) { bmUint32Mod(9305, b) } -func BenchmarkUint32Mod13307(b *testing.B) { bmUint32Mod(13307, b) } -func BenchmarkUint32Mod52513(b *testing.B) { bmUint32Mod(52513, b) } -func BenchmarkUint32Mod60978747(b *testing.B) { bmUint32Mod(60978747, b) } -func BenchmarkUint32Mod106956295(b *testing.B) { bmUint32Mod(106956295, b) } diff --git a/libgo/go/sort/sort.go b/libgo/go/sort/sort.go index e980c295c32..c7c30426aec 100644 --- a/libgo/go/sort/sort.go +++ b/libgo/go/sort/sort.go @@ -75,20 +75,19 @@ func heapSort(data Interface, a, b int) { // Quicksort, following Bentley and McIlroy, // ``Engineering a Sort Function,'' SP&E November 1993. -// medianOfThree moves the median of the three values data[a], data[b], data[c] into data[a]. -func medianOfThree(data Interface, a, b, c int) { - m0 := b - m1 := a - m2 := c - // bubble sort on 3 elements +// medianOfThree moves the median of the three values data[m0], data[m1], data[m2] into data[m1]. +func medianOfThree(data Interface, m1, m0, m2 int) { + // sort 3 elements if data.Less(m1, m0) { data.Swap(m1, m0) } + // data[m0] <= data[m1] if data.Less(m2, m1) { data.Swap(m2, m1) - } - if data.Less(m1, m0) { - data.Swap(m1, m0) + // data[m0] <= data[m2] && data[m1] < data[m2] + if data.Less(m1, m0) { + data.Swap(m1, m0) + } } // now data[m0] <= data[m1] <= data[m2] } @@ -297,11 +296,11 @@ func StringsAreSorted(a []string) bool { return IsSorted(StringSlice(a)) } // and Jukka Teuhola; Nordic Journal of Computing 3,1 (1996), 27-40: // The given algorithms are in-place, number of Swap and Assignments // grow as n log n but the algorithm is not stable. -// - "Fast Stable In-Plcae Sorting with O(n) Data Moves" J.I. Munro and +// - "Fast Stable In-Place Sorting with O(n) Data Moves" J.I. Munro and // V. Raman in Algorithmica (1996) 16, 115-160: // This algorithm either needs additional 2n bits or works only if there // are enough different elements available to encode some permutations -// which have to be undone later (so not stable an any input). +// which have to be undone later (so not stable on any input). // - All the optimal in-place sorting/merging algorithms I found are either // unstable or rely on enough different elements in each step to encode the // performed block rearrangements. See also "In-Place Merging Algorithms", @@ -316,7 +315,7 @@ func StringsAreSorted(a []string) bool { return IsSorted(StringSlice(a)) } // data.Less and O(n*log(n)*log(n)) calls to data.Swap. func Stable(data Interface) { n := data.Len() - blockSize := 20 + blockSize := 20 // must be > 0 a, b := 0, blockSize for b <= n { insertionSort(data, a, b) @@ -332,7 +331,9 @@ func Stable(data Interface) { a = b b += 2 * blockSize } - symMerge(data, a, a+blockSize, n) + if m := a + blockSize; m < n { + symMerge(data, a, m, n) + } blockSize *= 2 } } @@ -352,72 +353,111 @@ func Stable(data Interface) { // rotation algorithm which uses O(M+N+gcd(M+N)) assignments. The argumentation // in the paper carries through for Swap operations, especially as the block // swapping rotate uses only O(M+N) Swaps. +// +// symMerge assumes non-degenerate arguments: a < m && m < b. +// Having the caller check this condition eliminates many leaf recursion calls, +// which improves performance. func symMerge(data Interface, a, m, b int) { - if a >= m || m >= b { + // Avoid unnecessary recursions of symMerge + // by direct insertion of data[a] into data[m:b] + // if data[a:m] only contains one element. + if m-a == 1 { + // Use binary search to find the lowest index i + // such that data[i] >= data[a] for m <= i < b. + // Exit the search loop with i == b in case no such index exists. + i := m + j := b + for i < j { + h := i + (j-i)/2 + if data.Less(h, a) { + i = h + 1 + } else { + j = h + } + } + // Swap values until data[a] reaches the position before i. + for k := a; k < i-1; k++ { + data.Swap(k, k+1) + } + return + } + + // Avoid unnecessary recursions of symMerge + // by direct insertion of data[m] into data[a:m] + // if data[m:b] only contains one element. + if b-m == 1 { + // Use binary search to find the lowest index i + // such that data[i] > data[m] for a <= i < m. + // Exit the search loop with i == m in case no such index exists. + i := a + j := m + for i < j { + h := i + (j-i)/2 + if !data.Less(m, h) { + i = h + 1 + } else { + j = h + } + } + // Swap values until data[m] reaches the position i. + for k := m; k > i; k-- { + data.Swap(k, k-1) + } return } mid := a + (b-a)/2 n := mid + m - start := 0 + var start, r int if m > mid { start = n - b - r, p := mid, n-1 - for start < r { - c := start + (r-start)/2 - if !data.Less(p-c, c) { - start = c + 1 - } else { - r = c - } - } + r = mid } else { start = a - r, p := m, n-1 - for start < r { - c := start + (r-start)/2 - if !data.Less(p-c, c) { - start = c + 1 - } else { - r = c - } + r = m + } + p := n - 1 + + for start < r { + c := start + (r-start)/2 + if !data.Less(p-c, c) { + start = c + 1 + } else { + r = c } } + end := n - start - rotate(data, start, m, end) - symMerge(data, a, start, mid) - symMerge(data, mid, end, b) + if start < m && m < end { + rotate(data, start, m, end) + } + if a < start && start < mid { + symMerge(data, a, start, mid) + } + if mid < end && end < b { + symMerge(data, mid, end, b) + } } // Rotate two consecutives blocks u = data[a:m] and v = data[m:b] in data: // Data of the form 'x u v y' is changed to 'x v u y'. // Rotate performs at most b-a many calls to data.Swap. +// Rotate assumes non-degenerate arguments: a < m && m < b. func rotate(data Interface, a, m, b int) { i := m - a - if i == 0 { - return - } j := b - m - if j == 0 { - return - } - - if i == j { - swapRange(data, a, m, i) - return - } - p := a + i for i != j { if i > j { - swapRange(data, p-i, p, j) + swapRange(data, m-i, m, j) i -= j } else { - swapRange(data, p-i, p+j-i, i) + swapRange(data, m-i, m+j-i, i) j -= i } } - swapRange(data, p-i, p, i) + // i == j + swapRange(data, m-i, m, i) } /* diff --git a/libgo/go/strconv/atof.go b/libgo/go/strconv/atof.go index beaa68d71f5..a4f4862dba9 100644 --- a/libgo/go/strconv/atof.go +++ b/libgo/go/strconv/atof.go @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Package strconv implements conversions to and from string representations -// of basic data types. package strconv // decimal to binary floating point conversion. diff --git a/libgo/go/strconv/atoi.go b/libgo/go/strconv/atoi.go index 9ecec5a58b9..965e3a218fd 100644 --- a/libgo/go/strconv/atoi.go +++ b/libgo/go/strconv/atoi.go @@ -36,13 +36,7 @@ const intSize = 32 << (^uint(0) >> 63) // IntSize is the size in bits of an int or uint value. const IntSize = intSize -// Return the first number n such that n*base >= 1<<64. -func cutoff64(base int) uint64 { - if base < 2 { - return 0 - } - return (1<<64-1)/uint64(base) + 1 -} +const maxUint64 = (1<<64 - 1) // ParseUint is like ParseInt but for unsigned numbers. func ParseUint(s string, base int, bitSize int) (n uint64, err error) { @@ -52,7 +46,7 @@ func ParseUint(s string, base int, bitSize int) (n uint64, err error) { bitSize = int(IntSize) } - s0 := s + i := 0 switch { case len(s) < 1: err = ErrSyntax @@ -65,14 +59,15 @@ func ParseUint(s string, base int, bitSize int) (n uint64, err error) { // Look for octal, hex prefix. switch { case s[0] == '0' && len(s) > 1 && (s[1] == 'x' || s[1] == 'X'): - base = 16 - s = s[2:] - if len(s) < 1 { + if len(s) < 3 { err = ErrSyntax goto Error } + base = 16 + i = 2 case s[0] == '0': base = 8 + i = 1 default: base = 10 } @@ -82,11 +77,20 @@ func ParseUint(s string, base int, bitSize int) (n uint64, err error) { goto Error } - n = 0 - cutoff = cutoff64(base) + // Cutoff is the smallest number such that cutoff*base > maxUint64. + // Use compile-time constants for common cases. + switch base { + case 10: + cutoff = maxUint64/10 + 1 + case 16: + cutoff = maxUint64/16 + 1 + default: + cutoff = maxUint64/uint64(base) + 1 + } + maxVal = 1<= base { + if v >= byte(base) { n = 0 err = ErrSyntax goto Error @@ -109,7 +113,7 @@ func ParseUint(s string, base int, bitSize int) (n uint64, err error) { if n >= cutoff { // n*base overflows - n = 1<<64 - 1 + n = maxUint64 err = ErrRange goto Error } @@ -118,7 +122,7 @@ func ParseUint(s string, base int, bitSize int) (n uint64, err error) { n1 := n + uint64(v) if n1 < n || n1 > maxVal { // n+v overflows - n = 1<<64 - 1 + n = maxUint64 err = ErrRange goto Error } @@ -128,7 +132,7 @@ func ParseUint(s string, base int, bitSize int) (n uint64, err error) { return n, nil Error: - return n, &NumError{"ParseUint", s0, err} + return n, &NumError{"ParseUint", s, err} } // ParseInt interprets a string s in the given base (2 to 36) and diff --git a/libgo/go/strconv/atoi_test.go b/libgo/go/strconv/atoi_test.go index 94075730788..bd6a6a01fa1 100644 --- a/libgo/go/strconv/atoi_test.go +++ b/libgo/go/strconv/atoi_test.go @@ -33,12 +33,16 @@ var atoui64tests = []atoui64Test{ var btoui64tests = []atoui64Test{ {"", 0, ErrSyntax}, {"0", 0, nil}, + {"0x", 0, ErrSyntax}, + {"0X", 0, ErrSyntax}, {"1", 1, nil}, {"12345", 12345, nil}, {"012345", 012345, nil}, {"0x12345", 0x12345, nil}, {"0X12345", 0x12345, nil}, {"12345x", 0, ErrSyntax}, + {"0xabcdefg123", 0, ErrSyntax}, + {"123456789abc", 0, ErrSyntax}, {"98765432100", 98765432100, nil}, {"18446744073709551615", 1<<64 - 1, nil}, {"18446744073709551616", 1<<64 - 1, ErrRange}, @@ -77,28 +81,61 @@ var atoi64tests = []atoi64Test{ {"-9223372036854775809", -1 << 63, ErrRange}, } -var btoi64tests = []atoi64Test{ - {"", 0, ErrSyntax}, - {"0", 0, nil}, - {"-0", 0, nil}, - {"1", 1, nil}, - {"-1", -1, nil}, - {"12345", 12345, nil}, - {"-12345", -12345, nil}, - {"012345", 012345, nil}, - {"-012345", -012345, nil}, - {"0x12345", 0x12345, nil}, - {"-0X12345", -0x12345, nil}, - {"12345x", 0, ErrSyntax}, - {"-12345x", 0, ErrSyntax}, - {"98765432100", 98765432100, nil}, - {"-98765432100", -98765432100, nil}, - {"9223372036854775807", 1<<63 - 1, nil}, - {"-9223372036854775807", -(1<<63 - 1), nil}, - {"9223372036854775808", 1<<63 - 1, ErrRange}, - {"-9223372036854775808", -1 << 63, nil}, - {"9223372036854775809", 1<<63 - 1, ErrRange}, - {"-9223372036854775809", -1 << 63, ErrRange}, +type btoi64Test struct { + in string + base int + out int64 + err error +} + +var btoi64tests = []btoi64Test{ + {"", 0, 0, ErrSyntax}, + {"0", 0, 0, nil}, + {"-0", 0, 0, nil}, + {"1", 0, 1, nil}, + {"-1", 0, -1, nil}, + {"12345", 0, 12345, nil}, + {"-12345", 0, -12345, nil}, + {"012345", 0, 012345, nil}, + {"-012345", 0, -012345, nil}, + {"0x12345", 0, 0x12345, nil}, + {"-0X12345", 0, -0x12345, nil}, + {"12345x", 0, 0, ErrSyntax}, + {"-12345x", 0, 0, ErrSyntax}, + {"98765432100", 0, 98765432100, nil}, + {"-98765432100", 0, -98765432100, nil}, + {"9223372036854775807", 0, 1<<63 - 1, nil}, + {"-9223372036854775807", 0, -(1<<63 - 1), nil}, + {"9223372036854775808", 0, 1<<63 - 1, ErrRange}, + {"-9223372036854775808", 0, -1 << 63, nil}, + {"9223372036854775809", 0, 1<<63 - 1, ErrRange}, + {"-9223372036854775809", 0, -1 << 63, ErrRange}, + + // other bases + {"g", 17, 16, nil}, + {"10", 25, 25, nil}, + {"holycow", 35, (((((17*35+24)*35+21)*35+34)*35+12)*35+24)*35 + 32, nil}, + {"holycow", 36, (((((17*36+24)*36+21)*36+34)*36+12)*36+24)*36 + 32, nil}, + + // base 2 + {"0", 2, 0, nil}, + {"-1", 2, -1, nil}, + {"1010", 2, 10, nil}, + {"1000000000000000", 2, 1 << 15, nil}, + {"111111111111111111111111111111111111111111111111111111111111111", 2, 1<<63 - 1, nil}, + {"1000000000000000000000000000000000000000000000000000000000000000", 2, 1<<63 - 1, ErrRange}, + {"-1000000000000000000000000000000000000000000000000000000000000000", 2, -1 << 63, nil}, + {"-1000000000000000000000000000000000000000000000000000000000000001", 2, -1 << 63, ErrRange}, + + // base 8 + {"-10", 8, -8, nil}, + {"57635436545", 8, 057635436545, nil}, + {"100000000", 8, 1 << 24, nil}, + + // base 16 + {"10", 16, 16, nil}, + {"-123456789abcdef", 16, -0x123456789abcdef, nil}, + {"7fffffffffffffff", 16, 1<<63 - 1, nil}, } type atoui32Test struct { @@ -234,7 +271,7 @@ func TestParseInt64(t *testing.T) { func TestParseInt64Base(t *testing.T) { for i := range btoi64tests { test := &btoi64tests[i] - out, err := ParseInt(test.in, 0, 64) + out, err := ParseInt(test.in, test.base, 64) if test.out != out || !reflect.DeepEqual(test.err, err) { t.Errorf("ParseInt(%q) = %v, %v want %v, %v", test.in, out, err, test.out, test.err) diff --git a/libgo/go/strconv/decimal.go b/libgo/go/strconv/decimal.go index 42601283d23..5252d6e86eb 100644 --- a/libgo/go/strconv/decimal.go +++ b/libgo/go/strconv/decimal.go @@ -12,7 +12,7 @@ package strconv type decimal struct { - d [800]byte // digits + d [800]byte // digits, big-endian representation nd int // number of digits used dp int // decimal point neg bool @@ -102,16 +102,17 @@ func (a *decimal) Assign(v uint64) { } // Maximum shift that we can do in one pass without overflow. -// Signed int has 31 bits, and we have to be able to accommodate 9<> 63) +const maxShift = uintSize - 4 -// Binary shift right (* 2) by k bits. k <= maxShift to avoid overflow. +// Binary shift right (/ 2) by k bits. k <= maxShift to avoid overflow. func rightShift(a *decimal, k uint) { r := 0 // read pointer w := 0 // write pointer // Pick up enough leading digits to cover first shift. - n := 0 + var n uint for ; n>>k == 0; r++ { if r >= a.nd { if n == 0 { @@ -125,14 +126,14 @@ func rightShift(a *decimal, k uint) { } break } - c := int(a.d[r]) + c := uint(a.d[r]) n = n*10 + c - '0' } a.dp -= r - 1 // Pick up a digit, put down a digit. for ; r < a.nd; r++ { - c := int(a.d[r]) + c := uint(a.d[r]) dig := n >> k n -= dig << k a.d[w] = byte(dig + '0') @@ -169,50 +170,84 @@ func rightShift(a *decimal, k uint) { type leftCheat struct { delta int // number of new digits - cutoff string // minus one digit if original < a. + cutoff string // minus one digit if original < a. } var leftcheats = []leftCheat{ // Leading digits of 1/2^i = 5^i. // 5^23 is not an exact 64-bit floating point number, // so have to use bc for the math. + // Go up to 60 to be large enough for 32bit and 64bit platforms. /* - seq 27 | sed 's/^/5^/' | bc | - awk 'BEGIN{ print "\tleftCheat{ 0, \"\" }," } + seq 60 | sed 's/^/5^/' | bc | + awk 'BEGIN{ print "\t{ 0, \"\" }," } { log2 = log(2)/log(10) - printf("\tleftCheat{ %d, \"%s\" },\t// * %d\n", + printf("\t{ %d, \"%s\" },\t// * %d\n", int(log2*NR+1), $0, 2**NR) }' */ {0, ""}, - {1, "5"}, // * 2 - {1, "25"}, // * 4 - {1, "125"}, // * 8 - {2, "625"}, // * 16 - {2, "3125"}, // * 32 - {2, "15625"}, // * 64 - {3, "78125"}, // * 128 - {3, "390625"}, // * 256 - {3, "1953125"}, // * 512 - {4, "9765625"}, // * 1024 - {4, "48828125"}, // * 2048 - {4, "244140625"}, // * 4096 - {4, "1220703125"}, // * 8192 - {5, "6103515625"}, // * 16384 - {5, "30517578125"}, // * 32768 - {5, "152587890625"}, // * 65536 - {6, "762939453125"}, // * 131072 - {6, "3814697265625"}, // * 262144 - {6, "19073486328125"}, // * 524288 - {7, "95367431640625"}, // * 1048576 - {7, "476837158203125"}, // * 2097152 - {7, "2384185791015625"}, // * 4194304 - {7, "11920928955078125"}, // * 8388608 - {8, "59604644775390625"}, // * 16777216 - {8, "298023223876953125"}, // * 33554432 - {8, "1490116119384765625"}, // * 67108864 - {9, "7450580596923828125"}, // * 134217728 + {1, "5"}, // * 2 + {1, "25"}, // * 4 + {1, "125"}, // * 8 + {2, "625"}, // * 16 + {2, "3125"}, // * 32 + {2, "15625"}, // * 64 + {3, "78125"}, // * 128 + {3, "390625"}, // * 256 + {3, "1953125"}, // * 512 + {4, "9765625"}, // * 1024 + {4, "48828125"}, // * 2048 + {4, "244140625"}, // * 4096 + {4, "1220703125"}, // * 8192 + {5, "6103515625"}, // * 16384 + {5, "30517578125"}, // * 32768 + {5, "152587890625"}, // * 65536 + {6, "762939453125"}, // * 131072 + {6, "3814697265625"}, // * 262144 + {6, "19073486328125"}, // * 524288 + {7, "95367431640625"}, // * 1048576 + {7, "476837158203125"}, // * 2097152 + {7, "2384185791015625"}, // * 4194304 + {7, "11920928955078125"}, // * 8388608 + {8, "59604644775390625"}, // * 16777216 + {8, "298023223876953125"}, // * 33554432 + {8, "1490116119384765625"}, // * 67108864 + {9, "7450580596923828125"}, // * 134217728 + {9, "37252902984619140625"}, // * 268435456 + {9, "186264514923095703125"}, // * 536870912 + {10, "931322574615478515625"}, // * 1073741824 + {10, "4656612873077392578125"}, // * 2147483648 + {10, "23283064365386962890625"}, // * 4294967296 + {10, "116415321826934814453125"}, // * 8589934592 + {11, "582076609134674072265625"}, // * 17179869184 + {11, "2910383045673370361328125"}, // * 34359738368 + {11, "14551915228366851806640625"}, // * 68719476736 + {12, "72759576141834259033203125"}, // * 137438953472 + {12, "363797880709171295166015625"}, // * 274877906944 + {12, "1818989403545856475830078125"}, // * 549755813888 + {13, "9094947017729282379150390625"}, // * 1099511627776 + {13, "45474735088646411895751953125"}, // * 2199023255552 + {13, "227373675443232059478759765625"}, // * 4398046511104 + {13, "1136868377216160297393798828125"}, // * 8796093022208 + {14, "5684341886080801486968994140625"}, // * 17592186044416 + {14, "28421709430404007434844970703125"}, // * 35184372088832 + {14, "142108547152020037174224853515625"}, // * 70368744177664 + {15, "710542735760100185871124267578125"}, // * 140737488355328 + {15, "3552713678800500929355621337890625"}, // * 281474976710656 + {15, "17763568394002504646778106689453125"}, // * 562949953421312 + {16, "88817841970012523233890533447265625"}, // * 1125899906842624 + {16, "444089209850062616169452667236328125"}, // * 2251799813685248 + {16, "2220446049250313080847263336181640625"}, // * 4503599627370496 + {16, "11102230246251565404236316680908203125"}, // * 9007199254740992 + {17, "55511151231257827021181583404541015625"}, // * 18014398509481984 + {17, "277555756156289135105907917022705078125"}, // * 36028797018963968 + {17, "1387778780781445675529539585113525390625"}, // * 72057594037927936 + {18, "6938893903907228377647697925567626953125"}, // * 144115188075855872 + {18, "34694469519536141888238489627838134765625"}, // * 288230376151711744 + {18, "173472347597680709441192448139190673828125"}, // * 576460752303423488 + {19, "867361737988403547205962240695953369140625"}, // * 1152921504606846976 } // Is the leading prefix of b lexicographically less than s? @@ -228,7 +263,7 @@ func prefixIsLessThan(b []byte, s string) bool { return false } -// Binary shift left (/ 2) by k bits. k <= maxShift to avoid overflow. +// Binary shift left (* 2) by k bits. k <= maxShift to avoid overflow. func leftShift(a *decimal, k uint) { delta := leftcheats[k].delta if prefixIsLessThan(a.d[0:a.nd], leftcheats[k].cutoff) { @@ -237,11 +272,11 @@ func leftShift(a *decimal, k uint) { r := a.nd // read index w := a.nd + delta // write index - n := 0 // Pick up a digit, put down a digit. + var n uint for r--; r >= 0; r-- { - n += (int(a.d[r]) - '0') << k + n += (uint(a.d[r]) - '0') << k quo := n / 10 rem := n - 10*quo w-- diff --git a/libgo/go/strconv/doc.go b/libgo/go/strconv/doc.go new file mode 100644 index 00000000000..7bc1e27937f --- /dev/null +++ b/libgo/go/strconv/doc.go @@ -0,0 +1,57 @@ +// Copyright 2015 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 strconv implements conversions to and from string representations +// of basic data types. +// +// Numeric Conversions +// +// The most common numeric conversions are Atoi (string to int) and Itoa (int to string). +// +// i, err := strconv.Atoi("-42") +// s := strconv.Itoa(-42) +// +// These assume decimal and the Go int type. +// +// ParseBool, ParseFloat, ParseInt, and ParseUint convert strings to values: +// +// b, err := strconv.ParseBool("true") +// f, err := strconv.ParseFloat("3.1415", 64) +// i, err := strconv.ParseInt("-42", 10, 64) +// u, err := strconv.ParseUint("42", 10, 64) +// +// The parse functions return the widest type (float64, int64, and uint64), +// but if the size argument specifies a narrower width the result can be +// converted to that narrower type without data loss: +// +// s := "2147483647" // biggest int32 +// i64, err := strconv.ParseInt(s, 10, 32) +// ... +// i := int32(i64) +// +// FormatBool, FormatFloat, FormatInt, and FormatUint convert values to strings: +// +// s := strconv.FormatBool(true) +// s := strconv.FormatFloat(3.1415, 'E', -1, 64) +// s := strconv.FormatInt(-42, 16) +// s := strconv.FormatUint(42, 16) +// +// AppendBool, AppendFloat, AppendInt, and AppendUint are similar but +// append the formatted value to a destination slice. +// +// String Conversions +// +// Quote and QuoteToASCII convert strings to quoted Go string literals. +// The latter guarantees that the result is an ASCII string, by escaping +// any non-ASCII Unicode with \u: +// +// q := Quote("Hello, 世界") +// q := QuoteToASCII("Hello, 世界") +// +// QuoteRune and QuoteRuneToASCII are similar but accept runes and +// return quoted Go rune literals. +// +// Unquote and UnquoteChar unquote Go string and rune literals. +// +package strconv diff --git a/libgo/go/strconv/example_test.go b/libgo/go/strconv/example_test.go new file mode 100644 index 00000000000..01fbbc0fb9e --- /dev/null +++ b/libgo/go/strconv/example_test.go @@ -0,0 +1,338 @@ +// Copyright 2015 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 strconv_test + +import ( + "fmt" + "log" + "strconv" +) + +func ExampleAppendBool() { + b := []byte("bool:") + b = strconv.AppendBool(b, true) + fmt.Println(string(b)) + + // Output: + // bool:true +} + +func ExampleAppendFloat() { + b32 := []byte("float32:") + b32 = strconv.AppendFloat(b32, 3.1415926535, 'E', -1, 32) + fmt.Println(string(b32)) + + b64 := []byte("float64:") + b64 = strconv.AppendFloat(b64, 3.1415926535, 'E', -1, 64) + fmt.Println(string(b64)) + + // Output: + // float32:3.1415927E+00 + // float64:3.1415926535E+00 +} + +func ExampleAppendInt() { + b10 := []byte("int (base 10):") + b10 = strconv.AppendInt(b10, -42, 10) + fmt.Println(string(b10)) + + b16 := []byte("int (base 16):") + b16 = strconv.AppendInt(b16, -42, 16) + fmt.Println(string(b16)) + + // Output: + // int (base 10):-42 + // int (base 16):-2a +} + +func ExampleAppendQuote() { + b := []byte("quote:") + b = strconv.AppendQuote(b, `"Fran & Freddie's Diner"`) + fmt.Println(string(b)) + + // Output: + // quote:"\"Fran & Freddie's Diner\"" +} + +func ExampleAppendQuoteRune() { + b := []byte("rune:") + b = strconv.AppendQuoteRune(b, '☺') + fmt.Println(string(b)) + + // Output: + // rune:'☺' +} + +func ExampleAppendQuoteRuneToASCII() { + b := []byte("rune (ascii):") + b = strconv.AppendQuoteRuneToASCII(b, '☺') + fmt.Println(string(b)) + + // Output: + // rune (ascii):'\u263a' +} + +func ExampleAppendQuoteToASCII() { + b := []byte("quote (ascii):") + b = strconv.AppendQuoteToASCII(b, `"Fran & Freddie's Diner"`) + fmt.Println(string(b)) + + // Output: + // quote (ascii):"\"Fran & Freddie's Diner\"" +} + +func ExampleAppendUint() { + b10 := []byte("uint (base 10):") + b10 = strconv.AppendUint(b10, 42, 10) + fmt.Println(string(b10)) + + b16 := []byte("uint (base 16):") + b16 = strconv.AppendUint(b16, 42, 16) + fmt.Println(string(b16)) + + // Output: + // uint (base 10):42 + // uint (base 16):2a +} + +func ExampleAtoi() { + v := "10" + if s, err := strconv.Atoi(v); err == nil { + fmt.Printf("%T, %v", s, s) + } + + // Output: + // int, 10 +} + +func ExampleCanBackquote() { + fmt.Println(strconv.CanBackquote("Fran & Freddie's Diner ☺")) + fmt.Println(strconv.CanBackquote("`can't backquote this`")) + + // Output: + // true + // false +} + +func ExampleFormatBool() { + v := true + s := strconv.FormatBool(v) + fmt.Printf("%T, %v\n", s, s) + + // Output: + // string, true +} + +func ExampleFormatFloat() { + v := 3.1415926535 + + s32 := strconv.FormatFloat(v, 'E', -1, 32) + fmt.Printf("%T, %v\n", s32, s32) + + s64 := strconv.FormatFloat(v, 'E', -1, 64) + fmt.Printf("%T, %v\n", s64, s64) + + // Output: + // string, 3.1415927E+00 + // string, 3.1415926535E+00 +} + +func ExampleFormatInt() { + v := int64(-42) + + s10 := strconv.FormatInt(v, 10) + fmt.Printf("%T, %v\n", s10, s10) + + s16 := strconv.FormatInt(v, 16) + fmt.Printf("%T, %v\n", s16, s16) + + // Output: + // string, -42 + // string, -2a +} + +func ExampleFormatUint() { + v := uint64(42) + + s10 := strconv.FormatUint(v, 10) + fmt.Printf("%T, %v\n", s10, s10) + + s16 := strconv.FormatUint(v, 16) + fmt.Printf("%T, %v\n", s16, s16) + + // Output: + // string, 42 + // string, 2a +} + +func ExampleIsPrint() { + c := strconv.IsPrint('\u263a') + fmt.Println(c) + + bel := strconv.IsPrint('\007') + fmt.Println(bel) + + // Output: + // true + // false +} + +func ExampleItoa() { + i := 10 + s := strconv.Itoa(i) + fmt.Printf("%T, %v\n", s, s) + + // Output: + // string, 10 +} + +func ExampleParseBool() { + v := "true" + if s, err := strconv.ParseBool(v); err == nil { + fmt.Printf("%T, %v\n", s, s) + } + + // Output: + // bool, true +} + +func ExampleParseFloat() { + v := "3.1415926535" + if s, err := strconv.ParseFloat(v, 32); err == nil { + fmt.Printf("%T, %v\n", s, s) + } + if s, err := strconv.ParseFloat(v, 64); err == nil { + fmt.Printf("%T, %v\n", s, s) + } + + // Output: + // float64, 3.1415927410125732 + // float64, 3.1415926535 +} + +func ExampleParseInt() { + v32 := "-354634382" + if s, err := strconv.ParseInt(v32, 10, 32); err == nil { + fmt.Printf("%T, %v\n", s, s) + } + if s, err := strconv.ParseInt(v32, 16, 32); err == nil { + fmt.Printf("%T, %v\n", s, s) + } + + v64 := "-3546343826724305832" + if s, err := strconv.ParseInt(v64, 10, 64); err == nil { + fmt.Printf("%T, %v\n", s, s) + } + if s, err := strconv.ParseInt(v64, 16, 64); err == nil { + fmt.Printf("%T, %v\n", s, s) + } + + // Output: + // int64, -354634382 + // int64, -3546343826724305832 +} + +func ExampleParseUint() { + v := "42" + if s, err := strconv.ParseUint(v, 10, 32); err == nil { + fmt.Printf("%T, %v\n", s, s) + } + if s, err := strconv.ParseUint(v, 10, 64); err == nil { + fmt.Printf("%T, %v\n", s, s) + } + + // Output: + // uint64, 42 + // uint64, 42 +} + +func ExampleQuote() { + s := strconv.Quote(`"Fran & Freddie's Diner ☺"`) + fmt.Println(s) + + // Output: + // "\"Fran & Freddie's Diner\t☺\"" +} + +func ExampleQuoteRune() { + s := strconv.QuoteRune('☺') + fmt.Println(s) + + // Output: + // '☺' +} + +func ExampleQuoteRuneToASCII() { + s := strconv.QuoteRuneToASCII('☺') + fmt.Println(s) + + // Output: + // '\u263a' +} + +func ExampleQuoteToASCII() { + s := strconv.QuoteToASCII(`"Fran & Freddie's Diner ☺"`) + fmt.Println(s) + + // Output: + // "\"Fran & Freddie's Diner\t\u263a\"" +} + +func ExampleUnquote() { + test := func(s string) { + t, err := strconv.Unquote(s) + if err != nil { + fmt.Printf("Unquote(%#v): %v\n", s, err) + } else { + fmt.Printf("Unquote(%#v) = %v\n", s, t) + } + } + + s := `\"Fran & Freddie's Diner\t\u263a\"\"` + // If the string doesn't have quotes, it can't be unquoted. + test(s) // invalid syntax + test("`" + s + "`") + test(`"` + s + `"`) + test(`'\u263a'`) + + // Output: + // Unquote("\\\"Fran & Freddie's Diner\\t\\u263a\\\"\\\""): invalid syntax + // Unquote("`\\\"Fran & Freddie's Diner\\t\\u263a\\\"\\\"`") = \"Fran & Freddie's Diner\t\u263a\"\" + // Unquote("\"\\\"Fran & Freddie's Diner\\t\\u263a\\\"\\\"\"") = "Fran & Freddie's Diner ☺"" + // Unquote("'\\u263a'") = ☺ +} + +func ExampleUnquoteChar() { + v, mb, t, err := strconv.UnquoteChar(`\"Fran & Freddie's Diner\"`, '"') + if err != nil { + log.Fatal(err) + } + + fmt.Println("value:", string(v)) + fmt.Println("multibyte:", mb) + fmt.Println("tail:", t) + + // Output: + // value: " + // multibyte: false + // tail: Fran & Freddie's Diner\" +} + +func ExampleNumError() { + str := "Not a number" + if _, err := strconv.ParseFloat(str, 64); err != nil { + e := err.(*strconv.NumError) + fmt.Println("Func:", e.Func) + fmt.Println("Num:", e.Num) + fmt.Println("Err:", e.Err) + fmt.Println(err) + } + + // Output: + // Func: ParseFloat + // Num: Not a number + // Err: invalid syntax + // strconv.ParseFloat: parsing "Not a number": invalid syntax +} diff --git a/libgo/go/strconv/extfloat.go b/libgo/go/strconv/extfloat.go index bed8b16bdae..019b4eebdc9 100644 --- a/libgo/go/strconv/extfloat.go +++ b/libgo/go/strconv/extfloat.go @@ -256,7 +256,7 @@ var uint64pow10 = [...]uint64{ } // AssignDecimal sets f to an approximate value mantissa*10^exp. It -// returns true if the value represented by f is guaranteed to be the +// reports whether the value represented by f is guaranteed to be the // best approximation of d after being rounded to a float64 or // float32 depending on flt. func (f *extFloat) AssignDecimal(mantissa uint64, exp10 int, neg bool, trunc bool, flt *floatInfo) (ok bool) { diff --git a/libgo/go/strconv/ftoa.go b/libgo/go/strconv/ftoa.go index 1a9c41b85a8..468c37fafb9 100644 --- a/libgo/go/strconv/ftoa.go +++ b/libgo/go/strconv/ftoa.go @@ -47,7 +47,7 @@ func FormatFloat(f float64, fmt byte, prec, bitSize int) string { // AppendFloat appends the string form of the floating-point number f, // as generated by FormatFloat, to dst and returns the extended buffer. -func AppendFloat(dst []byte, f float64, fmt byte, prec int, bitSize int) []byte { +func AppendFloat(dst []byte, f float64, fmt byte, prec, bitSize int) []byte { return genericFtoa(dst, f, fmt, prec, bitSize) } @@ -119,7 +119,7 @@ func genericFtoa(dst []byte, val float64, fmt byte, prec, bitSize int) []byte { // Precision for shortest representation mode. switch fmt { case 'e', 'E': - prec = digs.nd - 1 + prec = max(digs.nd-1, 0) case 'f': prec = max(digs.nd-digs.dp, 0) case 'g', 'G': @@ -223,9 +223,8 @@ func formatDigits(dst []byte, shortest bool, neg bool, digs decimalSlice, prec i return append(dst, '%', fmt) } -// Round d (= mant * 2^exp) to the shortest number of digits -// that will let the original floating point value be precisely -// reconstructed. Size is original floating point size (64 or 32). +// roundShortest rounds d (= mant * 2^exp) to the shortest number of digits +// that will let the original floating point value be precisely reconstructed. func roundShortest(d *decimal, mant uint64, exp int, flt *floatInfo) { // If mantissa is zero, the number is zero; stop now. if mant == 0 { @@ -348,14 +347,13 @@ func fmtE(dst []byte, neg bool, d decimalSlice, prec int, fmt byte) []byte { if prec > 0 { dst = append(dst, '.') i := 1 - m := d.nd + prec + 1 - max(d.nd, prec+1) - for i < m { - dst = append(dst, d.d[i]) - i++ + m := min(d.nd, prec+1) + if i < m { + dst = append(dst, d.d[i:m]...) + i = m } - for i <= prec { + for ; i <= prec; i++ { dst = append(dst, '0') - i++ } } @@ -373,27 +371,16 @@ func fmtE(dst []byte, neg bool, d decimalSlice, prec int, fmt byte) []byte { } dst = append(dst, ch) - // dddd - var buf [3]byte - i := len(buf) - for exp >= 10 { - i-- - buf[i] = byte(exp%10 + '0') - exp /= 10 + // dd or ddd + switch { + case exp < 10: + dst = append(dst, '0', byte(exp)+'0') + case exp < 100: + dst = append(dst, byte(exp/10)+'0', byte(exp%10)+'0') + default: + dst = append(dst, byte(exp/100)+'0', byte(exp/10)%10+'0', byte(exp%10)+'0') } - // exp < 10 - i-- - buf[i] = byte(exp + '0') - switch i { - case 0: - dst = append(dst, buf[0], buf[1], buf[2]) - case 1: - dst = append(dst, buf[1], buf[2]) - case 2: - // leading zeroes - dst = append(dst, '0', buf[2]) - } return dst } @@ -406,11 +393,9 @@ func fmtF(dst []byte, neg bool, d decimalSlice, prec int) []byte { // integer, padded with zeros as needed. if d.dp > 0 { - var i int - for i = 0; i < d.dp && i < d.nd; i++ { - dst = append(dst, d.d[i]) - } - for ; i < d.dp; i++ { + m := min(d.nd, d.dp) + dst = append(dst, d.d[:m]...) + for ; m < d.dp; m++ { dst = append(dst, '0') } } else { @@ -432,39 +417,34 @@ func fmtF(dst []byte, neg bool, d decimalSlice, prec int) []byte { return dst } -// %b: -ddddddddp+ddd +// %b: -ddddddddp±ddd func fmtB(dst []byte, neg bool, mant uint64, exp int, flt *floatInfo) []byte { - var buf [50]byte - w := len(buf) - exp -= int(flt.mantbits) - esign := byte('+') - if exp < 0 { - esign = '-' - exp = -exp - } - n := 0 - for exp > 0 || n < 1 { - n++ - w-- - buf[w] = byte(exp%10 + '0') - exp /= 10 + // sign + if neg { + dst = append(dst, '-') } - w-- - buf[w] = esign - w-- - buf[w] = 'p' - n = 0 - for mant > 0 || n < 1 { - n++ - w-- - buf[w] = byte(mant%10 + '0') - mant /= 10 + + // mantissa + dst, _ = formatBits(dst, mant, 10, false, true) + + // p + dst = append(dst, 'p') + + // ±exponent + exp -= int(flt.mantbits) + if exp >= 0 { + dst = append(dst, '+') } - if neg { - w-- - buf[w] = '-' + dst, _ = formatBits(dst, uint64(exp), 10, exp < 0, true) + + return dst +} + +func min(a, b int) int { + if a < b { + return a } - return append(dst, buf[w:]...) + return b } func max(a, b int) int { diff --git a/libgo/go/strconv/ftoa_test.go b/libgo/go/strconv/ftoa_test.go index 39b861547ea..1b4dcd945b8 100644 --- a/libgo/go/strconv/ftoa_test.go +++ b/libgo/go/strconv/ftoa_test.go @@ -227,6 +227,7 @@ func BenchmarkAppendFloatNegExp(b *testing.B) { benchmarkAppendFloat(b, -5.11e- func BenchmarkAppendFloatBig(b *testing.B) { benchmarkAppendFloat(b, 123456789123456789123456789, 'g', -1, 64) } +func BenchmarkAppendFloatBinaryExp(b *testing.B) { benchmarkAppendFloat(b, -1, 'b', -1, 64) } func BenchmarkAppendFloat32Integer(b *testing.B) { benchmarkAppendFloat(b, 33909, 'g', -1, 32) } func BenchmarkAppendFloat32ExactFraction(b *testing.B) { benchmarkAppendFloat(b, 3.375, 'g', -1, 32) } diff --git a/libgo/go/strconv/isprint.go b/libgo/go/strconv/isprint.go index 80738ed7111..0cf363c699e 100644 --- a/libgo/go/strconv/isprint.go +++ b/libgo/go/strconv/isprint.go @@ -7,7 +7,7 @@ package strconv -// (468+138+67)*2 + (326)*4 = 2650 bytes +// (470+136+73)*2 + (342)*4 = 2726 bytes var isPrint16 = []uint16{ 0x0020, 0x007e, @@ -26,8 +26,8 @@ var isPrint16 = []uint16{ 0x0800, 0x082d, 0x0830, 0x085b, 0x085e, 0x085e, - 0x08a0, 0x08b2, - 0x08e4, 0x098c, + 0x08a0, 0x08b4, + 0x08e3, 0x098c, 0x098f, 0x0990, 0x0993, 0x09b2, 0x09b6, 0x09b9, @@ -51,6 +51,7 @@ var isPrint16 = []uint16{ 0x0ad0, 0x0ad0, 0x0ae0, 0x0ae3, 0x0ae6, 0x0af1, + 0x0af9, 0x0af9, 0x0b01, 0x0b0c, 0x0b0f, 0x0b10, 0x0b13, 0x0b39, @@ -73,7 +74,7 @@ var isPrint16 = []uint16{ 0x0be6, 0x0bfa, 0x0c00, 0x0c39, 0x0c3d, 0x0c4d, - 0x0c55, 0x0c59, + 0x0c55, 0x0c5a, 0x0c60, 0x0c63, 0x0c66, 0x0c6f, 0x0c78, 0x0cb9, @@ -84,7 +85,7 @@ var isPrint16 = []uint16{ 0x0d01, 0x0d3a, 0x0d3d, 0x0d4e, 0x0d57, 0x0d57, - 0x0d60, 0x0d63, + 0x0d5f, 0x0d63, 0x0d66, 0x0d75, 0x0d79, 0x0d7f, 0x0d82, 0x0d96, @@ -117,7 +118,8 @@ var isPrint16 = []uint16{ 0x1318, 0x135a, 0x135d, 0x137c, 0x1380, 0x1399, - 0x13a0, 0x13f4, + 0x13a0, 0x13f5, + 0x13f8, 0x13fd, 0x1400, 0x169c, 0x16a0, 0x16f8, 0x1700, 0x1714, @@ -167,9 +169,9 @@ var isPrint16 = []uint16{ 0x2030, 0x205e, 0x2070, 0x2071, 0x2074, 0x209c, - 0x20a0, 0x20bd, + 0x20a0, 0x20be, 0x20d0, 0x20f0, - 0x2100, 0x2189, + 0x2100, 0x218b, 0x2190, 0x23fa, 0x2400, 0x2426, 0x2440, 0x244a, @@ -177,6 +179,7 @@ var isPrint16 = []uint16{ 0x2b76, 0x2b95, 0x2b98, 0x2bb9, 0x2bbd, 0x2bd1, + 0x2bec, 0x2bef, 0x2c00, 0x2cf3, 0x2cf9, 0x2d27, 0x2d2d, 0x2d2d, @@ -193,19 +196,19 @@ var isPrint16 = []uint16{ 0x3131, 0x31ba, 0x31c0, 0x31e3, 0x31f0, 0x4db5, - 0x4dc0, 0x9fcc, + 0x4dc0, 0x9fd5, 0xa000, 0xa48c, 0xa490, 0xa4c6, 0xa4d0, 0xa62b, 0xa640, 0xa6f7, 0xa700, 0xa7ad, - 0xa7b0, 0xa7b1, + 0xa7b0, 0xa7b7, 0xa7f7, 0xa82b, 0xa830, 0xa839, 0xa840, 0xa877, 0xa880, 0xa8c4, 0xa8ce, 0xa8d9, - 0xa8e0, 0xa8fb, + 0xa8e0, 0xa8fd, 0xa900, 0xa953, 0xa95f, 0xa97c, 0xa980, 0xa9d9, @@ -217,9 +220,8 @@ var isPrint16 = []uint16{ 0xab01, 0xab06, 0xab09, 0xab0e, 0xab11, 0xab16, - 0xab20, 0xab5f, - 0xab64, 0xab65, - 0xabc0, 0xabed, + 0xab20, 0xab65, + 0xab70, 0xabed, 0xabf0, 0xabf9, 0xac00, 0xd7a3, 0xd7b0, 0xd7c6, @@ -234,8 +236,7 @@ var isPrint16 = []uint16{ 0xfd92, 0xfdc7, 0xfdf0, 0xfdfd, 0xfe00, 0xfe19, - 0xfe20, 0xfe2d, - 0xfe30, 0xfe6b, + 0xfe20, 0xfe6b, 0xfe70, 0xfefc, 0xff01, 0xffbe, 0xffc2, 0xffc7, @@ -370,8 +371,6 @@ var isNotPrint16 = []uint16{ 0x318f, 0x321f, 0x32ff, - 0xa69e, - 0xa78f, 0xa9ce, 0xa9ff, 0xab27, @@ -418,12 +417,13 @@ var isPrint32 = []uint32{ 0x01083c, 0x01083c, 0x01083f, 0x01089e, 0x0108a7, 0x0108af, - 0x010900, 0x01091b, + 0x0108e0, 0x0108f5, + 0x0108fb, 0x01091b, 0x01091f, 0x010939, 0x01093f, 0x01093f, 0x010980, 0x0109b7, - 0x0109be, 0x0109bf, - 0x010a00, 0x010a06, + 0x0109bc, 0x0109cf, + 0x0109d2, 0x010a06, 0x010a0c, 0x010a33, 0x010a38, 0x010a3a, 0x010a3f, 0x010a47, @@ -438,6 +438,9 @@ var isPrint32 = []uint32{ 0x010b99, 0x010b9c, 0x010ba9, 0x010baf, 0x010c00, 0x010c48, + 0x010c80, 0x010cb2, + 0x010cc0, 0x010cf2, + 0x010cfa, 0x010cff, 0x010e60, 0x010e7e, 0x011000, 0x01104d, 0x011052, 0x01106f, @@ -446,19 +449,19 @@ var isPrint32 = []uint32{ 0x0110f0, 0x0110f9, 0x011100, 0x011143, 0x011150, 0x011176, - 0x011180, 0x0111c8, - 0x0111cd, 0x0111cd, - 0x0111d0, 0x0111da, - 0x0111e1, 0x0111f4, + 0x011180, 0x0111cd, + 0x0111d0, 0x0111f4, 0x011200, 0x01123d, + 0x011280, 0x0112a9, 0x0112b0, 0x0112ea, 0x0112f0, 0x0112f9, - 0x011301, 0x01130c, + 0x011300, 0x01130c, 0x01130f, 0x011310, 0x011313, 0x011339, 0x01133c, 0x011344, 0x011347, 0x011348, 0x01134b, 0x01134d, + 0x011350, 0x011350, 0x011357, 0x011357, 0x01135d, 0x011363, 0x011366, 0x01136c, @@ -466,17 +469,22 @@ var isPrint32 = []uint32{ 0x011480, 0x0114c7, 0x0114d0, 0x0114d9, 0x011580, 0x0115b5, - 0x0115b8, 0x0115c9, + 0x0115b8, 0x0115dd, 0x011600, 0x011644, 0x011650, 0x011659, 0x011680, 0x0116b7, 0x0116c0, 0x0116c9, + 0x011700, 0x011719, + 0x01171d, 0x01172b, + 0x011730, 0x01173f, 0x0118a0, 0x0118f2, 0x0118ff, 0x0118ff, 0x011ac0, 0x011af8, - 0x012000, 0x012398, + 0x012000, 0x012399, 0x012400, 0x012474, + 0x012480, 0x012543, 0x013000, 0x01342e, + 0x014400, 0x014646, 0x016800, 0x016a38, 0x016a40, 0x016a69, 0x016a6e, 0x016a6f, @@ -497,7 +505,7 @@ var isPrint32 = []uint32{ 0x01d000, 0x01d0f5, 0x01d100, 0x01d126, 0x01d129, 0x01d172, - 0x01d17b, 0x01d1dd, + 0x01d17b, 0x01d1e8, 0x01d200, 0x01d245, 0x01d300, 0x01d356, 0x01d360, 0x01d371, @@ -508,7 +516,8 @@ var isPrint32 = []uint32{ 0x01d50d, 0x01d546, 0x01d54a, 0x01d6a5, 0x01d6a8, 0x01d7cb, - 0x01d7ce, 0x01d7ff, + 0x01d7ce, 0x01da8b, + 0x01da9b, 0x01daaf, 0x01e800, 0x01e8c4, 0x01e8c7, 0x01e8d6, 0x01ee00, 0x01ee24, @@ -530,13 +539,7 @@ var isPrint32 = []uint32{ 0x01f210, 0x01f23a, 0x01f240, 0x01f248, 0x01f250, 0x01f251, - 0x01f300, 0x01f32c, - 0x01f330, 0x01f37d, - 0x01f380, 0x01f3ce, - 0x01f3d4, 0x01f3f7, - 0x01f400, 0x01f54a, - 0x01f550, 0x01f642, - 0x01f645, 0x01f6cf, + 0x01f300, 0x01f6d0, 0x01f6e0, 0x01f6ec, 0x01f6f0, 0x01f6f3, 0x01f700, 0x01f773, @@ -546,9 +549,13 @@ var isPrint32 = []uint32{ 0x01f850, 0x01f859, 0x01f860, 0x01f887, 0x01f890, 0x01f8ad, + 0x01f910, 0x01f918, + 0x01f980, 0x01f984, + 0x01f9c0, 0x01f9c0, 0x020000, 0x02a6d6, 0x02a700, 0x02b734, 0x02b740, 0x02b81d, + 0x02b820, 0x02cea1, 0x02f800, 0x02fa1d, 0x0e0100, 0x0e01ef, } @@ -562,12 +569,18 @@ var isNotPrint32 = []uint16{ // add 0x10000 to each entry 0x0809, 0x0836, 0x0856, + 0x08f3, 0x0a04, 0x0a14, 0x0a18, 0x10bd, 0x1135, + 0x11e0, 0x1212, + 0x1287, + 0x1289, + 0x128e, + 0x129e, 0x1304, 0x1329, 0x1331, @@ -589,6 +602,7 @@ var isNotPrint32 = []uint16{ // add 0x10000 to each entry 0xd53f, 0xd545, 0xd551, + 0xdaa0, 0xee04, 0xee20, 0xee23, @@ -618,7 +632,6 @@ var isNotPrint32 = []uint16{ // add 0x10000 to each entry 0xf0c0, 0xf0d0, 0xf12f, - 0xf4ff, 0xf57a, 0xf5a4, } diff --git a/libgo/go/strconv/itoa.go b/libgo/go/strconv/itoa.go index 67f17d86647..e6f6303356b 100644 --- a/libgo/go/strconv/itoa.go +++ b/libgo/go/strconv/itoa.go @@ -40,9 +40,7 @@ func AppendUint(dst []byte, i uint64, base int) []byte { } const ( - digits = "0123456789abcdefghijklmnopqrstuvwxyz" - digits01 = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" - digits10 = "0000000000111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999" + digits = "0123456789abcdefghijklmnopqrstuvwxyz" ) var shifts = [len(digits) + 1]uint{ @@ -74,23 +72,34 @@ func formatBits(dst []byte, u uint64, base int, neg, append_ bool) (d []byte, s // convert bits if base == 10 { - // common case: use constants for / and % because - // the compiler can optimize it into a multiply+shift, - // and unroll loop - for u >= 100 { - i -= 2 - q := u / 100 - j := uintptr(u - q*100) - a[i+1] = digits01[j] - a[i+0] = digits10[j] - u = q + // common case: use constants for / because + // the compiler can optimize it into a multiply+shift + + if ^uintptr(0)>>32 == 0 { + for u > uint64(^uintptr(0)) { + q := u / 1e9 + us := uintptr(u - q*1e9) // us % 1e9 fits into a uintptr + for j := 9; j > 0; j-- { + i-- + qs := us / 10 + a[i] = byte(us - qs*10 + '0') + us = qs + } + u = q + } } - if u >= 10 { + + // u guaranteed to fit into a uintptr + us := uintptr(u) + for us >= 10 { i-- - q := u / 10 - a[i] = digits[uintptr(u-q*10)] - u = q + q := us / 10 + a[i] = byte(us - q*10 + '0') + us = q } + // u < 10 + i-- + a[i] = byte(us + '0') } else if s := shifts[base]; s > 0 { // base is power of 2: use shifts and masks instead of / and % @@ -101,21 +110,24 @@ func formatBits(dst []byte, u uint64, base int, neg, append_ bool) (d []byte, s a[i] = digits[uintptr(u)&m] u >>= s } + // u < base + i-- + a[i] = digits[uintptr(u)] } else { // general case b := uint64(base) for u >= b { i-- - a[i] = digits[uintptr(u%b)] - u /= b + q := u / b + a[i] = digits[uintptr(u-q*b)] + u = q } + // u < base + i-- + a[i] = digits[uintptr(u)] } - // u < base - i-- - a[i] = digits[uintptr(u)] - // add sign, if any if neg { i-- diff --git a/libgo/go/strconv/itoa_test.go b/libgo/go/strconv/itoa_test.go index e0213ae9afe..48dc03e8390 100644 --- a/libgo/go/strconv/itoa_test.go +++ b/libgo/go/strconv/itoa_test.go @@ -51,6 +51,7 @@ var itob64tests = []itob64Test{ {-0x123456789abcdef, 16, "-123456789abcdef"}, {1<<63 - 1, 16, "7fffffffffffffff"}, {1<<63 - 1, 2, "111111111111111111111111111111111111111111111111111111111111111"}, + {-1 << 63, 2, "-1000000000000000000000000000000000000000000000000000000000000000"}, {16, 17, "g"}, {25, 25, "10"}, diff --git a/libgo/go/strconv/quote_example_test.go b/libgo/go/strconv/quote_example_test.go deleted file mode 100644 index 405a57eb576..00000000000 --- a/libgo/go/strconv/quote_example_test.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2013 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package strconv_test - -import ( - "fmt" - "strconv" -) - -func ExampleUnquote() { - test := func(s string) { - t, err := strconv.Unquote(s) - if err != nil { - fmt.Printf("Unquote(%#v): %v\n", s, err) - } else { - fmt.Printf("Unquote(%#v) = %v\n", s, t) - } - } - - s := `cafe\u0301` - // If the string doesn't have quotes, it can't be unquoted. - test(s) // invalid syntax - test("`" + s + "`") - test(`"` + s + `"`) - - test(`'\u00e9'`) - - // Output: - // Unquote("cafe\\u0301"): invalid syntax - // Unquote("`cafe\\u0301`") = cafe\u0301 - // Unquote("\"cafe\\u0301\"") = café - // Unquote("'\\u00e9'") = é -} diff --git a/libgo/go/strings/compare.go b/libgo/go/strings/compare.go new file mode 100644 index 00000000000..b84dddea74e --- /dev/null +++ b/libgo/go/strings/compare.go @@ -0,0 +1,28 @@ +// Copyright 2015 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 strings + +// Compare returns an integer comparing two strings lexicographically. +// The result will be 0 if a==b, -1 if a < b, and +1 if a > b. +// +// Compare is included only for symmetry with package bytes. +// It is usually clearer and always faster to use the built-in +// string comparison operators ==, <, >, and so on. +func Compare(a, b string) int { + // NOTE(rsc): This function does NOT call the runtime cmpstring function, + // because we do not want to provide any performance justification for + // using strings.Compare. Basically no one should use strings.Compare. + // As the comment above says, it is here only for symmetry with package bytes. + // If performance is important, the compiler should be changed to recognize + // the pattern so that all code doing three-way comparisons, not just code + // using strings.Compare, can benefit. + if a == b { + return 0 + } + if a < b { + return -1 + } + return +1 +} diff --git a/libgo/go/strings/compare_test.go b/libgo/go/strings/compare_test.go new file mode 100644 index 00000000000..68fc88e1431 --- /dev/null +++ b/libgo/go/strings/compare_test.go @@ -0,0 +1,98 @@ +// Copyright 2013 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package strings_test + +// Derived from bytes/compare_test.go. +// Benchmarks omitted since the underlying implementation is identical. + +import ( + . "strings" + "testing" +) + +var compareTests = []struct { + a, b string + i int +}{ + {"", "", 0}, + {"a", "", 1}, + {"", "a", -1}, + {"abc", "abc", 0}, + {"ab", "abc", -1}, + {"abc", "ab", 1}, + {"x", "ab", 1}, + {"ab", "x", -1}, + {"x", "a", 1}, + {"b", "x", -1}, + // test runtime·memeq's chunked implementation + {"abcdefgh", "abcdefgh", 0}, + {"abcdefghi", "abcdefghi", 0}, + {"abcdefghi", "abcdefghj", -1}, +} + +func TestCompare(t *testing.T) { + for _, tt := range compareTests { + cmp := Compare(tt.a, tt.b) + if cmp != tt.i { + t.Errorf(`Compare(%q, %q) = %v`, tt.a, tt.b, cmp) + } + } +} + +func TestCompareIdenticalString(t *testing.T) { + var s = "Hello Gophers!" + if Compare(s, s) != 0 { + t.Error("s != s") + } + if Compare(s, s[:1]) != 1 { + t.Error("s > s[:1] failed") + } +} + +func TestCompareStrings(t *testing.T) { + n := 128 + a := make([]byte, n+1) + b := make([]byte, n+1) + for len := 0; len < 128; len++ { + // randomish but deterministic data. No 0 or 255. + for i := 0; i < len; i++ { + a[i] = byte(1 + 31*i%254) + b[i] = byte(1 + 31*i%254) + } + // data past the end is different + for i := len; i <= n; i++ { + a[i] = 8 + b[i] = 9 + } + + cmp := Compare(string(a[:len]), string(b[:len])) + if cmp != 0 { + t.Errorf(`CompareIdentical(%d) = %d`, len, cmp) + } + if len > 0 { + cmp = Compare(string(a[:len-1]), string(b[:len])) + if cmp != -1 { + t.Errorf(`CompareAshorter(%d) = %d`, len, cmp) + } + cmp = Compare(string(a[:len]), string(b[:len-1])) + if cmp != 1 { + t.Errorf(`CompareBshorter(%d) = %d`, len, cmp) + } + } + for k := 0; k < len; k++ { + b[k] = a[k] - 1 + cmp = Compare(string(a[:len]), string(b[:len])) + if cmp != 1 { + t.Errorf(`CompareAbigger(%d,%d) = %d`, len, k, cmp) + } + b[k] = a[k] + 1 + cmp = Compare(string(a[:len]), string(b[:len])) + if cmp != -1 { + t.Errorf(`CompareBbigger(%d,%d) = %d`, len, k, cmp) + } + b[k] = a[k] + } + } +} diff --git a/libgo/go/strings/reader.go b/libgo/go/strings/reader.go index 82df974398c..7a872fbcb08 100644 --- a/libgo/go/strings/reader.go +++ b/libgo/go/strings/reader.go @@ -28,6 +28,12 @@ func (r *Reader) Len() int { return int(int64(len(r.s)) - r.i) } +// Size returns the original length of the underlying string. +// Size is the number of bytes available for reading via ReadAt. +// The returned value is always the same and is not affected by calls +// to any other method. +func (r *Reader) Size() int64 { return int64(len(r.s)) } + func (r *Reader) Read(b []byte) (n int, err error) { if len(b) == 0 { return 0, nil diff --git a/libgo/go/strings/reader_test.go b/libgo/go/strings/reader_test.go index bee90eb2585..5003a37be48 100644 --- a/libgo/go/strings/reader_test.go +++ b/libgo/go/strings/reader_test.go @@ -8,6 +8,7 @@ import ( "bytes" "fmt" "io" + "io/ioutil" "os" "strings" "sync" @@ -157,3 +158,15 @@ func TestWriteTo(t *testing.T) { } } } + +// tests that Len is affected by reads, but Size is not. +func TestReaderLenSize(t *testing.T) { + r := strings.NewReader("abc") + io.CopyN(ioutil.Discard, r, 1) + if r.Len() != 2 { + t.Errorf("Len = %d; want 2", r.Len()) + } + if r.Size() != 3 { + t.Errorf("Size = %d; want 3", r.Size()) + } +} diff --git a/libgo/go/strings/strings.go b/libgo/go/strings/strings.go index 27d384983ef..dd51dabb322 100644 --- a/libgo/go/strings/strings.go +++ b/libgo/go/strings/strings.go @@ -2,7 +2,9 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Package strings implements simple functions to manipulate strings. +// Package strings implements simple functions to manipulate UTF-8 encoded strings. +// +// For information about UTF-8 strings in Go, see https://blog.golang.org/strings. package strings import ( @@ -78,6 +80,7 @@ func hashStrRev(sep string) (uint32, uint32) { } // Count counts the number of non-overlapping instances of sep in s. +// If sep is an empty string, Count returns 1 + the number of Unicode code points in s. func Count(s, sep string) int { n := 0 // special cases @@ -125,17 +128,17 @@ func Count(s, sep string) int { return n } -// Contains returns true if substr is within s. +// Contains reports whether substr is within s. func Contains(s, substr string) bool { return Index(s, substr) >= 0 } -// ContainsAny returns true if any Unicode code points in chars are within s. +// ContainsAny reports whether any Unicode code points in chars are within s. func ContainsAny(s, chars string) bool { return IndexAny(s, chars) >= 0 } -// ContainsRune returns true if the Unicode code point r is within s. +// ContainsRune reports whether the Unicode code point r is within s. func ContainsRune(s string, r rune) bool { return IndexRune(s, r) >= 0 } @@ -184,14 +187,7 @@ func LastIndex(s, sep string) int { case n == 0: return len(s) case n == 1: - // special case worth making fast - c := sep[0] - for i := len(s) - 1; i >= 0; i-- { - if s[i] == c { - return i - } - } - return -1 + return LastIndexByte(s, sep[0]) case n == len(s): if sep == s { return 0 @@ -270,6 +266,16 @@ func LastIndexAny(s, chars string) int { return -1 } +// LastIndexByte returns the index of the last instance of c in s, or -1 if c is not present in s. +func LastIndexByte(s string, c byte) int { + for i := len(s) - 1; i >= 0; i-- { + if s[i] == c { + return i + } + } + return -1 +} + // Generic split: splits after each instance of sep, // including sepSave bytes of sep in the subarrays. func genSplit(s, sep string, sepSave, n int) []string { @@ -519,7 +525,7 @@ func isSeparator(r rune) bool { // Title returns a copy of the string s with all Unicode letters that begin words // mapped to their title case. // -// BUG: The rule Title uses for word boundaries does not handle Unicode punctuation properly. +// BUG(rsc): The rule Title uses for word boundaries does not handle Unicode punctuation properly. func Title(s string) string { // Use a closure here to remember state. // Hackish but effective. Depends on Map scanning in order and calling diff --git a/libgo/go/strings/strings_test.go b/libgo/go/strings/strings_test.go index 7bb81ef3ca1..4e21deaecde 100644 --- a/libgo/go/strings/strings_test.go +++ b/libgo/go/strings/strings_test.go @@ -120,6 +120,23 @@ func TestLastIndex(t *testing.T) { runIndexTests(t, LastIndex, "LastIndex", l func TestIndexAny(t *testing.T) { runIndexTests(t, IndexAny, "IndexAny", indexAnyTests) } func TestLastIndexAny(t *testing.T) { runIndexTests(t, LastIndexAny, "LastIndexAny", lastIndexAnyTests) } +func TestLastIndexByte(t *testing.T) { + testCases := []IndexTest{ + {"", "q", -1}, + {"abcdef", "q", -1}, + {"abcdefabcdef", "a", len("abcdef")}, // something in the middle + {"abcdefabcdef", "f", len("abcdefabcde")}, // last byte + {"zabcdefabcdef", "z", 0}, // first byte + {"a☺b☻c☹d", "b", len("a☺")}, // non-ascii + } + for _, test := range testCases { + actual := LastIndexByte(test.s, test.sep[0]) + if actual != test.out { + t.Errorf("LastIndexByte(%q,%c) = %v; want %v", test.s, test.sep[0], actual, test.out) + } + } +} + var indexRuneTests = []struct { s string rune rune @@ -569,6 +586,35 @@ func TestTrim(t *testing.T) { } } +func BenchmarkTrim(b *testing.B) { + b.ReportAllocs() + + for i := 0; i < b.N; i++ { + for _, tc := range trimTests { + name := tc.f + var f func(string, string) string + switch name { + case "Trim": + f = Trim + case "TrimLeft": + f = TrimLeft + case "TrimRight": + f = TrimRight + case "TrimPrefix": + f = TrimPrefix + case "TrimSuffix": + f = TrimSuffix + default: + b.Errorf("Undefined trim function %s", name) + } + actual := f(tc.in, tc.arg) + if actual != tc.out { + b.Errorf("%s(%q, %q) = %q; want %q", name, tc.in, tc.arg, actual, tc.out) + } + } + } +} + type predicate struct { f func(rune) bool name string diff --git a/libgo/go/sync/atomic/atomic_test.go b/libgo/go/sync/atomic/atomic_test.go index eaa3b6b5c98..6dae0fd8e72 100644 --- a/libgo/go/sync/atomic/atomic_test.go +++ b/libgo/go/sync/atomic/atomic_test.go @@ -164,7 +164,7 @@ func TestSwapPointer(t *testing.T) { x.before = magicptr x.after = magicptr var j uintptr - for delta := uintptr(1); delta+delta > delta; delta += delta { + for delta := uintptr(1 << 16); delta+delta > delta; delta += delta { k := SwapPointer(&x.i, unsafe.Pointer(delta)) if uintptr(x.i) != delta || uintptr(k) != j { t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i, j, k) @@ -456,7 +456,7 @@ func TestCompareAndSwapPointer(t *testing.T) { magicptr := uintptr(m) x.before = magicptr x.after = magicptr - for val := uintptr(1); val+val > val; val += val { + for val := uintptr(1 << 16); val+val > val; val += val { x.i = unsafe.Pointer(val) if !CompareAndSwapPointer(&x.i, unsafe.Pointer(val), unsafe.Pointer(val+1)) { t.Fatalf("should have swapped %#x %#x", val, val+1) @@ -595,7 +595,7 @@ func TestLoadPointer(t *testing.T) { magicptr := uintptr(m) x.before = magicptr x.after = magicptr - for delta := uintptr(1); delta+delta > delta; delta += delta { + for delta := uintptr(1 << 16); delta+delta > delta; delta += delta { k := LoadPointer(&x.i) if k != x.i { t.Fatalf("delta=%d i=%d k=%d", delta, x.i, k) @@ -731,7 +731,7 @@ func TestStorePointer(t *testing.T) { x.before = magicptr x.after = magicptr v := unsafe.Pointer(uintptr(0)) - for delta := uintptr(1); delta+delta > delta; delta += delta { + for delta := uintptr(1 << 16); delta+delta > delta; delta += delta { StorePointer(&x.i, unsafe.Pointer(v)) if x.i != v { t.Fatalf("delta=%d i=%d v=%d", delta, x.i, v) @@ -759,14 +759,12 @@ var hammer32 = map[string]func(*uint32, int){ "SwapInt32": hammerSwapInt32, "SwapUint32": hammerSwapUint32, "SwapUintptr": hammerSwapUintptr32, - "SwapPointer": hammerSwapPointer32, "AddInt32": hammerAddInt32, "AddUint32": hammerAddUint32, "AddUintptr": hammerAddUintptr32, "CompareAndSwapInt32": hammerCompareAndSwapInt32, "CompareAndSwapUint32": hammerCompareAndSwapUint32, "CompareAndSwapUintptr": hammerCompareAndSwapUintptr32, - "CompareAndSwapPointer": hammerCompareAndSwapPointer32, } func init() { @@ -818,20 +816,6 @@ func hammerSwapUintptr32(uaddr *uint32, count int) { } } -func hammerSwapPointer32(uaddr *uint32, count int) { - // only safe when uintptr is 32-bit. - // not called on 64-bit systems. - addr := (*unsafe.Pointer)(unsafe.Pointer(uaddr)) - seed := int(uintptr(unsafe.Pointer(&count))) - for i := 0; i < count; i++ { - new := uintptr(seed+i)<<16 | uintptr(seed+i)<<16>>16 - old := uintptr(SwapPointer(addr, unsafe.Pointer(new))) - if old>>16 != old<<16>>16 { - panic(fmt.Sprintf("SwapPointer is not atomic: %#08x", old)) - } - } -} - func hammerAddInt32(uaddr *uint32, count int) { addr := (*int32)(unsafe.Pointer(uaddr)) for i := 0; i < count; i++ { @@ -891,20 +875,6 @@ func hammerCompareAndSwapUintptr32(uaddr *uint32, count int) { } } -func hammerCompareAndSwapPointer32(uaddr *uint32, count int) { - // only safe when uintptr is 32-bit. - // not called on 64-bit systems. - addr := (*unsafe.Pointer)(unsafe.Pointer(uaddr)) - for i := 0; i < count; i++ { - for { - v := LoadPointer(addr) - if CompareAndSwapPointer(addr, v, unsafe.Pointer(uintptr(v)+1)) { - break - } - } - } -} - func TestHammer32(t *testing.T) { const p = 4 n := 100000 @@ -940,14 +910,12 @@ var hammer64 = map[string]func(*uint64, int){ "SwapInt64": hammerSwapInt64, "SwapUint64": hammerSwapUint64, "SwapUintptr": hammerSwapUintptr64, - "SwapPointer": hammerSwapPointer64, "AddInt64": hammerAddInt64, "AddUint64": hammerAddUint64, "AddUintptr": hammerAddUintptr64, "CompareAndSwapInt64": hammerCompareAndSwapInt64, "CompareAndSwapUint64": hammerCompareAndSwapUint64, "CompareAndSwapUintptr": hammerCompareAndSwapUintptr64, - "CompareAndSwapPointer": hammerCompareAndSwapPointer64, } func init() { @@ -999,20 +967,6 @@ func hammerSwapUintptr64(uaddr *uint64, count int) { } } -func hammerSwapPointer64(uaddr *uint64, count int) { - // only safe when uintptr is 64-bit. - // not called on 32-bit systems. - addr := (*unsafe.Pointer)(unsafe.Pointer(uaddr)) - seed := int(uintptr(unsafe.Pointer(&count))) - for i := 0; i < count; i++ { - new := uintptr(seed+i)<<32 | uintptr(seed+i)<<32>>32 - old := uintptr(SwapPointer(addr, unsafe.Pointer(new))) - if old>>32 != old<<32>>32 { - panic(fmt.Sprintf("SwapPointer is not atomic: %v", old)) - } - } -} - func hammerAddInt64(uaddr *uint64, count int) { addr := (*int64)(unsafe.Pointer(uaddr)) for i := 0; i < count; i++ { @@ -1072,20 +1026,6 @@ func hammerCompareAndSwapUintptr64(uaddr *uint64, count int) { } } -func hammerCompareAndSwapPointer64(uaddr *uint64, count int) { - // only safe when uintptr is 64-bit. - // not called on 32-bit systems. - addr := (*unsafe.Pointer)(unsafe.Pointer(uaddr)) - for i := 0; i < count; i++ { - for { - v := LoadPointer(addr) - if CompareAndSwapPointer(addr, v, unsafe.Pointer(uintptr(v)+1)) { - break - } - } - } -} - func TestHammer64(t *testing.T) { if test64err != nil { t.Skipf("Skipping 64-bit tests: %v", test64err) @@ -1465,9 +1405,6 @@ func TestUnaligned64(t *testing.T) { } func TestNilDeref(t *testing.T) { - if p := runtime.GOOS + "/" + runtime.GOARCH; p == "freebsd/arm" || p == "netbsd/arm" { - t.Skipf("issue 7338: skipping test on %q", p) - } funcs := [...]func(){ func() { CompareAndSwapInt32(nil, 0, 0) }, func() { CompareAndSwapInt64(nil, 0, 0) }, diff --git a/libgo/go/sync/export_test.go b/libgo/go/sync/export_test.go index fa5983a2d1e..6f49b3bd8a8 100644 --- a/libgo/go/sync/export_test.go +++ b/libgo/go/sync/export_test.go @@ -7,3 +7,5 @@ package sync // Export for testing. var Runtime_Semacquire = runtime_Semacquire var Runtime_Semrelease = runtime_Semrelease + +const RaceEnabled = raceenabled diff --git a/libgo/go/sync/mutex.go b/libgo/go/sync/mutex.go index 73b33770222..3f280ad719d 100644 --- a/libgo/go/sync/mutex.go +++ b/libgo/go/sync/mutex.go @@ -48,15 +48,31 @@ func (m *Mutex) Lock() { } awoke := false + iter := 0 for { old := m.state new := old | mutexLocked if old&mutexLocked != 0 { + if runtime_canSpin(iter) { + // Active spinning makes sense. + // Try to set mutexWoken flag to inform Unlock + // to not wake other blocked goroutines. + if !awoke && old&mutexWoken == 0 && old>>mutexWaiterShift != 0 && + atomic.CompareAndSwapInt32(&m.state, old, old|mutexWoken) { + awoke = true + } + runtime_doSpin() + iter++ + continue + } new = old + 1<> 32) + w := uint32(state) if raceenabled { if delta > 0 && v == int32(delta) { // The first increment must be synchronized with Wait. @@ -66,18 +69,25 @@ func (wg *WaitGroup) Add(delta int) { if v < 0 { panic("sync: negative WaitGroup counter") } - if v > 0 || atomic.LoadInt32(&wg.waiters) == 0 { + if w != 0 && delta > 0 && v == int32(delta) { + panic("sync: WaitGroup misuse: Add called concurrently with Wait") + } + if v > 0 || w == 0 { return } - wg.m.Lock() - if atomic.LoadInt32(&wg.counter) == 0 { - for i := int32(0); i < wg.waiters; i++ { - runtime_Semrelease(wg.sema) - } - wg.waiters = 0 - wg.sema = nil + // This goroutine has set counter to 0 when waiters > 0. + // Now there can't be concurrent mutations of state: + // - Adds must not happen concurrently with Wait, + // - Wait does not increment waiters if it sees counter == 0. + // Still do a cheap sanity check to detect WaitGroup misuse. + if *statep != state { + panic("sync: WaitGroup misuse: Add called concurrently with Wait") + } + // Reset waiters count to 0. + *statep = 0 + for ; w != 0; w-- { + runtime_Semrelease(&wg.sema) } - wg.m.Unlock() } // Done decrements the WaitGroup counter. @@ -87,51 +97,41 @@ func (wg *WaitGroup) Done() { // Wait blocks until the WaitGroup counter is zero. func (wg *WaitGroup) Wait() { + statep := wg.state() if raceenabled { - _ = wg.m.state // trigger nil deref early + _ = *statep // trigger nil deref early raceDisable() } - if atomic.LoadInt32(&wg.counter) == 0 { - if raceenabled { - raceEnable() - raceAcquire(unsafe.Pointer(wg)) - } - return - } - wg.m.Lock() - w := atomic.AddInt32(&wg.waiters, 1) - // This code is racing with the unlocked path in Add above. - // The code above modifies counter and then reads waiters. - // We must modify waiters and then read counter (the opposite order) - // to avoid missing an Add. - if atomic.LoadInt32(&wg.counter) == 0 { - atomic.AddInt32(&wg.waiters, -1) - if raceenabled { - raceEnable() - raceAcquire(unsafe.Pointer(wg)) - raceDisable() + for { + state := atomic.LoadUint64(statep) + v := int32(state >> 32) + w := uint32(state) + if v == 0 { + // Counter is 0, no need to wait. + if raceenabled { + raceEnable() + raceAcquire(unsafe.Pointer(wg)) + } + return } - wg.m.Unlock() - if raceenabled { - raceEnable() + // Increment waiters count. + if atomic.CompareAndSwapUint64(statep, state, state+1) { + if raceenabled && w == 0 { + // Wait must be synchronized with the first Add. + // Need to model this is as a write to race with the read in Add. + // As a consequence, can do the write only for the first waiter, + // otherwise concurrent Waits will race with each other. + raceWrite(unsafe.Pointer(&wg.sema)) + } + runtime_Semacquire(&wg.sema) + if *statep != 0 { + panic("sync: WaitGroup is reused before previous Wait has returned") + } + if raceenabled { + raceEnable() + raceAcquire(unsafe.Pointer(wg)) + } + return } - return - } - if raceenabled && w == 1 { - // Wait must be synchronized with the first Add. - // Need to model this is as a write to race with the read in Add. - // As a consequence, can do the write only for the first waiter, - // otherwise concurrent Waits will race with each other. - raceWrite(unsafe.Pointer(&wg.sema)) - } - if wg.sema == nil { - wg.sema = new(uint32) - } - s := wg.sema - wg.m.Unlock() - runtime_Semacquire(s) - if raceenabled { - raceEnable() - raceAcquire(unsafe.Pointer(wg)) } } diff --git a/libgo/go/sync/waitgroup_test.go b/libgo/go/sync/waitgroup_test.go index 4c0a043c01e..3e3e3bf8243 100644 --- a/libgo/go/sync/waitgroup_test.go +++ b/libgo/go/sync/waitgroup_test.go @@ -5,6 +5,7 @@ package sync_test import ( + "runtime" . "sync" "sync/atomic" "testing" @@ -46,6 +47,12 @@ func TestWaitGroup(t *testing.T) { } } +func knownRacy(t *testing.T) { + if RaceEnabled { + t.Skip("skipping known-racy test under the race detector") + } +} + func TestWaitGroupMisuse(t *testing.T) { defer func() { err := recover() @@ -60,6 +67,95 @@ func TestWaitGroupMisuse(t *testing.T) { t.Fatal("Should panic") } +func TestWaitGroupMisuse2(t *testing.T) { + knownRacy(t) + if testing.Short() { + t.Skip("skipping flaky test in short mode; see issue 11443") + } + if runtime.NumCPU() <= 2 { + t.Skip("NumCPU<=2, skipping: this test requires parallelism") + } + defer func() { + err := recover() + if err != "sync: negative WaitGroup counter" && + err != "sync: WaitGroup misuse: Add called concurrently with Wait" && + err != "sync: WaitGroup is reused before previous Wait has returned" { + t.Fatalf("Unexpected panic: %#v", err) + } + }() + defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4)) + done := make(chan interface{}, 2) + // The detection is opportunistically, so we want it to panic + // at least in one run out of a million. + for i := 0; i < 1e6; i++ { + var wg WaitGroup + wg.Add(1) + go func() { + defer func() { + done <- recover() + }() + wg.Wait() + }() + go func() { + defer func() { + done <- recover() + }() + wg.Add(1) // This is the bad guy. + wg.Done() + }() + wg.Done() + for j := 0; j < 2; j++ { + if err := <-done; err != nil { + panic(err) + } + } + } + t.Fatal("Should panic") +} + +func TestWaitGroupMisuse3(t *testing.T) { + knownRacy(t) + if runtime.NumCPU() <= 1 { + t.Skip("NumCPU==1, skipping: this test requires parallelism") + } + defer func() { + err := recover() + if err != "sync: negative WaitGroup counter" && + err != "sync: WaitGroup misuse: Add called concurrently with Wait" && + err != "sync: WaitGroup is reused before previous Wait has returned" { + t.Fatalf("Unexpected panic: %#v", err) + } + }() + defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4)) + done := make(chan interface{}, 1) + // The detection is opportunistically, so we want it to panic + // at least in one run out of a million. + for i := 0; i < 1e6; i++ { + var wg WaitGroup + wg.Add(1) + go func() { + wg.Done() + }() + go func() { + defer func() { + done <- recover() + }() + wg.Wait() + // Start reusing the wg before waiting for the Wait below to return. + wg.Add(1) + go func() { + wg.Done() + }() + wg.Wait() + }() + wg.Wait() + if err := <-done; err != nil { + panic(err) + } + } + t.Fatal("Should panic") +} + func TestWaitGroupRace(t *testing.T) { // Run this test for about 1ms. for i := 0; i < 1000; i++ { @@ -85,6 +181,19 @@ func TestWaitGroupRace(t *testing.T) { } } +func TestWaitGroupAlign(t *testing.T) { + type X struct { + x byte + wg WaitGroup + } + var x X + x.wg.Add(1) + go func(x *X) { + x.wg.Done() + }(&x) + x.wg.Wait() +} + func BenchmarkWaitGroupUncontended(b *testing.B) { type PaddedWaitGroup struct { WaitGroup @@ -146,3 +255,17 @@ func BenchmarkWaitGroupWait(b *testing.B) { func BenchmarkWaitGroupWaitWork(b *testing.B) { benchmarkWaitGroupWait(b, 100) } + +func BenchmarkWaitGroupActuallyWait(b *testing.B) { + b.ReportAllocs() + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + var wg WaitGroup + wg.Add(1) + go func() { + wg.Done() + }() + wg.Wait() + } + }) +} diff --git a/libgo/go/syscall/const_plan9.go b/libgo/go/syscall/const_plan9.go new file mode 100644 index 00000000000..ba26f123dea --- /dev/null +++ b/libgo/go/syscall/const_plan9.go @@ -0,0 +1,59 @@ +package syscall + +// Plan 9 Constants + +// Open modes +const ( + O_RDONLY = 0 + O_WRONLY = 1 + O_RDWR = 2 + O_TRUNC = 16 + O_CLOEXEC = 32 + O_EXCL = 0x1000 +) + +// Rfork flags +const ( + RFNAMEG = 1 << 0 + RFENVG = 1 << 1 + RFFDG = 1 << 2 + RFNOTEG = 1 << 3 + RFPROC = 1 << 4 + RFMEM = 1 << 5 + RFNOWAIT = 1 << 6 + RFCNAMEG = 1 << 10 + RFCENVG = 1 << 11 + RFCFDG = 1 << 12 + RFREND = 1 << 13 + RFNOMNT = 1 << 14 +) + +// Qid.Type bits +const ( + QTDIR = 0x80 + QTAPPEND = 0x40 + QTEXCL = 0x20 + QTMOUNT = 0x10 + QTAUTH = 0x08 + QTTMP = 0x04 + QTFILE = 0x00 +) + +// Dir.Mode bits +const ( + DMDIR = 0x80000000 + DMAPPEND = 0x40000000 + DMEXCL = 0x20000000 + DMMOUNT = 0x10000000 + DMAUTH = 0x08000000 + DMTMP = 0x04000000 + DMREAD = 0x4 + DMWRITE = 0x2 + DMEXEC = 0x1 +) + +const ( + STATMAX = 65535 + ERRMAX = 128 + STATFIXLEN = 49 +) diff --git a/libgo/go/syscall/creds_test.go b/libgo/go/syscall/creds_test.go index b1894c66b07..b4a14ff4dd9 100644 --- a/libgo/go/syscall/creds_test.go +++ b/libgo/go/syscall/creds_test.go @@ -56,7 +56,13 @@ func TestSCMCredentials(t *testing.T) { ucred.Gid = 0 oob := syscall.UnixCredentials(&ucred) _, _, err := cli.(*net.UnixConn).WriteMsgUnix(nil, oob, nil) - if err.(*net.OpError).Err != syscall.EPERM { + if op, ok := err.(*net.OpError); ok { + err = op.Err + } + if sys, ok := err.(*os.SyscallError); ok { + err = sys.Err + } + if err != syscall.EPERM { t.Fatalf("WriteMsgUnix failed with %v, want EPERM", err) } } diff --git a/libgo/go/syscall/env_plan9.go b/libgo/go/syscall/env_plan9.go index 9ea36c886ab..cbf7f410925 100644 --- a/libgo/go/syscall/env_plan9.go +++ b/libgo/go/syscall/env_plan9.go @@ -16,7 +16,7 @@ var ( ) func readenv(key string) (string, error) { - fd, err := Open("/env/"+key, O_RDONLY) + fd, err := open("/env/"+key, O_RDONLY) if err != nil { return "", err } @@ -35,7 +35,7 @@ func readenv(key string) (string, error) { } func writeenv(key, value string) error { - fd, err := Create("/env/"+key, O_RDWR, 0666) + fd, err := create("/env/"+key, O_RDWR, 0666) if err != nil { return err } @@ -86,7 +86,7 @@ func Unsetenv(key string) error { } func Environ() []string { - fd, err := Open("/env", O_RDONLY) + fd, err := open("/env", O_RDONLY) if err != nil { return nil } diff --git a/libgo/go/syscall/env_windows.go b/libgo/go/syscall/env_windows.go index bc21690d9fd..1cb475428d7 100644 --- a/libgo/go/syscall/env_windows.go +++ b/libgo/go/syscall/env_windows.go @@ -16,19 +16,17 @@ func Getenv(key string) (value string, found bool) { if err != nil { return "", false } - b := make([]uint16, 100) - n, e := GetEnvironmentVariable(keyp, &b[0], uint32(len(b))) - if n == 0 && e == ERROR_ENVVAR_NOT_FOUND { - return "", false - } - if n > uint32(len(b)) { - b = make([]uint16, n) - n, e = GetEnvironmentVariable(keyp, &b[0], uint32(len(b))) - if n > uint32(len(b)) { - n = 0 + n := uint32(100) + for { + b := make([]uint16, n) + n, err = GetEnvironmentVariable(keyp, &b[0], uint32(len(b))) + if n == 0 && err == ERROR_ENVVAR_NOT_FOUND { + return "", false + } + if n <= uint32(len(b)) { + return string(utf16.Decode(b[:n])), true } } - return string(utf16.Decode(b[0:n])), true } func Setenv(key, value string) error { diff --git a/libgo/go/syscall/errors_plan9.go b/libgo/go/syscall/errors_plan9.go new file mode 100644 index 00000000000..ede3d6a329e --- /dev/null +++ b/libgo/go/syscall/errors_plan9.go @@ -0,0 +1,48 @@ +// 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 syscall + +// Constants +const ( + // Invented values to support what package os expects. + O_CREAT = 0x02000 + O_APPEND = 0x00400 + O_NOCTTY = 0x00000 + O_NONBLOCK = 0x00000 + O_SYNC = 0x00000 + O_ASYNC = 0x00000 + + S_IFMT = 0x1f000 + S_IFIFO = 0x1000 + S_IFCHR = 0x2000 + S_IFDIR = 0x4000 + S_IFBLK = 0x6000 + S_IFREG = 0x8000 + S_IFLNK = 0xa000 + S_IFSOCK = 0xc000 +) + +// Errors +var ( + EINVAL = NewError("bad arg in system call") + ENOTDIR = NewError("not a directory") + EISDIR = NewError("file is a directory") + ENOENT = NewError("file does not exist") + EEXIST = NewError("file already exists") + EMFILE = NewError("no free file descriptors") + EIO = NewError("i/o error") + ENAMETOOLONG = NewError("file name too long") + EINTR = NewError("interrupted") + EPERM = NewError("permission denied") + EBUSY = NewError("no free devices") + ETIMEDOUT = NewError("connection timed out") + EPLAN9 = NewError("not supported by plan 9") + + // The following errors do not correspond to any + // Plan 9 system messages. Invented to support + // what package os and others expect. + EACCES = NewError("access permission denied") + EAFNOSUPPORT = NewError("address family not supported by protocol") +) diff --git a/libgo/go/syscall/exec_bsd.go b/libgo/go/syscall/exec_bsd.go index 217e0c842df..f44e897f39b 100644 --- a/libgo/go/syscall/exec_bsd.go +++ b/libgo/go/syscall/exec_bsd.go @@ -15,9 +15,12 @@ type SysProcAttr struct { Credential *Credential // Credential. Ptrace bool // Enable tracing. Setsid bool // Create session. - Setpgid bool // Set process group ID to new pid (SYSV setpgrp) - Setctty bool // Set controlling terminal to fd 0 + Setpgid bool // Set process group ID to Pgid, or, if Pgid == 0, to new pid. + Setctty bool // Set controlling terminal to fd Ctty Noctty bool // Detach fd 0 from controlling terminal + Ctty int // Controlling TTY fd + Foreground bool // Place child's process group in foreground. (Implies Setpgid. Uses Ctty as fd of controlling TTY) + Pgid int // Child's process group ID if Setpgid. } // Implemented in runtime package. @@ -90,8 +93,24 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr } // Set process group - if sys.Setpgid { - err1 = raw_setpgid(0, 0) + if sys.Setpgid || sys.Foreground { + // Place child in process group. + err1 = raw_setpgid(0, sys.Pgid) + if err1 != 0 { + goto childerror + } + } + + if sys.Foreground { + pgrp := sys.Pgid + if pgrp == 0 { + r1 = raw_getpid() + + pgrp = int(r1) + } + + // Place process group in foreground. + _, err1 = raw_ioctl_ptr(sys.Ctty, TIOCSPGRP, unsafe.Pointer(&pgrp)) if err1 != 0 { goto childerror } @@ -215,9 +234,9 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr } } - // Make fd 0 the tty + // Set the controlling TTY to Ctty if sys.Setctty { - _, err1 = raw_ioctl(0, TIOCSCTTY, 0) + _, err1 = raw_ioctl(sys.Ctty, TIOCSCTTY, 0) if err1 != 0 { goto childerror } diff --git a/libgo/go/syscall/exec_linux.go b/libgo/go/syscall/exec_linux.go index 97bde0c4f52..d9600a142ae 100644 --- a/libgo/go/syscall/exec_linux.go +++ b/libgo/go/syscall/exec_linux.go @@ -27,14 +27,21 @@ type SysProcAttr struct { Credential *Credential // Credential. Ptrace bool // Enable tracing. Setsid bool // Create session. - Setpgid bool // Set process group ID to new pid (SYSV setpgrp) + Setpgid bool // Set process group ID to Pgid, or, if Pgid == 0, to new pid. Setctty bool // Set controlling terminal to fd Ctty (only meaningful if Setsid is set) Noctty bool // Detach fd 0 from controlling terminal - Ctty int // Controlling TTY fd (Linux only) + Ctty int // Controlling TTY fd + Foreground bool // Place child's process group in foreground. (Implies Setpgid. Uses Ctty as fd of controlling TTY) + Pgid int // Child's process group ID if Setpgid. Pdeathsig Signal // Signal that the process will get when its parent dies (Linux only) Cloneflags uintptr // Flags for clone calls (Linux only) UidMappings []SysProcIDMap // User ID mappings for user namespaces. GidMappings []SysProcIDMap // Group ID mappings for user namespaces. + // GidMappingsEnableSetgroups enabling setgroups syscall. + // If false, then setgroups syscall will be disabled for the child process. + // This parameter is no-op if GidMappings == nil. Otherwise for unprivileged + // users this should be set to false for mappings work. + GidMappingsEnableSetgroups bool } // Implemented in runtime package. @@ -62,6 +69,9 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr p [2]int ) + // Record parent PID so child can test if it has died. + ppid := raw_getpid() + // Guard against side effects of shuffling fds below. // Make sure that nextfd is beyond any currently open files so // that we can't run the risk of overwriting any of them. @@ -135,27 +145,6 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr } } - // Parent death signal - if sys.Pdeathsig != 0 { - _, err1 = raw_prctl(PR_SET_PDEATHSIG, int(sys.Pdeathsig), 0, 0, 0) - if err1 != 0 { - goto childerror - } - - // Signal self if parent is already dead. This might cause a - // duplicate signal in rare cases, but it won't matter when - // using SIGKILL. - ppid := Getppid() - if ppid == 1 { - pid = Getpid() - err2 := Kill(pid, sys.Pdeathsig) - if err2 != nil { - err1 = err2.(Errno) - goto childerror - } - } - } - // Enable tracing if requested. if sys.Ptrace { err1 = raw_ptrace(_PTRACE_TRACEME, 0, nil, nil) @@ -173,8 +162,27 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr } // Set process group - if sys.Setpgid { - err1 = raw_setpgid(0, 0) + if sys.Setpgid || sys.Foreground { + // Place child in process group. + err1 = raw_setpgid(0, sys.Pgid) + if err1 != 0 { + goto childerror + } + } + + if sys.Foreground { + pgrp := int32(sys.Pgid) + if pgrp == 0 { + r1 = uintptr(raw_getpid()) + if err1 != 0 { + goto childerror + } + + pgrp = int32(r1) + } + + // Place process group in foreground. + _, err1 = raw_ioctl_ptr(sys.Ctty, TIOCSPGRP, unsafe.Pointer(&pgrp)) if err1 != 0 { goto childerror } @@ -191,36 +199,19 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr // User and groups if cred := sys.Credential; cred != nil { ngroups := len(cred.Groups) - if ngroups == 0 { - err2 := setgroups(0, nil) - if err2 == nil { - err1 = 0 - } else { - err1 = err2.(Errno) - } - } else { - groups := make([]Gid_t, ngroups) - for i, v := range cred.Groups { - groups[i] = Gid_t(v) - } - err2 := setgroups(ngroups, &groups[0]) - if err2 == nil { - err1 = 0 - } else { - err1 = err2.(Errno) + if ngroups > 0 { + groups := unsafe.Pointer(&cred.Groups[0]) + err1 = raw_setgroups(ngroups, groups) + if err1 != 0 { + goto childerror } } + err1 = raw_setgid(int(cred.Gid)) if err1 != 0 { goto childerror } - err2 := Setgid(int(cred.Gid)) - if err2 != nil { - err1 = err2.(Errno) - goto childerror - } - err2 = Setuid(int(cred.Uid)) - if err2 != nil { - err1 = err2.(Errno) + err1 = raw_setuid(int(cred.Uid)) + if err1 != 0 { goto childerror } } @@ -233,6 +224,26 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr } } + // Parent death signal + if sys.Pdeathsig != 0 { + _, err1 = raw_prctl(PR_SET_PDEATHSIG, int(sys.Pdeathsig), 0, 0, 0) + if err1 != 0 { + goto childerror + } + + // Signal self if parent is already dead. This might cause a + // duplicate signal in rare cases, but it won't matter when + // using SIGKILL. + r1 := raw_getppid() + if r1 != ppid { + pid = raw_getpid() + err1 = raw_kill(pid, sys.Pdeathsig) + if err1 != 0 { + goto childerror + } + } + } + // Pass 1: look for fd[i] < i and move those up above len(fd) // so that pass 2 won't stomp on an fd it needs later. if pipe < nextfd { @@ -298,9 +309,9 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr } } - // Make fd 0 the tty - if sys.Setctty && sys.Ctty >= 0 { - _, err1 = raw_ioctl(0, TIOCSCTTY, sys.Ctty) + // Set the controlling TTY to Ctty + if sys.Setctty { + _, err1 = raw_ioctl(sys.Ctty, TIOCSCTTY, 0) if err1 != 0 { goto childerror } @@ -364,6 +375,32 @@ func writeIDMappings(path string, idMap []SysProcIDMap) error { return nil } +// writeSetgroups writes to /proc/PID/setgroups "deny" if enable is false +// and "allow" if enable is true. +// This is needed since kernel 3.19, because you can't write gid_map without +// disabling setgroups() system call. +func writeSetgroups(pid int, enable bool) error { + sgf := "/proc/" + itoa(pid) + "/setgroups" + fd, err := Open(sgf, O_RDWR, 0) + if err != nil { + return err + } + + var data []byte + if enable { + data = []byte("allow") + } else { + data = []byte("deny") + } + + if _, err := Write(fd, data); err != nil { + Close(fd) + return err + } + + return Close(fd) +} + // writeUidGidMappings writes User ID and Group ID mappings for user namespaces // for a process and it is called from the parent process. func writeUidGidMappings(pid int, sys *SysProcAttr) error { @@ -375,6 +412,10 @@ func writeUidGidMappings(pid int, sys *SysProcAttr) error { } if sys.GidMappings != nil { + // If the kernel is too old to support /proc/PID/setgroups, writeSetGroups will return ENOENT; this is OK. + if err := writeSetgroups(pid, sys.GidMappingsEnableSetgroups); err != nil && err != ENOENT { + return err + } gidf := "/proc/" + itoa(pid) + "/gid_map" if err := writeIDMappings(gidf, sys.GidMappings); err != nil { return err diff --git a/libgo/go/syscall/exec_linux_test.go b/libgo/go/syscall/exec_linux_test.go new file mode 100644 index 00000000000..60d2734f66a --- /dev/null +++ b/libgo/go/syscall/exec_linux_test.go @@ -0,0 +1,111 @@ +// Copyright 2015 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 linux + +package syscall_test + +import ( + "io/ioutil" + "os" + "os/exec" + "regexp" + "strconv" + "strings" + "syscall" + "testing" +) + +func whoamiCmd(t *testing.T, uid, gid int, setgroups bool) *exec.Cmd { + if _, err := os.Stat("/proc/self/ns/user"); err != nil { + if os.IsNotExist(err) { + t.Skip("kernel doesn't support user namespaces") + } + t.Fatalf("Failed to stat /proc/self/ns/user: %v", err) + } + cmd := exec.Command("whoami") + cmd.SysProcAttr = &syscall.SysProcAttr{ + Cloneflags: syscall.CLONE_NEWUSER, + UidMappings: []syscall.SysProcIDMap{ + {ContainerID: 0, HostID: uid, Size: 1}, + }, + GidMappings: []syscall.SysProcIDMap{ + {ContainerID: 0, HostID: gid, Size: 1}, + }, + GidMappingsEnableSetgroups: setgroups, + } + return cmd +} + +func testNEWUSERRemap(t *testing.T, uid, gid int, setgroups bool) { + cmd := whoamiCmd(t, uid, gid, setgroups) + out, err := cmd.CombinedOutput() + if err != nil { + // On some systems, there is a sysctl setting. + if os.IsPermission(err) && os.Getuid() != 0 { + data, errRead := ioutil.ReadFile("/proc/sys/kernel/unprivileged_userns_clone") + if errRead == nil && data[0] == '0' { + t.Skip("kernel prohibits user namespace in unprivileged process") + } + } + + t.Fatalf("Cmd failed with err %v, output: %s", err, out) + } + sout := strings.TrimSpace(string(out)) + want := "root" + if sout != want { + t.Fatalf("whoami = %q; want %q", out, want) + } +} + +func TestCloneNEWUSERAndRemapRootDisableSetgroups(t *testing.T) { + if os.Getuid() != 0 { + t.Skip("skipping root only test") + } + testNEWUSERRemap(t, 0, 0, false) +} + +func TestCloneNEWUSERAndRemapRootEnableSetgroups(t *testing.T) { + if os.Getuid() != 0 { + t.Skip("skipping root only test") + } + testNEWUSERRemap(t, 0, 0, false) +} + +// kernelVersion returns the major and minor versions of the Linux +// kernel version. It calls t.Skip if it can't figure it out. +func kernelVersion(t *testing.T) (int, int) { + bytes, err := ioutil.ReadFile("/proc/version") + if err != nil { + t.Skipf("can't get kernel version: %v", err) + } + matches := regexp.MustCompile("([0-9]+).([0-9]+)").FindSubmatch(bytes) + if len(matches) < 3 { + t.Skipf("can't get kernel version from %s", bytes) + } + major, _ := strconv.Atoi(string(matches[1])) + minor, _ := strconv.Atoi(string(matches[2])) + return major, minor +} + +func TestCloneNEWUSERAndRemapNoRootDisableSetgroups(t *testing.T) { + if os.Getuid() == 0 { + t.Skip("skipping unprivileged user only test") + } + testNEWUSERRemap(t, os.Getuid(), os.Getgid(), false) +} + +func TestCloneNEWUSERAndRemapNoRootSetgroupsEnableSetgroups(t *testing.T) { + if os.Getuid() == 0 { + t.Skip("skipping unprivileged user only test") + } + cmd := whoamiCmd(t, os.Getuid(), os.Getgid(), true) + err := cmd.Run() + if err == nil { + t.Skip("probably old kernel without security fix") + } + if !os.IsPermission(err) { + t.Fatalf("Unprivileged gid_map rewriting with GidMappingsEnableSetgroups must fail") + } +} diff --git a/libgo/go/syscall/exec_solaris_test.go b/libgo/go/syscall/exec_solaris_test.go new file mode 100644 index 00000000000..6b8f1ad3837 --- /dev/null +++ b/libgo/go/syscall/exec_solaris_test.go @@ -0,0 +1,37 @@ +// Copyright 2015 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 solaris + +package syscall + +import "unsafe" + +//go:cgo_import_dynamic libc_Getpgid getpgid "libc.so" +//go:cgo_import_dynamic libc_Getpgrp getpgrp "libc.so" + +//go:linkname libc_Getpgid libc_Getpgid +//go:linkname libc_Getpgrp libc_Getpgrp + +var ( + libc_Getpgid, + libc_Getpgrp libcFunc +) + +func Getpgid(pid int) (pgid int, err error) { + r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Getpgid)), 1, uintptr(pid), 0, 0, 0, 0, 0) + pgid = int(r0) + if e1 != 0 { + err = e1 + } + return +} + +func Getpgrp() (pgrp int) { + r0, _, _ := sysvicall6(uintptr(unsafe.Pointer(&libc_Getpgrp)), 0, 0, 0, 0, 0, 0, 0) + pgrp = int(r0) + return +} + +var Ioctl = ioctl diff --git a/libgo/go/syscall/exec_unix.go b/libgo/go/syscall/exec_unix.go index a49d95bc94c..7427c57b703 100644 --- a/libgo/go/syscall/exec_unix.go +++ b/libgo/go/syscall/exec_unix.go @@ -17,6 +17,12 @@ import ( //sysnb raw_fork() (pid Pid_t, err Errno) //fork() Pid_t +//sysnb raw_getpid() (pid int) +//getpid() Pid_t + +//sysnb raw_getppid() (pid int) +//getppid() Pid_t + //sysnb raw_setsid() (err Errno) //setsid() Pid_t @@ -36,7 +42,10 @@ import ( //close(fd _C_int) _C_int //sysnb raw_ioctl(fd int, cmd int, val int) (rval int, err Errno) -//ioctl(fd _C_int, cmd _C_int, val _C_int) _C_int +//__go_ioctl(fd _C_int, cmd _C_int, val _C_int) _C_int + +//sysnb raw_ioctl_ptr(fd int, cmd int, val unsafe.Pointer) (rval int, err Errno) +//__go_ioctl_ptr(fd _C_int, cmd _C_int, val unsafe.Pointer) _C_int //sysnb raw_execve(argv0 *byte, argv **byte, envv **byte) (err Errno) //execve(argv0 *byte, argv **byte, envv **byte) _C_int @@ -50,6 +59,18 @@ import ( //sysnb raw_dup2(oldfd int, newfd int) (err Errno) //dup2(oldfd _C_int, newfd _C_int) _C_int +//sysnb raw_kill(pid int, sig Signal) (err Errno) +//kill(pid Pid_t, sig _C_int) _C_int + +//sysnb raw_setgroups(size int, list unsafe.Pointer) (err Errno) +//setgroups(size Size_t, list *Gid_t) _C_int + +//sysnb raw_setuid(uid int) (err Errno) +//setuid(uid Uid_t) _C_int + +//sysnb raw_setgid(gid int) (err Errno) +//setgid(gid Gid_t) _C_int + // Lock synchronizing creation of new file descriptors with fork. // // We want the child in a fork/exec sequence to inherit only the @@ -99,9 +120,11 @@ import ( var ForkLock sync.RWMutex -// StringSlicePtr is deprecated. Use SlicePtrFromStrings instead. -// If any string contains a NUL byte this function panics instead -// of returning an error. +// StringSlicePtr converts a slice of strings to a slice of pointers +// to NUL-terminated byte arrays. If any string contains a NUL byte +// this function panics instead of returning an error. +// +// Deprecated: Use SlicePtrFromStrings instead. func StringSlicePtr(ss []string) []*byte { bb := make([]*byte, len(ss)+1) for i := 0; i < len(ss); i++ { @@ -112,7 +135,7 @@ func StringSlicePtr(ss []string) []*byte { } // SlicePtrFromStrings converts a slice of strings to a slice of -// pointers to NUL-terminated byte slices. If any string contains +// pointers to NUL-terminated byte arrays. If any string contains // a NUL byte, it returns (nil, EINVAL). func SlicePtrFromStrings(ss []string) ([]*byte, error) { var err error diff --git a/libgo/go/syscall/exec_unix_test.go b/libgo/go/syscall/exec_unix_test.go new file mode 100644 index 00000000000..9bb95c0f395 --- /dev/null +++ b/libgo/go/syscall/exec_unix_test.go @@ -0,0 +1,215 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd linux netbsd openbsd solaris + +package syscall_test + +import ( + "internal/testenv" + "io" + "os" + "os/exec" + "os/signal" + "syscall" + "testing" + "unsafe" +) + +type command struct { + pipe io.WriteCloser + proc *exec.Cmd + test *testing.T +} + +func (c *command) Info() (pid, pgrp int) { + pid = c.proc.Process.Pid + + pgrp, err := syscall.Getpgid(pid) + if err != nil { + c.test.Fatal(err) + } + + return +} + +func (c *command) Start() { + if err := c.proc.Start(); err != nil { + c.test.Fatal(err) + } +} + +func (c *command) Stop() { + c.pipe.Close() + if err := c.proc.Wait(); err != nil { + c.test.Fatal(err) + } +} + +func create(t *testing.T) *command { + testenv.MustHaveExec(t) + + proc := exec.Command("cat") + stdin, err := proc.StdinPipe() + if err != nil { + t.Fatal(err) + } + + return &command{stdin, proc, t} +} + +func parent() (pid, pgrp int) { + return syscall.Getpid(), syscall.Getpgrp() +} + +func TestZeroSysProcAttr(t *testing.T) { + ppid, ppgrp := parent() + + cmd := create(t) + + cmd.Start() + defer cmd.Stop() + + cpid, cpgrp := cmd.Info() + + if cpid == ppid { + t.Fatalf("Parent and child have the same process ID") + } + + if cpgrp != ppgrp { + t.Fatalf("Child is not in parent's process group") + } +} + +func TestSetpgid(t *testing.T) { + ppid, ppgrp := parent() + + cmd := create(t) + + cmd.proc.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} + cmd.Start() + defer cmd.Stop() + + cpid, cpgrp := cmd.Info() + + if cpid == ppid { + t.Fatalf("Parent and child have the same process ID") + } + + if cpgrp == ppgrp { + t.Fatalf("Parent and child are in the same process group") + } + + if cpid != cpgrp { + t.Fatalf("Child's process group is not the child's process ID") + } +} + +func TestPgid(t *testing.T) { + ppid, ppgrp := parent() + + cmd1 := create(t) + + cmd1.proc.SysProcAttr = &syscall.SysProcAttr{Setpgid: true} + cmd1.Start() + defer cmd1.Stop() + + cpid1, cpgrp1 := cmd1.Info() + + if cpid1 == ppid { + t.Fatalf("Parent and child 1 have the same process ID") + } + + if cpgrp1 == ppgrp { + t.Fatalf("Parent and child 1 are in the same process group") + } + + if cpid1 != cpgrp1 { + t.Fatalf("Child 1's process group is not its process ID") + } + + cmd2 := create(t) + + cmd2.proc.SysProcAttr = &syscall.SysProcAttr{ + Setpgid: true, + Pgid: cpgrp1, + } + cmd2.Start() + defer cmd2.Stop() + + cpid2, cpgrp2 := cmd2.Info() + + if cpid2 == ppid { + t.Fatalf("Parent and child 2 have the same process ID") + } + + if cpgrp2 == ppgrp { + t.Fatalf("Parent and child 2 are in the same process group") + } + + if cpid2 == cpgrp2 { + t.Fatalf("Child 2's process group is its process ID") + } + + if cpid1 == cpid2 { + t.Fatalf("Child 1 and 2 have the same process ID") + } + + if cpgrp1 != cpgrp2 { + t.Fatalf("Child 1 and 2 are not in the same process group") + } +} + +func TestForeground(t *testing.T) { + signal.Ignore(syscall.SIGTTIN, syscall.SIGTTOU) + + tty, err := os.OpenFile("/dev/tty", os.O_RDWR, 0) + if err != nil { + t.Skipf("Can't test Foreground. Couldn't open /dev/tty: %s", err) + } + + fpgrp := 0 + + errno := syscall.Ioctl(tty.Fd(), syscall.TIOCGPGRP, uintptr(unsafe.Pointer(&fpgrp))) + if errno != 0 { + t.Fatalf("TIOCGPGRP failed with error code: %s", errno) + } + + if fpgrp == 0 { + t.Fatalf("Foreground process group is zero") + } + + ppid, ppgrp := parent() + + cmd := create(t) + + cmd.proc.SysProcAttr = &syscall.SysProcAttr{ + Ctty: int(tty.Fd()), + Foreground: true, + } + cmd.Start() + + cpid, cpgrp := cmd.Info() + + if cpid == ppid { + t.Fatalf("Parent and child have the same process ID") + } + + if cpgrp == ppgrp { + t.Fatalf("Parent and child are in the same process group") + } + + if cpid != cpgrp { + t.Fatalf("Child's process group is not the child's process ID") + } + + cmd.Stop() + + errno = syscall.Ioctl(tty.Fd(), syscall.TIOCSPGRP, uintptr(unsafe.Pointer(&fpgrp))) + if errno != 0 { + t.Fatalf("TIOCSPGRP failed with error code: %s", errno) + } + + signal.Reset() +} diff --git a/libgo/go/syscall/exec_windows.go b/libgo/go/syscall/exec_windows.go index 936aeb577bc..5a01843d2be 100644 --- a/libgo/go/syscall/exec_windows.go +++ b/libgo/go/syscall/exec_windows.go @@ -135,23 +135,17 @@ func FullPath(name string) (path string, err error) { if err != nil { return "", err } - buf := make([]uint16, 100) - n, err := GetFullPathName(p, uint32(len(buf)), &buf[0], nil) - if err != nil { - return "", err - } - if n > uint32(len(buf)) { - // Windows is asking for bigger buffer. - buf = make([]uint16, n) + n := uint32(100) + for { + buf := make([]uint16, n) n, err = GetFullPathName(p, uint32(len(buf)), &buf[0], nil) if err != nil { return "", err } - if n > uint32(len(buf)) { - return "", EINVAL + if n <= uint32(len(buf)) { + return UTF16ToString(buf[:n]), nil } } - return UTF16ToString(buf[:n]), nil } func isSlash(c uint8) bool { @@ -250,6 +244,9 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle if len(attr.Files) > 3 { return 0, 0, EWINDOWS } + if len(attr.Files) < 3 { + return 0, 0, EINVAL + } if len(attr.Dir) != 0 { // StartProcess assumes that argv0 is relative to attr.Dir, diff --git a/libgo/go/syscall/export_unix_test.go b/libgo/go/syscall/export_unix_test.go new file mode 100644 index 00000000000..b41fe2f86b3 --- /dev/null +++ b/libgo/go/syscall/export_unix_test.go @@ -0,0 +1,12 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd linux netbsd openbsd + +package syscall + +func Ioctl(fd, req, arg uintptr) (err Errno) { + _, _, err = Syscall(SYS_IOCTL, fd, req, arg) + return err +} diff --git a/libgo/go/syscall/pwd_plan9.go b/libgo/go/syscall/pwd_plan9.go new file mode 100644 index 00000000000..12486135f0d --- /dev/null +++ b/libgo/go/syscall/pwd_plan9.go @@ -0,0 +1,83 @@ +// Copyright 2015 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. + +// The working directory in Plan 9 is effectively per P, so different +// goroutines and even the same goroutine as it's rescheduled on +// different Ps can see different working directories. +// +// Instead, track a Go process-wide intent of the current working directory, +// and switch to it at important points. + +package syscall + +import "sync" + +var ( + wdmu sync.Mutex // guards following + wdSet bool + wdStr string +) + +func Fixwd() { + wdmu.Lock() + defer wdmu.Unlock() + fixwdLocked() +} + +func fixwdLocked() { + if !wdSet { + return + } + // always call chdir when getwd returns an error + wd, _ := getwd() + if wd == wdStr { + return + } + if err := chdir(wdStr); err != nil { + return + } +} + +// goroutine-specific getwd +func getwd() (wd string, err error) { + fd, err := open(".", O_RDONLY) + if err != nil { + return "", err + } + defer Close(fd) + return Fd2path(fd) +} + +func Getwd() (wd string, err error) { + wdmu.Lock() + defer wdmu.Unlock() + + if wdSet { + return wdStr, nil + } + wd, err = getwd() + if err != nil { + return + } + wdSet = true + wdStr = wd + return wd, nil +} + +func Chdir(path string) error { + wdmu.Lock() + defer wdmu.Unlock() + + if err := chdir(path); err != nil { + return err + } + + wd, err := getwd() + if err != nil { + return err + } + wdSet = true + wdStr = wd + return nil +} diff --git a/libgo/go/syscall/route_bsd.go b/libgo/go/syscall/route_bsd.go index 1dabe42531b..c62fdc3c81d 100644 --- a/libgo/go/syscall/route_bsd.go +++ b/libgo/go/syscall/route_bsd.go @@ -4,23 +4,37 @@ // +build darwin dragonfly freebsd netbsd openbsd -// Routing sockets and messages - package syscall -import "unsafe" +import ( + "runtime" + "unsafe" +) + +var ( + freebsdConfArch string // "machine $arch" line in kern.conftxt on freebsd + minRoutingSockaddrLen = rsaAlignOf(0) +) // Round the length of a raw sockaddr up to align it properly. func rsaAlignOf(salen int) int { salign := sizeofPtr - // NOTE: It seems like 64-bit Darwin kernel still requires - // 32-bit aligned access to BSD subsystem. Also NetBSD 6 - // kernel and beyond require 64-bit aligned access to routing - // facilities. if darwin64Bit { + // Darwin kernels require 32-bit aligned access to + // routing facilities. salign = 4 } else if netbsd32Bit { + // NetBSD 6 and beyond kernels require 64-bit aligned + // access to routing facilities. salign = 8 + } else if runtime.GOOS == "freebsd" { + // In the case of kern.supported_archs="amd64 i386", + // we need to know the underlying kernel's + // architecture because the alignment for routing + // facilities are set at the build time of the kernel. + if freebsdConfArch == "amd64" { + salign = 8 + } } if salen == 0 { return salign @@ -28,6 +42,134 @@ func rsaAlignOf(salen int) int { return (salen + salign - 1) & ^(salign - 1) } +// parseSockaddrLink parses b as a datalink socket address. +func parseSockaddrLink(b []byte) (*SockaddrDatalink, error) { + sa, _, err := parseLinkLayerAddr(b[4:]) + if err != nil { + return nil, err + } + rsa := (*RawSockaddrDatalink)(unsafe.Pointer(&b[0])) + sa.Len = rsa.Len + sa.Family = rsa.Family + sa.Index = rsa.Index + return sa, nil +} + +// parseLinkLayerAddr parses b as a datalink socket address in +// conventional BSD kernel form. +func parseLinkLayerAddr(b []byte) (*SockaddrDatalink, int, error) { + // The encoding looks like the following: + // +----------------------------+ + // | Type (1 octet) | + // +----------------------------+ + // | Name length (1 octet) | + // +----------------------------+ + // | Address length (1 octet) | + // +----------------------------+ + // | Selector length (1 octet) | + // +----------------------------+ + // | Data (variable) | + // +----------------------------+ + type linkLayerAddr struct { + Type byte + Nlen byte + Alen byte + Slen byte + } + lla := (*linkLayerAddr)(unsafe.Pointer(&b[0])) + l := rsaAlignOf(int(4 + lla.Nlen + lla.Alen + lla.Slen)) + if len(b) < l { + return nil, 0, EINVAL + } + b = b[4:] + sa := &SockaddrDatalink{Type: lla.Type, Nlen: lla.Nlen, Alen: lla.Alen, Slen: lla.Slen} + for i := 0; len(sa.Data) > i && i < int(lla.Nlen+lla.Alen+lla.Slen); i++ { + sa.Data[i] = int8(b[i]) + } + return sa, l, nil +} + +// parseSockaddrInet parses b as an internet socket address. +func parseSockaddrInet(b []byte, family byte) (Sockaddr, error) { + switch family { + case AF_INET: + if len(b) < SizeofSockaddrInet4 { + return nil, EINVAL + } + rsa := (*RawSockaddrAny)(unsafe.Pointer(&b[0])) + return anyToSockaddr(rsa) + case AF_INET6: + if len(b) < SizeofSockaddrInet6 { + return nil, EINVAL + } + rsa := (*RawSockaddrAny)(unsafe.Pointer(&b[0])) + return anyToSockaddr(rsa) + default: + return nil, EINVAL + } +} + +const ( + offsetofInet4 = int(unsafe.Offsetof(RawSockaddrInet4{}.Addr)) + offsetofInet6 = int(unsafe.Offsetof(RawSockaddrInet6{}.Addr)) +) + +// parseNetworkLayerAddr parses b as an internet socket address in +// conventional BSD kernel form. +func parseNetworkLayerAddr(b []byte, family byte) (Sockaddr, error) { + // The encoding looks similar to the NLRI encoding. + // +----------------------------+ + // | Length (1 octet) | + // +----------------------------+ + // | Address prefix (variable) | + // +----------------------------+ + // + // The differences between the kernel form and the NLRI + // encoding are: + // + // - The length field of the kernel form indicates the prefix + // length in bytes, not in bits + // + // - In the kernel form, zero value of the length field + // doesn't mean 0.0.0.0/0 or ::/0 + // + // - The kernel form appends leading bytes to the prefix field + // to make the tuple to be conformed with + // the routing messeage boundary + l := int(rsaAlignOf(int(b[0]))) + if len(b) < l { + return nil, EINVAL + } + // Don't reorder case expressions. + // The case expressions for IPv6 must come first. + switch { + case b[0] == SizeofSockaddrInet6: + sa := &SockaddrInet6{} + copy(sa.Addr[:], b[offsetofInet6:]) + return sa, nil + case family == AF_INET6: + sa := &SockaddrInet6{} + if l-1 < offsetofInet6 { + copy(sa.Addr[:], b[1:l]) + } else { + copy(sa.Addr[:], b[l-offsetofInet6:l]) + } + return sa, nil + case b[0] == SizeofSockaddrInet4: + sa := &SockaddrInet4{} + copy(sa.Addr[:], b[offsetofInet4:]) + return sa, nil + default: // an old fashion, AF_UNSPEC or unknown means AF_INET + sa := &SockaddrInet4{} + if l-1 < offsetofInet4 { + copy(sa.Addr[:], b[1:l]) + } else { + copy(sa.Addr[:], b[l-offsetofInet4:l]) + } + return sa, nil + } +} + // RouteRIB returns routing information base, as known as RIB, // which consists of network facility information, states and // parameters. @@ -50,7 +192,7 @@ func RouteRIB(facility, param int) ([]byte, error) { // RoutingMessage represents a routing message. type RoutingMessage interface { - sockaddr() []Sockaddr + sockaddr() ([]Sockaddr, error) } const anyMessageLen = int(unsafe.Sizeof(anyMessage{})) @@ -68,50 +210,41 @@ type RouteMessage struct { Data []byte } -const rtaRtMask = RTA_DST | RTA_GATEWAY | RTA_NETMASK | RTA_GENMASK - -func (m *RouteMessage) sockaddr() []Sockaddr { - var ( - af int - sas [4]Sockaddr - ) +func (m *RouteMessage) sockaddr() ([]Sockaddr, error) { + var sas [RTAX_MAX]Sockaddr b := m.Data[:] - for i := uint(0); i < RTAX_MAX; i++ { - if m.Header.Addrs&rtaRtMask&(1<= minRoutingSockaddrLen; i++ { + if m.Header.Addrs&(1< 0 && j < int(rsa4.Len)-int(unsafe.Offsetof(rsa4.Addr)); j++ { - sa.Addr[j] = rsa4.Addr[j] - } - sas[i] = sa - case AF_INET6: - rsa6 := (*RawSockaddrInet6)(unsafe.Pointer(&b[0])) - sa := new(SockaddrInet6) - for j := 0; rsa6.Len > 0 && j < int(rsa6.Len)-int(unsafe.Offsetof(rsa6.Addr)); j++ { - sa.Addr[j] = rsa6.Addr[j] - } - sas[i] = sa + b = b[rsaAlignOf(int(rsa.Len)):] + family = rsa.Family + default: + sa, err := parseNetworkLayerAddr(b, family) + if err != nil { + return nil, err } + sas[i] = sa + b = b[rsaAlignOf(int(b[0])):] } - b = b[rsaAlignOf(int(rsa.Len)):] } - return sas[:] + return sas[:], nil } // InterfaceMessage represents a routing message containing @@ -121,15 +254,17 @@ type InterfaceMessage struct { Data []byte } -func (m *InterfaceMessage) sockaddr() (sas []Sockaddr) { +func (m *InterfaceMessage) sockaddr() ([]Sockaddr, error) { + var sas [RTAX_MAX]Sockaddr if m.Header.Addrs&RTA_IFP == 0 { - return nil + return nil, nil } - sa, err := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(&m.Data[0]))) + sa, err := parseSockaddrLink(m.Data[:]) if err != nil { - return nil + return nil, err } - return append(sas, sa) + sas[RTAX_IFP] = sa + return sas[:], nil } // InterfaceAddrMessage represents a routing message containing @@ -139,79 +274,63 @@ type InterfaceAddrMessage struct { Data []byte } -const rtaIfaMask = RTA_IFA | RTA_NETMASK | RTA_BRD - -func (m *InterfaceAddrMessage) sockaddr() (sas []Sockaddr) { - if m.Header.Addrs&rtaIfaMask == 0 { - return nil - } +func (m *InterfaceAddrMessage) sockaddr() ([]Sockaddr, error) { + var sas [RTAX_MAX]Sockaddr b := m.Data[:] - // We still see AF_UNSPEC in socket addresses on some - // platforms. To identify each address family correctly, we - // will use the address family of RTAX_NETMASK as a preferred - // one on the 32-bit NetBSD kernel, also use the length of - // RTAX_NETMASK socket address on the FreeBSD kernel. - preferredFamily := uint8(AF_UNSPEC) - for i := uint(0); i < RTAX_MAX; i++ { + family := uint8(AF_UNSPEC) + for i := uint(0); i < RTAX_MAX && len(b) >= minRoutingSockaddrLen; i++ { if m.Header.Addrs&(1<= anyMessageLen { - msgCount++ + nmsgs++ any := (*anyMessage)(unsafe.Pointer(&b[0])) if any.Version != RTM_VERSION { b = b[any.Msglen:] continue } - msgs = append(msgs, any.toRoutingMessage(b)) + if m := any.toRoutingMessage(b); m == nil { + nskips++ + } else { + msgs = append(msgs, m) + } b = b[any.Msglen:] } // We failed to parse any of the messages - version mismatch? - if msgCount > 0 && len(msgs) == 0 { + if nmsgs != len(msgs)+nskips { return nil, EINVAL } return msgs, nil @@ -219,6 +338,10 @@ func ParseRoutingMessage(b []byte) (msgs []RoutingMessage, err error) { // ParseRoutingMessage parses msg's payload as raw sockaddrs and // returns the slice containing the Sockaddr interfaces. -func ParseRoutingSockaddr(msg RoutingMessage) (sas []Sockaddr, err error) { - return append(sas, msg.sockaddr()...), nil +func ParseRoutingSockaddr(msg RoutingMessage) ([]Sockaddr, error) { + sas, err := msg.sockaddr() + if err != nil { + return nil, err + } + return sas, nil } diff --git a/libgo/go/syscall/route_bsd_test.go b/libgo/go/syscall/route_bsd_test.go new file mode 100644 index 00000000000..8617663d43a --- /dev/null +++ b/libgo/go/syscall/route_bsd_test.go @@ -0,0 +1,225 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin dragonfly freebsd netbsd openbsd + +package syscall_test + +import ( + "fmt" + "net" + "os" + "syscall" + "testing" + "time" +) + +func TestRouteRIB(t *testing.T) { + for _, facility := range []int{syscall.NET_RT_DUMP, syscall.NET_RT_IFLIST} { + for _, param := range []int{syscall.AF_UNSPEC, syscall.AF_INET, syscall.AF_INET6} { + var err error + var b []byte + // The VM allocator wrapper functions can + // return ENOMEM easily. + for i := 0; i < 3; i++ { + b, err = syscall.RouteRIB(facility, param) + if err != nil { + time.Sleep(5 * time.Millisecond) + continue + } + break + } + if err != nil { + t.Error(facility, param, err) + continue + } + msgs, err := syscall.ParseRoutingMessage(b) + if err != nil { + t.Error(facility, param, err) + continue + } + var ipv4loopback, ipv6loopback bool + for _, m := range msgs { + flags, err := parseRoutingMessageHeader(m) + if err != nil { + t.Error(err) + continue + } + sas, err := parseRoutingSockaddrs(m) + if err != nil { + t.Error(err) + continue + } + if flags&(syscall.RTA_DST|syscall.RTA_IFA) != 0 { + sa := sas[syscall.RTAX_DST] + if sa == nil { + sa = sas[syscall.RTAX_IFA] + } + switch sa := sa.(type) { + case *syscall.SockaddrInet4: + if net.IP(sa.Addr[:]).IsLoopback() { + ipv4loopback = true + } + case *syscall.SockaddrInet6: + if net.IP(sa.Addr[:]).IsLoopback() { + ipv6loopback = true + } + } + } + t.Log(facility, param, flags, sockaddrs(sas)) + } + if param == syscall.AF_UNSPEC && len(msgs) > 0 && !ipv4loopback && !ipv6loopback { + t.Errorf("no loopback facility found: ipv4/ipv6=%v/%v, %v", ipv4loopback, ipv6loopback, len(msgs)) + continue + } + } + } +} + +func TestRouteMonitor(t *testing.T) { + if testing.Short() || os.Getuid() != 0 { + t.Skip("must be root") + } + + s, err := syscall.Socket(syscall.AF_ROUTE, syscall.SOCK_RAW, syscall.AF_UNSPEC) + if err != nil { + t.Fatal(err) + } + defer syscall.Close(s) + + tmo := time.After(30 * time.Second) + go func() { + b := make([]byte, os.Getpagesize()) + for { + n, err := syscall.Read(s, b) + if err != nil { + return + } + msgs, err := syscall.ParseRoutingMessage(b[:n]) + if err != nil { + t.Error(err) + return + } + for _, m := range msgs { + flags, err := parseRoutingMessageHeader(m) + if err != nil { + t.Error(err) + continue + } + sas, err := parseRoutingSockaddrs(m) + if err != nil { + t.Error(err) + continue + } + t.Log(flags, sockaddrs(sas)) + } + } + }() + <-tmo +} + +type addrFamily byte + +func (f addrFamily) String() string { + switch f { + case syscall.AF_UNSPEC: + return "unspec" + case syscall.AF_LINK: + return "link" + case syscall.AF_INET: + return "inet4" + case syscall.AF_INET6: + return "inet6" + default: + return fmt.Sprintf("unknown %d", f) + } +} + +type addrFlags uint32 + +var addrFlagNames = [...]string{ + "dst", + "gateway", + "netmask", + "genmask", + "ifp", + "ifa", + "author", + "brd", + "mpls1,tag,src", // sockaddr_mpls=dragonfly,netbsd, sockaddr_in/in6=openbsd + "mpls2,srcmask", // sockaddr_mpls=dragonfly, sockaddr_in/in6=openbsd + "mpls3,label", // sockaddr_mpls=dragonfly, sockaddr_rtlabel=openbsd +} + +func (f addrFlags) String() string { + var s string + for i, name := range addrFlagNames { + if f&(1<" + } + return s +} + +type sockaddrs []syscall.Sockaddr + +func (sas sockaddrs) String() string { + var s string + for _, sa := range sas { + if sa == nil { + continue + } + if len(s) > 0 { + s += " " + } + switch sa := sa.(type) { + case *syscall.SockaddrDatalink: + s += fmt.Sprintf("[%v/%v/%v t/n/a/s=%v/%v/%v/%v]", sa.Len, addrFamily(sa.Family), sa.Index, sa.Type, sa.Nlen, sa.Alen, sa.Slen) + case *syscall.SockaddrInet4: + s += fmt.Sprintf("%v", net.IP(sa.Addr[:]).To4()) + case *syscall.SockaddrInet6: + s += fmt.Sprintf("%v", net.IP(sa.Addr[:]).To16()) + } + } + if s == "" { + return "" + } + return s +} + +func (sas sockaddrs) match(flags addrFlags) error { + var f addrFlags + family := syscall.AF_UNSPEC + for i := range sas { + if sas[i] != nil { + f |= 1 << uint(i) + } + switch sas[i].(type) { + case *syscall.SockaddrInet4: + if family == syscall.AF_UNSPEC { + family = syscall.AF_INET + } + if family != syscall.AF_INET { + return fmt.Errorf("got %v; want %v", sockaddrs(sas), family) + } + case *syscall.SockaddrInet6: + if family == syscall.AF_UNSPEC { + family = syscall.AF_INET6 + } + if family != syscall.AF_INET6 { + return fmt.Errorf("got %v; want %v", sockaddrs(sas), family) + } + } + } + if f != flags { + return fmt.Errorf("got %v; want %v", f, flags) + } + return nil +} diff --git a/libgo/go/syscall/route_darwin.go b/libgo/go/syscall/route_darwin.go index ad279072305..89bca12f3e1 100644 --- a/libgo/go/syscall/route_darwin.go +++ b/libgo/go/syscall/route_darwin.go @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Routing sockets and messages for Darwin - package syscall import "unsafe" @@ -33,29 +31,37 @@ type InterfaceMulticastAddrMessage struct { Data []byte } -const rtaIfmaMask = RTA_GATEWAY | RTA_IFP | RTA_IFA - -func (m *InterfaceMulticastAddrMessage) sockaddr() (sas []Sockaddr) { - if m.Header.Addrs&rtaIfmaMask == 0 { - return nil - } +func (m *InterfaceMulticastAddrMessage) sockaddr() ([]Sockaddr, error) { + var sas [RTAX_MAX]Sockaddr b := m.Data[:] - for i := uint(0); i < RTAX_MAX; i++ { - if m.Header.Addrs&rtaIfmaMask&(1<= minRoutingSockaddrLen; i++ { + if m.Header.Addrs&(1<= minRoutingSockaddrLen; i++ { + if m.Header.Addrs&(1< len("machine") && s[:len("machine")] == "machine" { + s = s[len("machine"):] + for k := 0; k < len(s); k++ { + if s[k] == ' ' || s[k] == '\t' { + s = s[1:] + } + break + } + freebsdConfArch = s + break + } + } } func (any *anyMessage) toRoutingMessage(b []byte) RoutingMessage { switch any.Type { case RTM_ADD, RTM_DELETE, RTM_CHANGE, RTM_GET, RTM_LOSING, RTM_REDIRECT, RTM_MISS, RTM_LOCK, RTM_RESOLVE: - p := (*RouteMessage)(unsafe.Pointer(any)) - return &RouteMessage{Header: p.Header, Data: b[SizeofRtMsghdr:any.Msglen]} + return any.parseRouteMessage(b) case RTM_IFINFO: return any.parseInterfaceMessage(b) case RTM_IFANNOUNCE: @@ -41,7 +57,7 @@ type InterfaceAnnounceMessage struct { Header IfAnnounceMsghdr } -func (m *InterfaceAnnounceMessage) sockaddr() (sas []Sockaddr) { return nil } +func (m *InterfaceAnnounceMessage) sockaddr() ([]Sockaddr, error) { return nil, nil } // InterfaceMulticastAddrMessage represents a routing message // containing network interface address entries. @@ -50,29 +66,37 @@ type InterfaceMulticastAddrMessage struct { Data []byte } -const rtaIfmaMask = RTA_GATEWAY | RTA_IFP | RTA_IFA - -func (m *InterfaceMulticastAddrMessage) sockaddr() (sas []Sockaddr) { - if m.Header.Addrs&rtaIfmaMask == 0 { - return nil - } +func (m *InterfaceMulticastAddrMessage) sockaddr() ([]Sockaddr, error) { + var sas [RTAX_MAX]Sockaddr b := m.Data[:] - for i := uint(0); i < RTAX_MAX; i++ { - if m.Header.Addrs&rtaIfmaMask&(1<= minRoutingSockaddrLen; i++ { + if m.Header.Addrs&(1< 0 || err != nil { + t.Fatalf("child process: %q, %v", out, err) + } + } else { + // child + got := flock + // make sure the child lock is conflicting with the parent lock + got.Start-- + got.Len++ + if err := syscall.FcntlFlock(3, syscall.F_GETLK, &got); err != nil { + t.Fatalf("FcntlFlock(F_GETLK) failed: %v", err) + } + flock.Pid = int32(syscall.Getppid()) + // Linux kernel always set Whence to 0 + flock.Whence = 0 + if got.Type == flock.Type && got.Start == flock.Start && got.Len == flock.Len && got.Pid == flock.Pid && got.Whence == flock.Whence { + os.Exit(0) + } + t.Fatalf("FcntlFlock got %v, want %v", got, flock) } } @@ -93,6 +132,9 @@ func TestPassFD(t *testing.T) { // TODO(aram): Figure out why ReadMsgUnix is returning empty message. t.Skip("skipping test on solaris, see issue 7402") } + + testenv.MustHaveExec(t) + if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" { passFDChild() return @@ -116,11 +158,7 @@ func TestPassFD(t *testing.T) { defer readFile.Close() cmd := exec.Command(os.Args[0], "-test.run=^TestPassFD$", "--", tempDir) - cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"} - path := os.Getenv("LD_LIBRARY_PATH") - if path != "" { - cmd.Env = append(cmd.Env, "LD_LIBRARY_PATH="+path) - } + cmd.Env = append(os.Environ(), "GO_WANT_HELPER_PROCESS=1") cmd.ExtraFiles = []*os.File{writeFile} out, err := cmd.CombinedOutput() @@ -179,7 +217,7 @@ func passFDChild() { defer os.Exit(0) // Look for our fd. It should be fd 3, but we work around an fd leak - // bug here (http://golang.org/issue/2603) to let it be elsewhere. + // bug here (https://golang.org/issue/2603) to let it be elsewhere. var uc *net.UnixConn for fd := uintptr(3); fd <= 10; fd++ { f := os.NewFile(fd, "unix-conn") diff --git a/libgo/go/testing/benchmark.go b/libgo/go/testing/benchmark.go index ffd5376844a..62e696d2214 100644 --- a/libgo/go/testing/benchmark.go +++ b/libgo/go/testing/benchmark.go @@ -280,6 +280,14 @@ func (r BenchmarkResult) MemString() string { r.AllocedBytesPerOp(), r.AllocsPerOp()) } +// benchmarkName returns full name of benchmark including procs suffix. +func benchmarkName(name string, n int) string { + if n != 1 { + return fmt.Sprintf("%s-%d", name, n) + } + return name +} + // An internal function but exported because it is cross-package; part of the implementation // of the "go test" command. func RunBenchmarks(matchString func(pat, str string) (bool, error), benchmarks []InternalBenchmark) { @@ -287,15 +295,30 @@ func RunBenchmarks(matchString func(pat, str string) (bool, error), benchmarks [ if len(*matchBenchmarks) == 0 { return } + // Collect matching benchmarks and determine longest name. + maxprocs := 1 + for _, procs := range cpuList { + if procs > maxprocs { + maxprocs = procs + } + } + maxlen := 0 + var bs []InternalBenchmark for _, Benchmark := range benchmarks { matched, err := matchString(*matchBenchmarks, Benchmark.Name) if err != nil { fmt.Fprintf(os.Stderr, "testing: invalid regexp for -test.bench: %s\n", err) os.Exit(1) } - if !matched { - continue + if matched { + bs = append(bs, Benchmark) + benchName := benchmarkName(Benchmark.Name, maxprocs) + if l := len(benchName); l > maxlen { + maxlen = l + } } + } + for _, Benchmark := range bs { for _, procs := range cpuList { runtime.GOMAXPROCS(procs) b := &B{ @@ -304,11 +327,8 @@ func RunBenchmarks(matchString func(pat, str string) (bool, error), benchmarks [ }, benchmark: Benchmark, } - benchName := Benchmark.Name - if procs != 1 { - benchName = fmt.Sprintf("%s-%d", Benchmark.Name, procs) - } - fmt.Printf("%s\t", benchName) + benchName := benchmarkName(Benchmark.Name, procs) + fmt.Printf("%-*s\t", maxlen, benchName) r := b.run() if b.failed { // The output could be very long here, but probably isn't. diff --git a/libgo/go/testing/example.go b/libgo/go/testing/example.go index f5762e4db4a..30baf27030a 100644 --- a/libgo/go/testing/example.go +++ b/libgo/go/testing/example.go @@ -43,7 +43,7 @@ func RunExamples(matchString func(pat, str string) (bool, error), examples []Int func runExample(eg InternalExample) (ok bool) { if *chatty { - fmt.Printf("=== RUN: %s\n", eg.Name) + fmt.Printf("=== RUN %s\n", eg.Name) } // Capture stdout. @@ -56,8 +56,8 @@ func runExample(eg InternalExample) (ok bool) { os.Stdout = w outC := make(chan string) go func() { - buf := new(bytes.Buffer) - _, err := io.Copy(buf, r) + var buf bytes.Buffer + _, err := io.Copy(&buf, r) r.Close() if err != nil { fmt.Fprintf(os.Stderr, "testing: copying pipe: %v\n", err) diff --git a/libgo/go/testing/iotest/logger.go b/libgo/go/testing/iotest/logger.go index 1475d9b0c65..0aec15c575e 100644 --- a/libgo/go/testing/iotest/logger.go +++ b/libgo/go/testing/iotest/logger.go @@ -48,7 +48,7 @@ func (l *readLogger) Read(p []byte) (n int, err error) { // NewReadLogger returns a reader that behaves like r except // that it logs (using log.Print) each read to standard error, -// printing the prefix and the hexadecimal data written. +// printing the prefix and the hexadecimal data read. func NewReadLogger(prefix string, r io.Reader) io.Reader { return &readLogger{prefix, r} } diff --git a/libgo/go/testing/quick/quick.go b/libgo/go/testing/quick/quick.go index 909c65f788b..13c56cdf488 100644 --- a/libgo/go/testing/quick/quick.go +++ b/libgo/go/testing/quick/quick.go @@ -102,12 +102,16 @@ func Value(t reflect.Type, rand *rand.Rand) (value reflect.Value, ok bool) { v.SetMapIndex(key, value) } case reflect.Ptr: - elem, ok := Value(concrete.Elem(), rand) - if !ok { - return reflect.Value{}, false + if rand.Intn(complexSize) == 0 { + v.Set(reflect.Zero(concrete)) // Generate nil pointer. + } else { + elem, ok := Value(concrete.Elem(), rand) + if !ok { + return reflect.Value{}, false + } + v.Set(reflect.New(concrete.Elem())) + v.Elem().Set(elem) } - v.Set(reflect.New(concrete.Elem())) - v.Elem().Set(elem) case reflect.Slice: numElems := rand.Intn(complexSize) v.Set(reflect.MakeSlice(concrete, numElems, numElems)) @@ -118,6 +122,14 @@ func Value(t reflect.Type, rand *rand.Rand) (value reflect.Value, ok bool) { } v.Index(i).Set(elem) } + case reflect.Array: + for i := 0; i < v.Len(); i++ { + elem, ok := Value(concrete.Elem(), rand) + if !ok { + return reflect.Value{}, false + } + v.Index(i).Set(elem) + } case reflect.String: numChars := rand.Intn(complexSize) codePoints := make([]rune, numChars) @@ -153,7 +165,7 @@ type Config struct { Rand *rand.Rand // If non-nil, the Values function generates a slice of arbitrary // reflect.Values that are congruent with the arguments to the function - // being tested. Otherwise, the top-level Values function is used + // being tested. Otherwise, the top-level Value function is used // to generate them. Values func([]reflect.Value, *rand.Rand) } @@ -237,7 +249,7 @@ func Check(f interface{}, config *Config) (err error) { } if fType.NumOut() != 1 { - err = SetupError("function returns more than one value.") + err = SetupError("function does not return one value") return } if fType.Out(0).Kind() != reflect.Bool { diff --git a/libgo/go/testing/quick/quick_test.go b/libgo/go/testing/quick/quick_test.go index e925ba67507..c79f30ea1db 100644 --- a/libgo/go/testing/quick/quick_test.go +++ b/libgo/go/testing/quick/quick_test.go @@ -10,6 +10,12 @@ import ( "testing" ) +func fArray(a [4]byte) [4]byte { return a } + +type TestArrayAlias [4]byte + +func fArrayAlias(a TestArrayAlias) TestArrayAlias { return a } + func fBool(a bool) bool { return a } type TestBoolAlias bool @@ -76,6 +82,18 @@ type TestMapAlias map[int]int func fMapAlias(a TestMapAlias) TestMapAlias { return a } +func fPtr(a *int) *int { + if a == nil { + return nil + } + b := *a + return &b +} + +type TestPtrAlias *int + +func fPtrAlias(a TestPtrAlias) TestPtrAlias { return a } + func fSlice(a []byte) []byte { return a } type TestSliceAlias []byte @@ -135,15 +153,6 @@ type TestUintptrAlias uintptr func fUintptrAlias(a TestUintptrAlias) TestUintptrAlias { return a } -func fIntptr(a *int) *int { - b := *a - return &b -} - -type TestIntptrAlias *int - -func fIntptrAlias(a TestIntptrAlias) TestIntptrAlias { return a } - func reportError(property string, err error, t *testing.T) { if err != nil { t.Errorf("%s: %s", property, err) @@ -151,6 +160,8 @@ func reportError(property string, err error, t *testing.T) { } func TestCheckEqual(t *testing.T) { + reportError("fArray", CheckEqual(fArray, fArray, nil), t) + reportError("fArrayAlias", CheckEqual(fArrayAlias, fArrayAlias, nil), t) reportError("fBool", CheckEqual(fBool, fBool, nil), t) reportError("fBoolAlias", CheckEqual(fBoolAlias, fBoolAlias, nil), t) reportError("fFloat32", CheckEqual(fFloat32, fFloat32, nil), t) @@ -175,6 +186,8 @@ func TestCheckEqual(t *testing.T) { reportError("fInt32Alias", CheckEqual(fInt32Alias, fInt32Alias, nil), t) reportError("fMap", CheckEqual(fMap, fMap, nil), t) reportError("fMapAlias", CheckEqual(fMapAlias, fMapAlias, nil), t) + reportError("fPtr", CheckEqual(fPtr, fPtr, nil), t) + reportError("fPtrAlias", CheckEqual(fPtrAlias, fPtrAlias, nil), t) reportError("fSlice", CheckEqual(fSlice, fSlice, nil), t) reportError("fSliceAlias", CheckEqual(fSliceAlias, fSliceAlias, nil), t) reportError("fString", CheckEqual(fString, fString, nil), t) @@ -193,8 +206,6 @@ func TestCheckEqual(t *testing.T) { reportError("fUintAlias", CheckEqual(fUintAlias, fUintAlias, nil), t) reportError("fUintptr", CheckEqual(fUintptr, fUintptr, nil), t) reportError("fUintptrAlias", CheckEqual(fUintptrAlias, fUintptrAlias, nil), t) - reportError("fIntptr", CheckEqual(fIntptr, fIntptr, nil), t) - reportError("fIntptrAlias", CheckEqual(fIntptrAlias, fIntptrAlias, nil), t) } // This tests that ArbitraryValue is working by checking that all the arbitrary @@ -247,3 +258,17 @@ func TestFailure(t *testing.T) { t.Errorf("#3 Error was not a SetupError: %s", err) } } + +// The following test didn't terminate because nil pointers were not +// generated. +// Issue 8818. +func TestNilPointers(t *testing.T) { + type Recursive struct { + Next *Recursive + } + + f := func(rec Recursive) bool { + return true + } + Check(f, nil) +} diff --git a/libgo/go/testing/testing.go b/libgo/go/testing/testing.go index e54a3b8ce4d..9ec3869768c 100644 --- a/libgo/go/testing/testing.go +++ b/libgo/go/testing/testing.go @@ -34,7 +34,7 @@ // its -bench flag is provided. Benchmarks are run sequentially. // // For a description of the testing flags, see -// http://golang.org/cmd/go/#hdr-Description_of_testing_flags. +// https://golang.org/cmd/go/#hdr-Description_of_testing_flags. // // A sample benchmark function looks like this: // func BenchmarkHello(b *testing.B) { @@ -44,7 +44,7 @@ // } // // The benchmark function must run the target code b.N times. -// During benchark execution, b.N is adjusted until the benchmark function lasts +// During benchmark execution, b.N is adjusted until the benchmark function lasts // long enough to be timed reliably. The output // BenchmarkHello 10000000 282 ns/op // means that the loop ran 10000000 times at a speed of 282 ns per loop. @@ -130,13 +130,17 @@ // then the generated test will call TestMain(m) instead of running the tests // directly. TestMain runs in the main goroutine and can do whatever setup // and teardown is necessary around a call to m.Run. It should then call -// os.Exit with the result of m.Run. +// os.Exit with the result of m.Run. When TestMain is called, flag.Parse has +// not been run. If TestMain depends on command-line flags, including those +// of the testing package, it should call flag.Parse explicitly. // -// The minimal implementation of TestMain is: +// A simple implementation of TestMain is: // -// func TestMain(m *testing.M) { os.Exit(m.Run()) } +// func TestMain(m *testing.M) { +// flag.Parse() +// os.Exit(m.Run()) +// } // -// In effect, that is the implementation used when no TestMain is explicitly defined. package testing import ( @@ -168,6 +172,7 @@ var ( // Report as tests are run; default is silent for success. chatty = flag.Bool("test.v", false, "verbose: print additional output") + count = flag.Uint("test.count", 1, "run tests and benchmarks `n` times") coverProfile = flag.String("test.coverprofile", "", "write a coverage profile to the named file after execution") match = flag.String("test.run", "", "regular expression to select tests and examples to run") memProfile = flag.String("test.memprofile", "", "write a memory profile to the named file after execution") @@ -175,6 +180,7 @@ var ( cpuProfile = flag.String("test.cpuprofile", "", "write a cpu profile to the named file during execution") blockProfile = flag.String("test.blockprofile", "", "write a goroutine blocking profile to the named file after execution") blockProfileRate = flag.Int("test.blockprofilerate", 1, "if >= 0, calls runtime.SetBlockProfileRate()") + traceFile = flag.String("test.trace", "", "write an execution trace to the named file after execution") timeout = flag.Duration("test.timeout", 0, "if positive, sets an aggregate time limit for all tests") 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") @@ -337,13 +343,15 @@ func (c *common) log(s string) { } // Log formats its arguments using default formatting, analogous to Println, -// and records the text in the error log. The text will be printed only if -// the test fails or the -test.v flag is set. +// and records the text in the error log. For tests, the text will be printed only if +// the test fails or the -test.v flag is set. For benchmarks, the text is always +// printed to avoid having performance depend on the value of the -test.v flag. func (c *common) Log(args ...interface{}) { c.log(fmt.Sprintln(args...)) } // Logf formats its arguments according to the format, analogous to Printf, -// and records the text in the error log. The text will be printed only if -// the test fails or the -test.v flag is set. +// and records the text in the error log. For tests, the text will be printed only if +// the test fails or the -test.v flag is set. For benchmarks, the text is always +// printed to avoid having performance depend on the value of the -test.v flag. func (c *common) Logf(format string, args ...interface{}) { c.log(fmt.Sprintf(format, args...)) } // Error is equivalent to Log followed by Fail. @@ -538,9 +546,6 @@ func RunTests(matchString func(pat, str string) (bool, error), tests []InternalT continue } testName := tests[i].Name - if procs != 1 { - testName = fmt.Sprintf("%s-%d", tests[i].Name, procs) - } t := &T{ common: common{ signal: make(chan interface{}), @@ -550,7 +555,7 @@ func RunTests(matchString func(pat, str string) (bool, error), tests []InternalT } t.self = t if *chatty { - fmt.Printf("=== RUN %s\n", t.name) + fmt.Printf("=== RUN %s\n", t.name) } go tRunner(t, &tests[i]) out := (<-t.signal).(*T) @@ -600,6 +605,22 @@ func before() { } // Could save f so after can call f.Close; not worth the effort. } + if *traceFile != "" { + f, err := os.Create(toOutputDir(*traceFile)) + if err != nil { + fmt.Fprintf(os.Stderr, "testing: %s", err) + return + } + /* + if err := trace.Start(f); err != nil { + fmt.Fprintf(os.Stderr, "testing: can't start tracing: %s", err) + f.Close() + return + } + */ + _ = f + // Could save f so after can call f.Close; not worth the effort. + } if *blockProfile != "" && *blockProfileRate >= 0 { runtime.SetBlockProfileRate(*blockProfileRate) } @@ -614,6 +635,11 @@ func after() { if *cpuProfile != "" { pprof.StopCPUProfile() // flushes profile to disk } + if *traceFile != "" { + /* + trace.Stop() // flushes trace to disk + */ + } if *memProfile != "" { f, err := os.Create(toOutputDir(*memProfile)) if err != nil { @@ -701,9 +727,13 @@ func parseCpuList() { fmt.Fprintf(os.Stderr, "testing: invalid value %q for -test.cpu\n", val) os.Exit(1) } - cpuList = append(cpuList, cpu) + for i := uint(0); i < *count; i++ { + cpuList = append(cpuList, cpu) + } } if cpuList == nil { - cpuList = append(cpuList, runtime.GOMAXPROCS(-1)) + for i := uint(0); i < *count; i++ { + cpuList = append(cpuList, runtime.GOMAXPROCS(-1)) + } } } diff --git a/libgo/go/text/scanner/example_test.go b/libgo/go/text/scanner/example_test.go new file mode 100644 index 00000000000..f8b51b7322b --- /dev/null +++ b/libgo/go/text/scanner/example_test.go @@ -0,0 +1,40 @@ +// Copyright 2015 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 + +package scanner_test + +import ( + "fmt" + "strings" + "text/scanner" +) + +func Example() { + const src = ` + // This is scanned code. + if a > 10 { + someParsable = text + }` + var s scanner.Scanner + s.Init(strings.NewReader(src)) + var tok rune + for tok != scanner.EOF { + tok = s.Scan() + fmt.Println("At position", s.Pos(), ":", s.TokenText()) + } + + // Output: + // At position 3:4 : if + // At position 3:6 : a + // At position 3:8 : > + // At position 3:11 : 10 + // At position 3:13 : { + // At position 4:15 : someParsable + // At position 4:17 : = + // At position 4:22 : text + // At position 5:3 : } + // At position 5:3 : +} diff --git a/libgo/go/text/scanner/scanner.go b/libgo/go/text/scanner/scanner.go index 5199ee4fc7d..3ab01edd247 100644 --- a/libgo/go/text/scanner/scanner.go +++ b/libgo/go/text/scanner/scanner.go @@ -12,17 +12,6 @@ // literals as defined by the Go language specification. It may be // customized to recognize only a subset of those literals and to recognize // different identifier and white space characters. -// -// Basic usage pattern: -// -// var s scanner.Scanner -// s.Init(src) -// tok := s.Scan() -// for tok != scanner.EOF { -// // do something with tok -// tok = s.Scan() -// } -// package scanner import ( @@ -43,7 +32,7 @@ type Position struct { Column int // column number, starting at 1 (character count per line) } -// IsValid returns true if the position is valid. +// IsValid reports whether the position is valid. func (pos *Position) IsValid() bool { return pos.Line > 0 } func (pos Position) String() string { @@ -208,7 +197,7 @@ func (s *Scanner) Init(src io.Reader) *Scanner { s.tokPos = -1 // initialize one character look-ahead - s.ch = -1 // no char read yet + s.ch = -2 // no char read yet, not EOF // initialize public fields s.Error = nil @@ -314,7 +303,9 @@ func (s *Scanner) Next() rune { s.tokPos = -1 // don't collect token text s.Line = 0 // invalidate token position ch := s.Peek() - s.ch = s.next() + if ch != EOF { + s.ch = s.next() + } return ch } @@ -322,7 +313,7 @@ func (s *Scanner) Next() rune { // the scanner. It returns EOF if the scanner's position is at the last // character of the source. func (s *Scanner) Peek() rune { - if s.ch < 0 { + if s.ch == -2 { // this code is only run for the very first character s.ch = s.next() if s.ch == '\uFEFF' { @@ -597,6 +588,8 @@ redo: } default: switch ch { + case EOF: + break case '"': if s.Mode&ScanStrings != 0 { s.scanString('"') diff --git a/libgo/go/text/scanner/scanner_test.go b/libgo/go/text/scanner/scanner_test.go index 702fac2b1ad..798bed7e92a 100644 --- a/libgo/go/text/scanner/scanner_test.go +++ b/libgo/go/text/scanner/scanner_test.go @@ -616,3 +616,52 @@ func TestPos(t *testing.T) { t.Errorf("%d errors", s.ErrorCount) } } + +type countReader int + +func (r *countReader) Read([]byte) (int, error) { + *r++ + return 0, io.EOF +} + +func TestNextEOFHandling(t *testing.T) { + var r countReader + + // corner case: empty source + s := new(Scanner).Init(&r) + + tok := s.Next() + if tok != EOF { + t.Error("1) EOF not reported") + } + + tok = s.Peek() + if tok != EOF { + t.Error("2) EOF not reported") + } + + if r != 1 { + t.Errorf("scanner called Read %d times, not once", r) + } +} + +func TestScanEOFHandling(t *testing.T) { + var r countReader + + // corner case: empty source + s := new(Scanner).Init(&r) + + tok := s.Scan() + if tok != EOF { + t.Error("1) EOF not reported") + } + + tok = s.Peek() + if tok != EOF { + t.Error("2) EOF not reported") + } + + if r != 1 { + t.Errorf("scanner called Read %d times, not once", r) + } +} diff --git a/libgo/go/text/template/doc.go b/libgo/go/text/template/doc.go index 223c595c25d..0ce63f66d59 100644 --- a/libgo/go/text/template/doc.go +++ b/libgo/go/text/template/doc.go @@ -18,7 +18,7 @@ structure as execution proceeds. The input text for a template is UTF-8-encoded text in any format. "Actions"--data evaluations or control structures--are delimited by "{{" and "}}"; all text outside actions is copied to the output unchanged. -Actions may not span newlines, although comments can. +Except for raw strings, actions may not span newlines, although comments can. Once parsed, a template may be executed safely in parallel. @@ -106,7 +106,7 @@ An argument is a simple value, denoted by one of the following. - A boolean, string, character, integer, floating-point, imaginary or complex constant in Go syntax. These behave like Go's untyped - constants, although raw strings may not span newlines. + constants. - The keyword nil, representing an untyped Go nil. - The character '.' (period): . diff --git a/libgo/go/text/template/exec.go b/libgo/go/text/template/exec.go index b00e10c7e41..daba788b55b 100644 --- a/libgo/go/text/template/exec.go +++ b/libgo/go/text/template/exec.go @@ -113,7 +113,10 @@ func errRecover(errp *error) { // the output writer. // A template may be executed safely in parallel. func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{}) error { - tmpl := t.tmpl[name] + var tmpl *Template + if t.common != nil { + tmpl = t.tmpl[name] + } if tmpl == nil { return fmt.Errorf("template: no template %q associated with template %q", name, t.name) } @@ -134,26 +137,36 @@ func (t *Template) Execute(wr io.Writer, data interface{}) (err error) { wr: wr, vars: []variable{{"$", value}}, } - t.init() if t.Tree == nil || t.Root == nil { - var b bytes.Buffer - for name, tmpl := range t.tmpl { - if tmpl.Tree == nil || tmpl.Root == nil { - continue - } - if b.Len() > 0 { - b.WriteString(", ") - } - fmt.Fprintf(&b, "%q", name) + state.errorf("%q is an incomplete or empty template%s", t.Name(), t.DefinedTemplates()) + } + state.walk(value, t.Root) + return +} + +// DefinedTemplates returns a string listing the defined templates, +// prefixed by the string "defined templates are: ". If there are none, +// it returns the empty string. For generating an error message here +// and in html/template. +func (t *Template) DefinedTemplates() string { + if t.common == nil { + return "" + } + var b bytes.Buffer + for name, tmpl := range t.tmpl { + if tmpl.Tree == nil || tmpl.Root == nil { + continue } - var s string if b.Len() > 0 { - s = "; defined templates are: " + b.String() + b.WriteString(", ") } - state.errorf("%q is an incomplete or empty template%s", t.Name(), s) + fmt.Fprintf(&b, "%q", name) } - state.walk(value, t.Root) - return + var s string + if b.Len() > 0 { + s = "; defined templates are: " + b.String() + } + return s } // Walk functions step through the major pieces of the template structure, @@ -418,11 +431,14 @@ func (s *state) evalFieldNode(dot reflect.Value, field *parse.FieldNode, args [] func (s *state) evalChainNode(dot reflect.Value, chain *parse.ChainNode, args []parse.Node, final reflect.Value) reflect.Value { s.at(chain) - // (pipe).Field1.Field2 has pipe as .Node, fields as .Field. Eval the pipeline, then the fields. - pipe := s.evalArg(dot, nil, chain.Node) if len(chain.Field) == 0 { s.errorf("internal error: no fields in evalChainNode") } + if chain.Node.Type() == parse.NodeNil { + s.errorf("indirection through explicit nil in %s", chain) + } + // (pipe).Field1.Field2 has pipe as .Node, fields as .Field. Eval the pipeline, then the fields. + pipe := s.evalArg(dot, nil, chain.Node) return s.evalFieldChain(dot, pipe, chain, chain.Field, args, final) } @@ -505,7 +521,18 @@ func (s *state) evalField(dot reflect.Value, fieldName string, node parse.Node, if hasArgs { s.errorf("%s is not a method but has arguments", fieldName) } - return receiver.MapIndex(nameVal) + result := receiver.MapIndex(nameVal) + if !result.IsValid() { + switch s.tmpl.option.missingKey { + case mapInvalid: + // Just use the invalid value. + case mapZeroValue: + result = reflect.Zero(receiver.Type().Elem()) + case mapError: + s.errorf("map has no entry for key %q", fieldName) + } + } + return result } } s.errorf("can't evaluate field %s in type %s", fieldName, typ) @@ -560,7 +587,15 @@ func (s *state) evalCall(dot, fun reflect.Value, node parse.Node, name string, a if final.IsValid() { t := typ.In(typ.NumIn() - 1) if typ.IsVariadic() { - t = t.Elem() + if numIn-1 < numFixed { + // The added final argument corresponds to a fixed parameter of the function. + // Validate against the type of the actual parameter. + t = typ.In(numIn - 1) + } else { + // The added final argument corresponds to the variadic part. + // Validate against the type of the elements of the variadic slice. + t = t.Elem() + } } argv[i] = s.validateType(final, t) } @@ -635,7 +670,7 @@ func (s *state) evalArg(dot reflect.Value, typ reflect.Type, n parse.Node) refle case *parse.PipeNode: return s.validateType(s.evalPipeline(dot, arg), typ) case *parse.IdentifierNode: - return s.evalFunction(dot, arg, arg, nil, zero) + return s.validateType(s.evalFunction(dot, arg, arg, nil, zero), typ) case *parse.ChainNode: return s.validateType(s.evalChainNode(dot, arg, nil, zero), typ) } diff --git a/libgo/go/text/template/exec_test.go b/libgo/go/text/template/exec_test.go index 69c213ed245..ba0e434f98c 100644 --- a/libgo/go/text/template/exec_test.go +++ b/libgo/go/text/template/exec_test.go @@ -527,6 +527,24 @@ var execTests = []execTest{ {"bug12XE", "{{printf `%T` 0XEE}}", "int", T{}, true}, // Chained nodes did not work as arguments. Issue 8473. {"bug13", "{{print (.Copy).I}}", "17", tVal, true}, + // Didn't protect against nil or literal values in field chains. + {"bug14a", "{{(nil).True}}", "", tVal, false}, + {"bug14b", "{{$x := nil}}{{$x.anything}}", "", tVal, false}, + {"bug14c", `{{$x := (1.0)}}{{$y := ("hello")}}{{$x.anything}}{{$y.true}}`, "", tVal, false}, + // Didn't call validateType on function results. Issue 10800. + {"bug15", "{{valueString returnInt}}", "", tVal, false}, + // Variadic function corner cases. Issue 10946. + {"bug16a", "{{true|printf}}", "", tVal, false}, + {"bug16b", "{{1|printf}}", "", tVal, false}, + {"bug16c", "{{1.1|printf}}", "", tVal, false}, + {"bug16d", "{{'x'|printf}}", "", tVal, false}, + {"bug16e", "{{0i|printf}}", "", tVal, false}, + {"bug16f", "{{true|twoArgs \"xxx\"}}", "", tVal, false}, + {"bug16g", "{{\"aaa\" |twoArgs \"bbb\"}}", "twoArgs=bbbaaa", tVal, true}, + {"bug16h", "{{1|oneArg}}", "", tVal, false}, + {"bug16i", "{{\"aaa\"|oneArg}}", "oneArg=aaa", tVal, true}, + {"bug16j", "{{1+2i|printf \"%v\"}}", "(1+2i)", tVal, true}, + {"bug16k", "{{\"aaa\"|printf }}", "aaa", tVal, true}, } func zeroArgs() string { @@ -537,6 +555,10 @@ func oneArg(a string) string { return "oneArg=" + a } +func twoArgs(a, b string) string { + return "twoArgs=" + a + b +} + func dddArg(a int, b ...string) string { return fmt.Sprintln(a, b) } @@ -566,6 +588,11 @@ func valueString(v string) string { return "value is ignored" } +// returnInt returns an int +func returnInt() int { + return 7 +} + func add(args ...int) int { sum := 0 for _, x := range args { @@ -607,7 +634,9 @@ func testExecute(execTests []execTest, template *Template, t *testing.T) { "makemap": makemap, "mapOfThree": mapOfThree, "oneArg": oneArg, + "returnInt": returnInt, "stringer": stringer, + "twoArgs": twoArgs, "typeOf": typeOf, "valueString": valueString, "vfunc": vfunc, @@ -853,7 +882,13 @@ func TestTree(t *testing.T) { func TestExecuteOnNewTemplate(t *testing.T) { // This is issue 3872. - _ = New("Name").Templates() + New("Name").Templates() + // This is issue 11379. + new(Template).Templates() + new(Template).Parse("") + new(Template).New("abc").Parse("") + new(Template).Execute(nil, nil) // returns an error (but does not crash) + new(Template).ExecuteTemplate(nil, "XXX", nil) // returns an error (but does not crash) } const testTemplates = `{{define "one"}}one{{end}}{{define "two"}}two{{end}}` @@ -1042,3 +1077,67 @@ func TestComparison(t *testing.T) { } } } + +func TestMissingMapKey(t *testing.T) { + data := map[string]int{ + "x": 99, + } + tmpl, err := New("t1").Parse("{{.x}} {{.y}}") + if err != nil { + t.Fatal(err) + } + var b bytes.Buffer + // By default, just get "" + err = tmpl.Execute(&b, data) + if err != nil { + t.Fatal(err) + } + want := "99 " + got := b.String() + if got != want { + t.Errorf("got %q; expected %q", got, want) + } + // Same if we set the option explicitly to the default. + tmpl.Option("missingkey=default") + b.Reset() + err = tmpl.Execute(&b, data) + if err != nil { + t.Fatal("default:", err) + } + want = "99 " + got = b.String() + if got != want { + t.Errorf("got %q; expected %q", got, want) + } + // Next we ask for a zero value + tmpl.Option("missingkey=zero") + b.Reset() + err = tmpl.Execute(&b, data) + if err != nil { + t.Fatal("zero:", err) + } + want = "99 0" + got = b.String() + if got != want { + t.Errorf("got %q; expected %q", got, want) + } + // Now we ask for an error. + tmpl.Option("missingkey=error") + err = tmpl.Execute(&b, data) + if err == nil { + t.Errorf("expected error; got none") + } +} + +// Test that the error message for multiline unterminated string +// refers to the line number of the opening quote. +func TestUnterminatedStringError(t *testing.T) { + _, err := New("X").Parse("hello\n\n{{`unterminated\n\n\n\n}}\n some more\n\n") + if err == nil { + t.Fatal("expected error") + } + str := err.Error() + if !strings.Contains(str, "X:3: unexpected unterminated raw quoted strin") { + t.Fatalf("unexpected error: %s", str) + } +} diff --git a/libgo/go/text/template/funcs.go b/libgo/go/text/template/funcs.go index 39ee5ed68fb..ccd0dfc80d8 100644 --- a/libgo/go/text/template/funcs.go +++ b/libgo/go/text/template/funcs.go @@ -92,6 +92,8 @@ func goodFunc(typ reflect.Type) bool { // findFunction looks for a function in the template, and global map. func findFunction(name string, tmpl *Template) (reflect.Value, bool) { if tmpl != nil && tmpl.common != nil { + tmpl.muFuncs.RLock() + defer tmpl.muFuncs.RUnlock() if fn := tmpl.execFuncs[name]; fn.IsValid() { return fn, true } @@ -590,7 +592,7 @@ func evalArgs(args []interface{}) string { a, ok := printableValue(reflect.ValueOf(arg)) if ok { args[i] = a - } // else left fmt do its thing + } // else let fmt do its thing } s = fmt.Sprint(args...) } diff --git a/libgo/go/text/template/helper.go b/libgo/go/text/template/helper.go index 3636fb54d69..787ca62e5f3 100644 --- a/libgo/go/text/template/helper.go +++ b/libgo/go/text/template/helper.go @@ -26,8 +26,8 @@ func Must(t *Template, err error) *Template { } // ParseFiles creates a new Template and parses the template definitions from -// the named files. The returned template's name will have the (base) name and -// (parsed) contents of the first file. There must be at least one file. +// the named files. The returned template's name will have the base name and +// parsed contents of the first file. There must be at least one file. // If an error occurs, parsing stops and the returned *Template is nil. func ParseFiles(filenames ...string) (*Template, error) { return parseFiles(nil, filenames...) @@ -36,7 +36,13 @@ func ParseFiles(filenames ...string) (*Template, error) { // ParseFiles parses the named files and associates the resulting templates with // t. If an error occurs, parsing stops and the returned template is nil; // otherwise it is t. There must be at least one file. +// Since the templates created by ParseFiles are named by the base +// names of the argument files, t should usually have the name of one +// of the (base) names of the files. If it does not, depending on t's +// contents before calling ParseFiles, t.Execute may fail. In that +// case use t.ExecuteTemplate to execute a valid template. func (t *Template) ParseFiles(filenames ...string) (*Template, error) { + t.init() return parseFiles(t, filenames...) } @@ -92,6 +98,7 @@ func ParseGlob(pattern string) (*Template, error) { // equivalent to calling t.ParseFiles with the list of files matched by the // pattern. func (t *Template) ParseGlob(pattern string) (*Template, error) { + t.init() return parseGlob(t, pattern) } diff --git a/libgo/go/text/template/multi_test.go b/libgo/go/text/template/multi_test.go index e4e804880a4..ea01875e9c0 100644 --- a/libgo/go/text/template/multi_test.go +++ b/libgo/go/text/template/multi_test.go @@ -290,3 +290,76 @@ func TestRedefinition(t *testing.T) { t.Fatalf("expected redefinition error; got %v", err) } } + +// Issue 10879 +func TestEmptyTemplateCloneCrash(t *testing.T) { + t1 := New("base") + t1.Clone() // used to panic +} + +// Issue 10910, 10926 +func TestTemplateLookUp(t *testing.T) { + t1 := New("foo") + if t1.Lookup("foo") != nil { + t.Error("Lookup returned non-nil value for undefined template foo") + } + t1.New("bar") + if t1.Lookup("bar") != nil { + t.Error("Lookup returned non-nil value for undefined template bar") + } + t1.Parse(`{{define "foo"}}test{{end}}`) + if t1.Lookup("foo") == nil { + t.Error("Lookup returned nil value for defined template") + } +} + +func TestNew(t *testing.T) { + // template with same name already exists + t1, _ := New("test").Parse(`{{define "test"}}foo{{end}}`) + t2 := t1.New("test") + + if t1.common != t2.common { + t.Errorf("t1 & t2 didn't share common struct; got %v != %v", t1.common, t2.common) + } + if t1.Tree == nil { + t.Error("defined template got nil Tree") + } + if t2.Tree != nil { + t.Error("undefined template got non-nil Tree") + } + + containsT1 := false + for _, tmpl := range t1.Templates() { + if tmpl == t2 { + t.Error("Templates included undefined template") + } + if tmpl == t1 { + containsT1 = true + } + } + if !containsT1 { + t.Error("Templates didn't include defined template") + } +} + +func TestParse(t *testing.T) { + // In multiple calls to Parse with the same receiver template, only one call + // can contain text other than space, comments, and template definitions + var err error + t1 := New("test") + if _, err := t1.Parse(`{{define "test"}}{{end}}`); err != nil { + t.Fatalf("parsing test: %s", err) + } + if _, err := t1.Parse(`{{define "test"}}{{/* this is a comment */}}{{end}}`); err != nil { + t.Fatalf("parsing test: %s", err) + } + if _, err := t1.Parse(`{{define "test"}}foo{{end}}`); err != nil { + t.Fatalf("parsing test: %s", err) + } + if _, err = t1.Parse(`{{define "test"}}foo{{end}}`); err == nil { + t.Fatal("no error from redefining a template") + } + if !strings.Contains(err.Error(), "redefinition") { + t.Fatalf("expected redefinition error; got %v", err) + } +} diff --git a/libgo/go/text/template/option.go b/libgo/go/text/template/option.go new file mode 100644 index 00000000000..addce2d890d --- /dev/null +++ b/libgo/go/text/template/option.go @@ -0,0 +1,74 @@ +// Copyright 2015 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 the code to handle template options. + +package template + +import "strings" + +// missingKeyAction defines how to respond to indexing a map with a key that is not present. +type missingKeyAction int + +const ( + mapInvalid missingKeyAction = iota // Return an invalid reflect.Value. + mapZeroValue // Return the zero value for the map element. + mapError // Error out +) + +type option struct { + missingKey missingKeyAction +} + +// Option sets options for the template. Options are described by +// strings, either a simple string or "key=value". There can be at +// most one equals sign in an option string. If the option string +// is unrecognized or otherwise invalid, Option panics. +// +// Known options: +// +// missingkey: Control the behavior during execution if a map is +// indexed with a key that is not present in the map. +// "missingkey=default" or "missingkey=invalid" +// The default behavior: Do nothing and continue execution. +// If printed, the result of the index operation is the string +// "". +// "missingkey=zero" +// The operation returns the zero value for the map type's element. +// "missingkey=error" +// Execution stops immediately with an error. +// +func (t *Template) Option(opt ...string) *Template { + t.init() + for _, s := range opt { + t.setOption(s) + } + return t +} + +func (t *Template) setOption(opt string) { + if opt == "" { + panic("empty option string") + } + elems := strings.Split(opt, "=") + switch len(elems) { + case 2: + // key=value + switch elems[0] { + case "missingkey": + switch elems[1] { + case "invalid", "default": + t.option.missingKey = mapInvalid + return + case "zero": + t.option.missingKey = mapZeroValue + return + case "error": + t.option.missingKey = mapError + return + } + } + } + panic("unrecognized option: " + opt) +} diff --git a/libgo/go/text/template/parse/lex.go b/libgo/go/text/template/parse/lex.go index 1674aaf9cd4..8f9fe1d4d8e 100644 --- a/libgo/go/text/template/parse/lex.go +++ b/libgo/go/text/template/parse/lex.go @@ -167,12 +167,20 @@ func (l *lexer) errorf(format string, args ...interface{}) stateFn { } // nextItem returns the next item from the input. +// Called by the parser, not in the lexing goroutine. func (l *lexer) nextItem() item { item := <-l.items l.lastPos = item.pos return item } +// drain drains the output so the lexing goroutine will exit. +// Called by the parser, not in the lexing goroutine. +func (l *lexer) drain() { + for range l.items { + } +} + // lex creates a new scanner for the input string. func lex(name, input, left, right string) *lexer { if left == "" { @@ -197,6 +205,7 @@ func (l *lexer) run() { for l.state = lexText; l.state != nil; { l.state = l.state(l) } + close(l.items) } // state functions @@ -313,14 +322,12 @@ func lexInsideAction(l *lexer) stateFn { case r == '(': l.emit(itemLeftParen) l.parenDepth++ - return lexInsideAction case r == ')': l.emit(itemRightParen) l.parenDepth-- if l.parenDepth < 0 { return l.errorf("unexpected right paren %#U", r) } - return lexInsideAction case r <= unicode.MaxASCII && unicode.IsPrint(r): l.emit(itemChar) return lexInsideAction @@ -525,7 +532,7 @@ func lexRawQuote(l *lexer) stateFn { Loop: for { switch l.next() { - case eof, '\n': + case eof: return l.errorf("unterminated raw quoted string") case '`': break Loop diff --git a/libgo/go/text/template/parse/lex_test.go b/libgo/go/text/template/parse/lex_test.go index d251ccffb6c..be551d87803 100644 --- a/libgo/go/text/template/parse/lex_test.go +++ b/libgo/go/text/template/parse/lex_test.go @@ -58,18 +58,20 @@ type lexTest struct { } var ( - tEOF = item{itemEOF, 0, ""} - tFor = item{itemIdentifier, 0, "for"} - tLeft = item{itemLeftDelim, 0, "{{"} - tLpar = item{itemLeftParen, 0, "("} - tPipe = item{itemPipe, 0, "|"} - tQuote = item{itemString, 0, `"abc \n\t\" "`} - tRange = item{itemRange, 0, "range"} - tRight = item{itemRightDelim, 0, "}}"} - tRpar = item{itemRightParen, 0, ")"} - tSpace = item{itemSpace, 0, " "} - raw = "`" + `abc\n\t\" ` + "`" - tRawQuote = item{itemRawString, 0, raw} + tEOF = item{itemEOF, 0, ""} + tFor = item{itemIdentifier, 0, "for"} + tLeft = item{itemLeftDelim, 0, "{{"} + tLpar = item{itemLeftParen, 0, "("} + tPipe = item{itemPipe, 0, "|"} + tQuote = item{itemString, 0, `"abc \n\t\" "`} + tRange = item{itemRange, 0, "range"} + tRight = item{itemRightDelim, 0, "}}"} + tRpar = item{itemRightParen, 0, ")"} + tSpace = item{itemSpace, 0, " "} + raw = "`" + `abc\n\t\" ` + "`" + rawNL = "`now is{{\n}}the time`" // Contains newline inside raw quote. + tRawQuote = item{itemRawString, 0, raw} + tRawQuoteNL = item{itemRawString, 0, rawNL} ) var lexTests = []lexTest{ @@ -104,6 +106,7 @@ var lexTests = []lexTest{ {"for", `{{for}}`, []item{tLeft, tFor, tRight, tEOF}}, {"quote", `{{"abc \n\t\" "}}`, []item{tLeft, tQuote, tRight, tEOF}}, {"raw quote", "{{" + raw + "}}", []item{tLeft, tRawQuote, tRight, tEOF}}, + {"raw quote with newline", "{{" + rawNL + "}}", []item{tLeft, tRawQuoteNL, tRight, tEOF}}, {"numbers", "{{1 02 0x14 -7.2i 1e3 +1.2e-4 4.2i 1+2i}}", []item{ tLeft, {itemNumber, 0, "1"}, @@ -294,7 +297,7 @@ var lexTests = []lexTest{ tLeft, {itemError, 0, "unterminated quoted string"}, }}, - {"unclosed raw quote", "{{`xx\n`}}", []item{ + {"unclosed raw quote", "{{`xx}}", []item{ tLeft, {itemError, 0, "unterminated raw quoted string"}, }}, @@ -463,3 +466,31 @@ func TestPos(t *testing.T) { } } } + +// Test that an error shuts down the lexing goroutine. +func TestShutdown(t *testing.T) { + // We need to duplicate template.Parse here to hold on to the lexer. + const text = "erroneous{{define}}{{else}}1234" + lexer := lex("foo", text, "{{", "}}") + _, err := New("root").parseLexer(lexer, text) + if err == nil { + t.Fatalf("expected error") + } + // The error should have drained the input. Therefore, the lexer should be shut down. + token, ok := <-lexer.items + if ok { + t.Fatalf("input was not drained; got %v", token) + } +} + +// parseLexer is a local version of parse that lets us pass in the lexer instead of building it. +// We expect an error, so the tree set and funcs list are explicitly nil. +func (t *Tree) parseLexer(lex *lexer, text string) (tree *Tree, err error) { + defer t.recover(&err) + t.ParseName = t.Name + t.startParse(nil, lex) + t.parse(nil) + t.add(nil) + t.stopParse() + return t, nil +} diff --git a/libgo/go/text/template/parse/node.go b/libgo/go/text/template/parse/node.go index 55c37f6dbac..55ff46c17ab 100644 --- a/libgo/go/text/template/parse/node.go +++ b/libgo/go/text/template/parse/node.go @@ -145,7 +145,7 @@ type PipeNode struct { NodeType Pos tr *Tree - Line int // The line number in the input (deprecated; kept for compatibility) + Line int // The line number in the input. Deprecated: Kept for compatibility. Decl []*VariableNode // Variable declarations in lexical order. Cmds []*CommandNode // The commands in lexical order. } @@ -208,7 +208,7 @@ type ActionNode struct { NodeType Pos tr *Tree - Line int // The line number in the input (deprecated; kept for compatibility) + Line int // The line number in the input. Deprecated: Kept for compatibility. Pipe *PipeNode // The pipeline in the action. } @@ -592,6 +592,11 @@ func (t *Tree) newNumber(pos Pos, text string, typ itemType) (*NumberNode, error } else { f, err := strconv.ParseFloat(text, 64) if err == nil { + // If we parsed it as a float but it looks like an integer, + // it's a huge number too large to fit in an int. Reject it. + if !strings.ContainsAny(text, ".eE") { + return nil, fmt.Errorf("integer overflow: %q", text) + } n.IsFloat = true n.Float64 = f // If a floating-point extraction succeeded, extract the int if needed. @@ -696,7 +701,7 @@ type elseNode struct { NodeType Pos tr *Tree - Line int // The line number in the input (deprecated; kept for compatibility) + Line int // The line number in the input. Deprecated: Kept for compatibility. } func (t *Tree) newElse(pos Pos, line int) *elseNode { @@ -724,7 +729,7 @@ type BranchNode struct { NodeType Pos tr *Tree - Line int // The line number in the input (deprecated; kept for compatibility) + Line int // The line number in the input. Deprecated: Kept for compatibility. Pipe *PipeNode // The pipeline to be evaluated. List *ListNode // What to execute if the value is non-empty. ElseList *ListNode // What to execute if the value is empty (nil if absent). @@ -809,7 +814,7 @@ type TemplateNode struct { NodeType Pos tr *Tree - Line int // The line number in the input (deprecated; kept for compatibility) + Line int // The line number in the input. Deprecated: Kept for compatibility. Name string // The name of the template (unquoted). Pipe *PipeNode // The command to evaluate as dot for the template. } diff --git a/libgo/go/text/template/parse/parse.go b/libgo/go/text/template/parse/parse.go index af33880c15a..88aacd1b72b 100644 --- a/libgo/go/text/template/parse/parse.go +++ b/libgo/go/text/template/parse/parse.go @@ -196,6 +196,7 @@ func (t *Tree) recover(errp *error) { panic(e) } if t != nil { + t.lex.drain() t.stopParse() } *errp = e.(error) @@ -288,11 +289,12 @@ func (t *Tree) parse(treeSet map[string]*Tree) (next Node) { } t.backup2(delim) } - n := t.textOrAction() - if n.Type() == nodeEnd { + switch n := t.textOrAction(); n.Type() { + case nodeEnd, nodeElse: t.errorf("unexpected %s", n) + default: + t.Root.append(n) } - t.Root.append(n) } return nil } @@ -411,9 +413,8 @@ func (t *Tree) pipeline(context string) (pipe *PipeNode) { for { switch token := t.nextNonSpace(); token.typ { case itemRightDelim, itemRightParen: - if len(pipe.Cmds) == 0 { - t.errorf("missing value for %s", context) - } + // At this point, the pipeline is complete + t.checkPipeline(pipe, context) if token.typ == itemRightParen { t.backup() } @@ -428,6 +429,21 @@ func (t *Tree) pipeline(context string) (pipe *PipeNode) { } } +func (t *Tree) checkPipeline(pipe *PipeNode, context string) { + // Reject empty pipelines + if len(pipe.Cmds) == 0 { + t.errorf("missing value for %s", context) + } + // Only the first command of a pipeline can start with a non executable operand + for i, c := range pipe.Cmds[1:] { + switch c.Args[0].Type() { + case NodeBool, NodeDot, NodeNil, NodeNumber, NodeString: + // With A|B|C, pipeline stage 2 is B + t.errorf("non executable command in pipeline stage %d", i+2) + } + } +} + func (t *Tree) parseControl(allowElseIf bool, context string) (pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) { defer t.popVars(len(t.vars)) line = t.lex.lineNumber() @@ -553,7 +569,7 @@ func (t *Tree) command() *CommandNode { t.backup() case itemPipe: default: - t.errorf("unexpected %s in operand; missing space?", token) + t.errorf("unexpected %s in operand", token) } break } @@ -581,12 +597,15 @@ func (t *Tree) operand() Node { // Compatibility with original API: If the term is of type NodeField // or NodeVariable, just put more fields on the original. // Otherwise, keep the Chain node. - // TODO: Switch to Chains always when we can. + // Obvious parsing errors involving literal values are detected here. + // More complex error cases will have to be handled at execution time. switch node.Type() { case NodeField: node = t.newField(chain.Position(), chain.String()) case NodeVariable: node = t.newVariable(chain.Position(), chain.String()) + case NodeBool, NodeString, NodeNumber, NodeNil, NodeDot: + t.errorf("unexpected . after term %q", node.String()) default: node = chain } diff --git a/libgo/go/text/template/parse/parse_test.go b/libgo/go/text/template/parse/parse_test.go index 4a504fa7c83..200d50c194d 100644 --- a/libgo/go/text/template/parse/parse_test.go +++ b/libgo/go/text/template/parse/parse_test.go @@ -69,6 +69,7 @@ var numberTests = []numberTest{ {text: "1+2."}, {text: "'x"}, {text: "'xx'"}, + {text: "'433937734937734969526500969526500'"}, // Integer too large - issue 10634. // Issue 8622 - 0xe parsed as floating point. Very embarrassing. {"0xef", true, true, true, false, 0xef, 0xef, 0xef, 0}, } @@ -230,6 +231,9 @@ var parseTests = []parseTest{ // Errors. {"unclosed action", "hello{{range", hasError, ""}, {"unmatched end", "{{end}}", hasError, ""}, + {"unmatched else", "{{else}}", hasError, ""}, + {"unmatched else after if", "{{if .X}}hello{{end}}{{else}}", hasError, ""}, + {"multiple else", "{{if .X}}1{{else}}2{{else}}3{{end}}", hasError, ""}, {"missing end", "hello{{range .x}}", hasError, ""}, {"missing end after else", "hello{{range .x}}{{else}}", hasError, ""}, {"undefined function", "hello{{undefined}}", hasError, ""}, @@ -257,6 +261,22 @@ var parseTests = []parseTest{ {"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. + // dot following a literal value + {"dot after integer", "{{1.E}}", hasError, ""}, + {"dot after float", "{{0.1.E}}", hasError, ""}, + {"dot after boolean", "{{true.E}}", hasError, ""}, + {"dot after char", "{{'a'.any}}", hasError, ""}, + {"dot after string", `{{"hello".guys}}`, hasError, ""}, + {"dot after dot", "{{..E}}", hasError, ""}, + {"dot after nil", "{{nil.E}}", hasError, ""}, + // Wrong pipeline + {"wrong pipeline dot", "{{12|.}}", hasError, ""}, + {"wrong pipeline number", "{{.|12|printf}}", hasError, ""}, + {"wrong pipeline string", "{{.|printf|\"error\"}}", hasError, ""}, + {"wrong pipeline char", "{{12|printf|'e'}}", hasError, ""}, + {"wrong pipeline boolean", "{{.|true}}", hasError, ""}, + {"wrong pipeline nil", "{{'c'|nil}}", hasError, ""}, + {"empty pipeline", `{{printf "%d" ( ) }}`, hasError, ""}, } var builtins = map[string]interface{}{ @@ -375,7 +395,7 @@ var errorTests = []parseTest{ hasError, `unexpected ")"`}, {"space", "{{`x`3}}", - hasError, `missing space?`}, + hasError, `in operand`}, {"idchar", "{{a#}}", hasError, `'#'`}, @@ -407,6 +427,15 @@ var errorTests = []parseTest{ {"undefvar", "{{$a}}", hasError, `undefined variable`}, + {"wrongdot", + "{{true.any}}", + hasError, `unexpected . after term`}, + {"wrongpipeline", + "{{12|false}}", + hasError, `non executable command in pipeline`}, + {"emptypipeline", + `{{ ( ) }}`, + hasError, `missing value for parenthesized pipeline`}, } func TestErrors(t *testing.T) { diff --git a/libgo/go/text/template/template.go b/libgo/go/text/template/template.go index 249d0cbfb90..3e80982123a 100644 --- a/libgo/go/text/template/template.go +++ b/libgo/go/text/template/template.go @@ -7,15 +7,18 @@ package template import ( "fmt" "reflect" + "sync" "text/template/parse" ) // common holds the information shared by related templates. type common struct { - tmpl map[string]*Template + tmpl map[string]*Template // Map from name to defined templates. + option option // We use two maps, one for parsing and one for execution. // This separation makes the API cleaner since it doesn't // expose reflection to the client. + muFuncs sync.RWMutex // protects parseFuncs and execFuncs parseFuncs FuncMap execFuncs map[string]reflect.Value } @@ -31,11 +34,13 @@ type Template struct { rightDelim string } -// New allocates a new template with the given name. +// New allocates a new, undefined template with the given name. func New(name string) *Template { - return &Template{ + t := &Template{ name: name, } + t.init() + return t } // Name returns the name of the template. @@ -43,25 +48,28 @@ func (t *Template) Name() string { return t.name } -// New allocates a new template associated with the given one and with the same +// New allocates a new, undefined template associated with the given one and with the same // delimiters. The association, which is transitive, allows one template to // invoke another with a {{template}} action. func (t *Template) New(name string) *Template { t.init() - return &Template{ + nt := &Template{ name: name, common: t.common, leftDelim: t.leftDelim, rightDelim: t.rightDelim, } + return nt } +// init guarantees that t has a valid common structure. func (t *Template) init() { if t.common == nil { - t.common = new(common) - t.tmpl = make(map[string]*Template) - t.parseFuncs = make(FuncMap) - t.execFuncs = make(map[string]reflect.Value) + c := new(common) + c.tmpl = make(map[string]*Template) + c.parseFuncs = make(FuncMap) + c.execFuncs = make(map[string]reflect.Value) + t.common = c } } @@ -74,15 +82,20 @@ func (t *Template) init() { func (t *Template) Clone() (*Template, error) { nt := t.copy(nil) nt.init() - nt.tmpl[t.name] = nt + if t.common == nil { + return nt, nil + } for k, v := range t.tmpl { - if k == t.name { // Already installed. + if k == t.name { + nt.tmpl[t.name] = nt continue } // The associated templates share nt's common structure. tmpl := v.copy(nt.common) nt.tmpl[k] = tmpl } + t.muFuncs.RLock() + defer t.muFuncs.RUnlock() for k, v := range t.parseFuncs { nt.parseFuncs[k] = v } @@ -102,20 +115,27 @@ func (t *Template) copy(c *common) *Template { return nt } -// AddParseTree creates a new template with the name and parse tree -// and associates it with t. +// AddParseTree adds parse tree for template with given name and associates it with t. +// If the template does not already exist, it will create a new one. +// It is an error to reuse a name except to overwrite an empty template. func (t *Template) AddParseTree(name string, tree *parse.Tree) (*Template, error) { - if t.common != nil && t.tmpl[name] != nil { - return nil, fmt.Errorf("template: redefinition of template %q", name) + t.init() + // If the name is the name of this template, overwrite this template. + // The associate method checks it's not a redefinition. + nt := t + if name != t.name { + nt = t.New(name) + } + // Even if nt == t, we need to install it in the common.tmpl map. + if replace, err := t.associate(nt, tree); err != nil { + return nil, err + } else if replace { + nt.Tree = tree } - nt := t.New(name) - nt.Tree = tree - t.tmpl[name] = nt return nt, nil } -// Templates returns a slice of the templates associated with t, including t -// itself. +// Templates returns a slice of defined templates associated with t. func (t *Template) Templates() []*Template { if t.common == nil { return nil @@ -134,6 +154,7 @@ func (t *Template) Templates() []*Template { // corresponding default: {{ or }}. // The return value is the template, so calls can be chained. func (t *Template) Delims(left, right string) *Template { + t.init() t.leftDelim = left t.rightDelim = right return t @@ -145,13 +166,15 @@ func (t *Template) Delims(left, right string) *Template { // value is the template, so calls can be chained. func (t *Template) Funcs(funcMap FuncMap) *Template { t.init() + t.muFuncs.Lock() + defer t.muFuncs.Unlock() addValueFuncs(t.execFuncs, funcMap) addFuncs(t.parseFuncs, funcMap) return t } -// Lookup returns the template with the given name that is associated with t, -// or nil if there is no such template. +// Lookup returns the template with the given name that is associated with t. +// It returns nil if there is no such template or the template has no definition. func (t *Template) Lookup(name string) *Template { if t.common == nil { return nil @@ -159,7 +182,7 @@ func (t *Template) Lookup(name string) *Template { return t.tmpl[name] } -// Parse parses a string into a template. Nested template definitions will be +// Parse defines the template by parsing the text. Nested template definitions will be // associated with the top-level template t. Parse may be called multiple times // to parse definitions of templates to associate with t. It is an error if a // resulting template is non-empty (contains content other than template @@ -168,26 +191,17 @@ func (t *Template) Lookup(name string) *Template { // can contain text other than space, comments, and template definitions.) func (t *Template) Parse(text string) (*Template, error) { t.init() + t.muFuncs.RLock() trees, err := parse.Parse(t.name, text, t.leftDelim, t.rightDelim, t.parseFuncs, builtins) + t.muFuncs.RUnlock() if err != nil { return nil, err } // Add the newly parsed trees, including the one for t, into our common structure. for name, tree := range trees { - // If the name we parsed is the name of this template, overwrite this template. - // The associate method checks it's not a redefinition. - tmpl := t - if name != t.name { - tmpl = t.New(name) - } - // Even if t == tmpl, we need to install it in the common.tmpl map. - if replace, err := t.associate(tmpl, tree); err != nil { + if _, err := t.AddParseTree(name, tree); err != nil { return nil, err - } else if replace { - tmpl.Tree = tree } - tmpl.leftDelim = t.leftDelim - tmpl.rightDelim = t.rightDelim } return t, nil } diff --git a/libgo/go/time/example_test.go b/libgo/go/time/example_test.go index a37e8b86ddc..f76fdcd4d03 100644 --- a/libgo/go/time/example_test.go +++ b/libgo/go/time/example_test.go @@ -58,17 +58,127 @@ func ExampleDate() { } func ExampleTime_Format() { - // layout shows by example how the reference time should be represented. - const layout = "Jan 2, 2006 at 3:04pm (MST)" - t := time.Date(2009, time.November, 10, 15, 0, 0, 0, time.Local) - fmt.Println(t.Format(layout)) - fmt.Println(t.UTC().Format(layout)) + // Parse a time value from a string in the standard Unix format. + t, err := time.Parse(time.UnixDate, "Sat Mar 7 11:06:39 PST 2015") + if err != nil { // Always check errors even if they should not happen. + panic(err) + } + + // time.Time's Stringer method is useful without any format. + fmt.Println("default format:", t) + + // Predefined constants in the package implement common layouts. + fmt.Println("Unix format:", t.Format(time.UnixDate)) + + // The time zone attached to the time value affects its output. + fmt.Println("Same, in UTC:", t.UTC().Format(time.UnixDate)) + + // The rest of this function demonstrates the properties of the + // layout string used in the format. + + // The layout string used by the Parse function and Format method + // shows by example how the reference time should be represented. + // We stress that one must show how the reference time is formatted, + // not a time of the user's choosing. Thus each layout string is a + // representation of the time stamp, + // Jan 2 15:04:05 2006 MST + // An easy way to remember this value is that it holds, when presented + // in this order, the values (lined up with the elements above): + // 1 2 3 4 5 6 -7 + // There are some wrinkles illustrated below. + + // Most uses of Format and Parse use constant layout strings such as + // the ones defined in this package, but the interface is flexible, + // as these examples show. + + // Define a helper function to make the examples' output look nice. + do := func(name, layout, want string) { + got := t.Format(layout) + if want != got { + fmt.Printf("error: for %q got %q; expected %q\n", layout, got, want) + return + } + fmt.Printf("%-15s %q gives %q\n", name, layout, got) + } + + // Print a header in our output. + fmt.Printf("\nFormats:\n\n") + + // A simple starter example. + do("Basic", "Mon Jan 2 15:04:05 MST 2006", "Sat Mar 7 11:06:39 PST 2015") + + // For fixed-width printing of values, such as the date, that may be one or + // two characters (7 vs. 07), use an _ instead of a space in the layout string. + // Here we print just the day, which is 2 in our layout string and 7 in our + // value. + do("No pad", "<2>", "<7>") + + // An underscore represents a zero pad, if required. + do("Spaces", "<_2>", "< 7>") + + // Similarly, a 0 indicates zero padding. + do("Zeros", "<02>", "<07>") + + // If the value is already the right width, padding is not used. + // For instance, the second (05 in the reference time) in our value is 39, + // so it doesn't need padding, but the minutes (04, 06) does. + do("Suppressed pad", "04:05", "06:39") + + // The predefined constant Unix uses an underscore to pad the day. + // Compare with our simple starter example. + do("Unix", time.UnixDate, "Sat Mar 7 11:06:39 PST 2015") + + // The hour of the reference time is 15, or 3PM. The layout can express + // it either way, and since our value is the morning we should see it as + // an AM time. We show both in one format string. Lower case too. + do("AM/PM", "3PM==3pm==15h", "11AM==11am==11h") + + // When parsing, if the seconds value is followed by a decimal point + // and some digits, that is taken as a fraction of a second even if + // the layout string does not represent the fractional second. + // Here we add a fractional second to our time value used above. + t, err = time.Parse(time.UnixDate, "Sat Mar 7 11:06:39.1234 PST 2015") + if err != nil { + panic(err) + } + // It does not appear in the output if the layout string does not contain + // a representation of the fractional second. + do("No fraction", time.UnixDate, "Sat Mar 7 11:06:39 PST 2015") + + // Fractional seconds can be printed by adding a run of 0s or 9s after + // a decimal point in the seconds value in the layout string. + // If the layout digits are 0s, the fractional second is of the specified + // width. Note that the output has a trailing zero. + do("0s for fraction", "15:04:05.00000", "11:06:39.12340") + + // If the fraction in the layout is 9s, trailing zeros are dropped. + do("9s for fraction", "15:04:05.99999999", "11:06:39.1234") + // Output: - // Nov 10, 2009 at 3:00pm (PST) - // Nov 10, 2009 at 11:00pm (UTC) + // default format: 2015-03-07 11:06:39 -0800 PST + // Unix format: Sat Mar 7 11:06:39 PST 2015 + // Same, in UTC: Sat Mar 7 19:06:39 UTC 2015 + // + // Formats: + // + // Basic "Mon Jan 2 15:04:05 MST 2006" gives "Sat Mar 7 11:06:39 PST 2015" + // No pad "<2>" gives "<7>" + // Spaces "<_2>" gives "< 7>" + // Zeros "<02>" gives "<07>" + // Suppressed pad "04:05" gives "06:39" + // Unix "Mon Jan _2 15:04:05 MST 2006" gives "Sat Mar 7 11:06:39 PST 2015" + // AM/PM "3PM==3pm==15h" gives "11AM==11am==11h" + // No fraction "Mon Jan _2 15:04:05 MST 2006" gives "Sat Mar 7 11:06:39 PST 2015" + // 0s for fraction "15:04:05.00000" gives "11:06:39.12340" + // 9s for fraction "15:04:05.99999999" gives "11:06:39.1234" + } func ExampleParse() { + // See the example for time.Format for a thorough description of how + // to define the layout string to parse a time.Time value; Parse and + // Format use the same model to describe their input and output. + // longForm shows by example how the reference time would be represented in // the desired layout. const longForm = "Jan 2, 2006 at 3:04pm (MST)" diff --git a/libgo/go/time/format.go b/libgo/go/time/format.go index 04e79f32dcd..873d3ffde91 100644 --- a/libgo/go/time/format.go +++ b/libgo/go/time/format.go @@ -39,6 +39,9 @@ import "errors" // offset for the UTC zone. Thus: // Z0700 Z or ±hhmm // Z07:00 Z or ±hh:mm +// +// The executable example for time.Format demonstrates the working +// of the layout string in detail and is a good reference. const ( ANSIC = "Mon Jan _2 15:04:05 2006" UnixDate = "Mon Jan _2 15:04:05 MST 2006" @@ -288,7 +291,7 @@ var longMonthNames = []string{ "December", } -// match returns true if s1 and s2 match ignoring case. +// match reports whether s1 and s2 match ignoring case. // It is assumed s1 and s2 are the same length. func match(s1, s2 string) bool { for i := 0; i < len(s1); i++ { @@ -315,36 +318,34 @@ func lookup(tab []string, val string) (int, string, error) { return -1, val, errBad } -// appendUint appends the decimal form of x to b and returns the result. -// If x is a single-digit number and pad != 0, appendUint inserts the pad byte -// before the digit. +// appendInt appends the decimal form of x to b and returns the result. +// If the decimal form (excluding sign) is shorter than width, the result is padded with leading 0's. // Duplicates functionality in strconv, but avoids dependency. -func appendUint(b []byte, x uint, pad byte) []byte { - if x < 10 { - if pad != 0 { - b = append(b, pad) - } - return append(b, byte('0'+x)) - } - if x < 100 { - b = append(b, byte('0'+x/10)) - b = append(b, byte('0'+x%10)) - return b +func appendInt(b []byte, x int, width int) []byte { + u := uint(x) + if x < 0 { + b = append(b, '-') + u = uint(-x) } - var buf [32]byte - n := len(buf) - if x == 0 { - return append(b, '0') + // Assemble decimal in reverse order. + var buf [20]byte + i := len(buf) + for u >= 10 { + i-- + q := u / 10 + buf[i] = byte('0' + u - q*10) + u = q } - for x >= 10 { - n-- - buf[n] = byte(x%10 + '0') - x /= 10 + i-- + buf[i] = byte('0' + u) + + // Add 0-padding. + for w := len(buf) - i; w < width; w++ { + b = append(b, '0') } - n-- - buf[n] = byte(x + '0') - return append(b, buf[n:]...) + + return append(b, buf[i:]...) } // Never printed, just needs to be non-nil for return by atoi. @@ -407,11 +408,32 @@ func (t Time) String() string { // would be displayed if it were the value; it serves as an example of the // desired output. The same display rules will then be applied to the time // value. +// +// A fractional second is represented by adding a period and zeros +// to the end of the seconds section of layout string, as in "15:04:05.000" +// to format a time stamp with millisecond precision. +// // Predefined layouts ANSIC, UnixDate, RFC3339 and others describe standard // and convenient representations of the reference time. For more information // about the formats and the definition of the reference time, see the // documentation for ANSIC and the other constants defined by this package. func (t Time) Format(layout string) string { + const bufSize = 64 + var b []byte + max := len(layout) + 10 + if max < bufSize { + var buf [bufSize]byte + b = buf[:0] + } else { + b = make([]byte, 0, max) + } + b = t.AppendFormat(b, layout) + return string(b) +} + +// AppendFormat is like Format but appends the textual +// representation to b and returns the extended buffer. +func (t Time) AppendFormat(b []byte, layout string) []byte { var ( name, offset, abs = t.locabs() @@ -421,16 +443,7 @@ func (t Time) Format(layout string) string { hour int = -1 min int sec int - - b []byte - buf [64]byte ) - max := len(layout) + 10 - if max <= len(buf) { - b = buf[:0] - } else { - b = make([]byte, 0, max) - } // Each iteration generates one std value. for layout != "" { prefix, std, suffix := nextStdChunk(layout) @@ -458,75 +471,56 @@ func (t Time) Format(layout string) string { if y < 0 { y = -y } - b = appendUint(b, uint(y%100), '0') + b = appendInt(b, y%100, 2) case stdLongYear: - // Pad year to at least 4 digits. - y := year - switch { - case year <= -1000: - b = append(b, '-') - y = -y - case year <= -100: - b = append(b, "-0"...) - y = -y - case year <= -10: - b = append(b, "-00"...) - y = -y - case year < 0: - b = append(b, "-000"...) - y = -y - case year < 10: - b = append(b, "000"...) - case year < 100: - b = append(b, "00"...) - case year < 1000: - b = append(b, '0') - } - b = appendUint(b, uint(y), 0) + b = appendInt(b, year, 4) case stdMonth: b = append(b, month.String()[:3]...) case stdLongMonth: m := month.String() b = append(b, m...) case stdNumMonth: - b = appendUint(b, uint(month), 0) + b = appendInt(b, int(month), 0) case stdZeroMonth: - b = appendUint(b, uint(month), '0') + b = appendInt(b, int(month), 2) case stdWeekDay: b = append(b, absWeekday(abs).String()[:3]...) case stdLongWeekDay: s := absWeekday(abs).String() b = append(b, s...) case stdDay: - b = appendUint(b, uint(day), 0) + b = appendInt(b, day, 0) case stdUnderDay: - b = appendUint(b, uint(day), ' ') + if day < 10 { + b = append(b, ' ') + } + b = appendInt(b, day, 0) case stdZeroDay: - b = appendUint(b, uint(day), '0') + b = appendInt(b, day, 2) case stdHour: - b = appendUint(b, uint(hour), '0') + b = appendInt(b, hour, 2) case stdHour12: // Noon is 12PM, midnight is 12AM. hr := hour % 12 if hr == 0 { hr = 12 } - b = appendUint(b, uint(hr), 0) + b = appendInt(b, hr, 0) case stdZeroHour12: // Noon is 12PM, midnight is 12AM. hr := hour % 12 if hr == 0 { hr = 12 } - b = appendUint(b, uint(hr), '0') + b = appendInt(b, hr, 2) case stdMinute: - b = appendUint(b, uint(min), 0) + b = appendInt(b, min, 0) case stdZeroMinute: - b = appendUint(b, uint(min), '0') + b = appendInt(b, min, 2) case stdSecond: - b = appendUint(b, uint(sec), 0) + b = appendInt(b, sec, 2) case stdZeroSecond: - b = appendUint(b, uint(sec), '0') + b = appendInt(b, sec, 2) case stdPM: if hour >= 12 { b = append(b, "PM"...) @@ -555,18 +549,18 @@ func (t Time) Format(layout string) string { } else { b = append(b, '+') } - b = appendUint(b, uint(zone/60), '0') + b = appendInt(b, zone/60, 2) if std == stdISO8601ColonTZ || std == stdNumColonTZ || std == stdISO8601ColonSecondsTZ || std == stdNumColonSecondsTZ { b = append(b, ':') } - b = appendUint(b, uint(zone%60), '0') + b = appendInt(b, zone%60, 2) // append seconds if appropriate if std == stdISO8601SecondsTZ || std == stdNumSecondsTz || std == stdNumColonSecondsTZ || std == stdISO8601ColonSecondsTZ { if std == stdNumColonSecondsTZ || std == stdISO8601ColonSecondsTZ { b = append(b, ':') } - b = appendUint(b, uint(absoffset%60), '0') + b = appendInt(b, absoffset%60, 2) } case stdTZ: @@ -583,13 +577,13 @@ func (t Time) Format(layout string) string { } else { b = append(b, '+') } - b = appendUint(b, uint(zone/60), '0') - b = appendUint(b, uint(zone%60), '0') + b = appendInt(b, zone/60, 2) + b = appendInt(b, zone%60, 2) case stdFracSecond0, stdFracSecond9: b = formatNano(b, uint(t.Nanosecond()), std>>stdArgShift, std&stdMask == stdFracSecond9) } } - return string(b) + return b } var errBad = errors.New("bad value for field") // placeholder not passed to user @@ -620,8 +614,7 @@ func (e *ParseError) Error() string { quote(e.Value) + e.Message } -// isDigit returns true if s[i] is a decimal digit, false if not or -// if s[i] is out of range. +// isDigit reports whether s[i] is in range and is a decimal digit. func isDigit(s string, i int) bool { if len(s) <= i { return false @@ -681,10 +674,13 @@ func skip(value, prefix string) (string, error) { // would be interpreted if it were the value; it serves as an example of // the input format. The same interpretation will then be made to the // input string. +// // Predefined layouts ANSIC, UnixDate, RFC3339 and others describe standard // and convenient representations of the reference time. For more information // about the formats and the definition of the reference time, see the // documentation for ANSIC and the other constants defined by this package. +// Also, the executable example for time.Format demonstrates the working +// of the layout string in detail and is a good reference. // // Elements omitted from the value are assumed to be zero or, when // zero is impossible, one, so parsing "3:04pm" returns the time @@ -1131,24 +1127,28 @@ func leadingInt(s string) (x int64, rem string, err error) { if c < '0' || c > '9' { break } - if x >= (1<<63-10)/10 { + if x > (1<<63-1)/10 { // overflow return 0, "", errLeadingInt } x = x*10 + int64(c) - '0' + if x < 0 { + // overflow + return 0, "", errLeadingInt + } } return x, s[i:], nil } -var unitMap = map[string]float64{ - "ns": float64(Nanosecond), - "us": float64(Microsecond), - "µs": float64(Microsecond), // U+00B5 = micro symbol - "μs": float64(Microsecond), // U+03BC = Greek letter mu - "ms": float64(Millisecond), - "s": float64(Second), - "m": float64(Minute), - "h": float64(Hour), +var unitMap = map[string]int64{ + "ns": int64(Nanosecond), + "us": int64(Microsecond), + "µs": int64(Microsecond), // U+00B5 = micro symbol + "μs": int64(Microsecond), // U+03BC = Greek letter mu + "ms": int64(Millisecond), + "s": int64(Second), + "m": int64(Minute), + "h": int64(Hour), } // ParseDuration parses a duration string. @@ -1159,7 +1159,7 @@ var unitMap = map[string]float64{ func ParseDuration(s string) (Duration, error) { // [-+]?([0-9]*(\.[0-9]*)?[a-z]+)+ orig := s - f := float64(0) + var d int64 neg := false // Consume [-+]? @@ -1178,22 +1178,23 @@ func ParseDuration(s string) (Duration, error) { return 0, errors.New("time: invalid duration " + orig) } for s != "" { - g := float64(0) // this element of the sequence + var ( + v, f int64 // integers before, after decimal point + scale float64 = 1 // value = v + f/scale + ) - var x int64 var err error // The next character must be [0-9.] - if !(s[0] == '.' || ('0' <= s[0] && s[0] <= '9')) { + if !(s[0] == '.' || '0' <= s[0] && s[0] <= '9') { return 0, errors.New("time: invalid duration " + orig) } // Consume [0-9]* pl := len(s) - x, s, err = leadingInt(s) + v, s, err = leadingInt(s) if err != nil { return 0, errors.New("time: invalid duration " + orig) } - g = float64(x) pre := pl != len(s) // whether we consumed anything before a period // Consume (\.[0-9]*)? @@ -1201,15 +1202,13 @@ func ParseDuration(s string) (Duration, error) { if s != "" && s[0] == '.' { s = s[1:] pl := len(s) - x, s, err = leadingInt(s) + f, s, err = leadingInt(s) if err != nil { return 0, errors.New("time: invalid duration " + orig) } - scale := 1.0 for n := pl - len(s); n > 0; n-- { scale *= 10 } - g += float64(x) / scale post = pl != len(s) } if !pre && !post { @@ -1221,7 +1220,7 @@ func ParseDuration(s string) (Duration, error) { i := 0 for ; i < len(s); i++ { c := s[i] - if c == '.' || ('0' <= c && c <= '9') { + if c == '.' || '0' <= c && c <= '9' { break } } @@ -1234,15 +1233,29 @@ func ParseDuration(s string) (Duration, error) { if !ok { return 0, errors.New("time: unknown unit " + u + " in duration " + orig) } - - f += g * unit + if v > (1<<63-1)/unit { + // overflow + return 0, errors.New("time: invalid duration " + orig) + } + v *= unit + if f > 0 { + // float64 is needed to be nanosecond accurate for fractions of hours. + // v >= 0 && (f*unit/scale) <= 3.6e+12 (ns/h, h is the largest unit) + v += int64(float64(f) * (float64(unit) / scale)) + if v < 0 { + // overflow + return 0, errors.New("time: invalid duration " + orig) + } + } + d += v + if d < 0 { + // overflow + return 0, errors.New("time: invalid duration " + orig) + } } if neg { - f = -f - } - if f < float64(-1<<63) || f > float64(1<<63-1) { - return 0, errors.New("time: overflow parsing duration") + d = -d } - return Duration(f), nil + return Duration(d), nil } diff --git a/libgo/go/time/sleep_test.go b/libgo/go/time/sleep_test.go index c21eb997dc4..c286bd00273 100644 --- a/libgo/go/time/sleep_test.go +++ b/libgo/go/time/sleep_test.go @@ -8,7 +8,6 @@ import ( "errors" "fmt" "runtime" - "sort" "strings" "sync" "sync/atomic" @@ -224,10 +223,11 @@ func TestAfterStop(t *testing.T) { func TestAfterQueuing(t *testing.T) { // This test flakes out on some systems, // so we'll try it a few times before declaring it a failure. - const attempts = 3 + const attempts = 5 err := errors.New("!=nil") for i := 0; i < attempts && err != nil; i++ { - if err = testAfterQueuing(t); err != nil { + delta := Duration(20+i*50) * Millisecond + if err = testAfterQueuing(t, delta); err != nil { t.Logf("attempt %v failed: %v", i, err) } } @@ -248,11 +248,7 @@ func await(slot int, result chan<- afterResult, ac <-chan Time) { result <- afterResult{slot, <-ac} } -func testAfterQueuing(t *testing.T) error { - Delta := 100 * Millisecond - if testing.Short() { - Delta = 20 * Millisecond - } +func testAfterQueuing(t *testing.T, delta Duration) error { // make the result channel buffered because we don't want // to depend on channel queueing semantics that might // possibly change in the future. @@ -260,18 +256,25 @@ func testAfterQueuing(t *testing.T) error { t0 := Now() for _, slot := range slots { - go await(slot, result, After(Duration(slot)*Delta)) + go await(slot, result, After(Duration(slot)*delta)) } - sort.Ints(slots) - for _, slot := range slots { + var order []int + var times []Time + for range slots { r := <-result - if r.slot != slot { - return fmt.Errorf("after slot %d, expected %d", r.slot, slot) + order = append(order, r.slot) + times = append(times, r.t) + } + for i := range order { + if i > 0 && order[i] < order[i-1] { + return fmt.Errorf("After calls returned out of order: %v", order) } - dt := r.t.Sub(t0) - target := Duration(slot) * Delta - if dt < target-Delta/2 || dt > target+Delta*10 { - return fmt.Errorf("After(%s) arrived at %s, expected [%s,%s]", target, dt, target-Delta/2, target+Delta*10) + } + for i, t := range times { + dt := t.Sub(t0) + target := Duration(order[i]) * delta + if dt < target-delta/2 || dt > target+delta*10 { + return fmt.Errorf("After(%s) arrived at %s, expected [%s,%s]", target, dt, target-delta/2, target+delta*10) } } return nil @@ -384,6 +387,10 @@ func TestOverflowSleep(t *testing.T) { // Test that a panic while deleting a timer does not leave // the timers mutex held, deadlocking a ticker.Stop in a defer. func TestIssue5745(t *testing.T) { + if runtime.GOOS == "darwin" && runtime.GOARCH == "arm" { + t.Skipf("skipping on %s/%s, see issue 10043", runtime.GOOS, runtime.GOARCH) + } + ticker := NewTicker(Hour) defer func() { // would deadlock here before the fix due to diff --git a/libgo/go/time/sys_unix.go b/libgo/go/time/sys_unix.go index 379e13d6a53..e592415daa5 100644 --- a/libgo/go/time/sys_unix.go +++ b/libgo/go/time/sys_unix.go @@ -74,3 +74,5 @@ func preadn(fd uintptr, buf []byte, off int) error { } return nil } + +func isNotExist(err error) bool { return err == syscall.ENOENT } diff --git a/libgo/go/time/tick.go b/libgo/go/time/tick.go index 19007841e1a..196e8ac61a6 100644 --- a/libgo/go/time/tick.go +++ b/libgo/go/time/tick.go @@ -47,7 +47,9 @@ func (t *Ticker) Stop() { } // Tick is a convenience wrapper for NewTicker providing access to the ticking -// channel only. Useful for clients that have no need to shut down the ticker. +// channel only. While Tick is useful for clients that have no need to shut down +// the Ticker, be aware that without a way to shut it down the underlying +// Ticker cannot be recovered by the garbage collector; it "leaks". func Tick(d Duration) <-chan Time { if d <= 0 { return nil diff --git a/libgo/go/time/time.go b/libgo/go/time/time.go index 0300e846a4b..294cc77f417 100644 --- a/libgo/go/time/time.go +++ b/libgo/go/time/time.go @@ -966,6 +966,8 @@ func (t *Time) UnmarshalText(data []byte) (err error) { // Unix returns the local Time corresponding to the given Unix time, // sec seconds and nsec nanoseconds since January 1, 1970 UTC. // It is valid to pass nsec outside the range [0, 999999999]. +// Not all sec values have a corresponding time value. One such +// value is 1<<63-1 (the largest int64 value). func Unix(sec int64, nsec int64) Time { if nsec < 0 || nsec >= 1e9 { n := nsec / 1e9 diff --git a/libgo/go/time/time_test.go b/libgo/go/time/time_test.go index 7e31dd78a92..2d16ea59ae3 100644 --- a/libgo/go/time/time_test.go +++ b/libgo/go/time/time_test.go @@ -830,8 +830,16 @@ var parseDurationTests = []struct { {"39h9m14.425s", true, 39*Hour + 9*Minute + 14*Second + 425*Millisecond}, // large value {"52763797000ns", true, 52763797000 * Nanosecond}, - // more than 9 digits after decimal point, see http://golang.org/issue/6617 + // more than 9 digits after decimal point, see https://golang.org/issue/6617 {"0.3333333333333333333h", true, 20 * Minute}, + // 9007199254740993 = 1<<53+1 cannot be stored precisely in a float64 + {"9007199254740993ns", true, (1<<53 + 1) * Nanosecond}, + // largest duration that can be represented by int64 in nanoseconds + {"9223372036854775807ns", true, (1<<63 - 1) * Nanosecond}, + {"9223372036854775.807us", true, (1<<63 - 1) * Nanosecond}, + {"9223372036s854ms775us807ns", true, (1<<63 - 1) * Nanosecond}, + // large negative value + {"-9223372036854775807ns", true, -1<<63 + 1*Nanosecond}, // errors {"", false, 0}, @@ -842,7 +850,13 @@ var parseDurationTests = []struct { {"-.", false, 0}, {".s", false, 0}, {"+.s", false, 0}, - {"3000000h", false, 0}, // overflow + {"3000000h", false, 0}, // overflow + {"9223372036854775808ns", false, 0}, // overflow + {"9223372036854775.808us", false, 0}, // overflow + {"9223372036854ms775us808ns", false, 0}, // overflow + // largest negative value of type int64 in nanoseconds should fail + // see https://go-review.googlesource.com/#/c/2461/ + {"-9223372036854775808ns", false, 0}, } func TestParseDuration(t *testing.T) { @@ -1052,6 +1066,13 @@ func BenchmarkParse(b *testing.B) { } } +func BenchmarkParseDuration(b *testing.B) { + for i := 0; i < b.N; i++ { + ParseDuration("9007199254.740993ms") + ParseDuration("9007199254740993ns") + } +} + func BenchmarkHour(b *testing.B) { t := Now() for i := 0; i < b.N; i++ { diff --git a/libgo/go/time/zoneinfo_ios.go b/libgo/go/time/zoneinfo_ios.go new file mode 100644 index 00000000000..f09166c89e9 --- /dev/null +++ b/libgo/go/time/zoneinfo_ios.go @@ -0,0 +1,51 @@ +// Copyright 2015 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin +// +build arm arm64 + +package time + +import "syscall" + +var zoneFile string + +func init() { + wd, err := syscall.Getwd() + if err != nil { + return + } + + // The working directory at initialization is the root of the + // app bundle: "/private/.../bundlename.app". That's where we + // keep zoneinfo.zip. + zoneFile = wd + "/zoneinfo.zip" +} + +func forceZipFileForTesting(zipOnly bool) { + // On iOS we only have the zip file. +} + +func initTestingZone() { + z, err := loadZoneFile(zoneFile, "America/Los_Angeles") + if err != nil { + panic("cannot load America/Los_Angeles for testing: " + err.Error()) + } + z.name = "Local" + localLoc = *z +} + +func initLocal() { + // TODO(crawshaw): [NSTimeZone localTimeZone] + localLoc = *UTC +} + +func loadLocation(name string) (*Location, error) { + z, err := loadZoneFile(zoneFile, name) + if err != nil { + return nil, err + } + z.name = name + return z, nil +} diff --git a/libgo/go/time/zoneinfo_plan9.go b/libgo/go/time/zoneinfo_plan9.go index 4bb0cb39096..0694f0a9904 100644 --- a/libgo/go/time/zoneinfo_plan9.go +++ b/libgo/go/time/zoneinfo_plan9.go @@ -7,7 +7,6 @@ package time import ( - "errors" "runtime" "syscall" ) @@ -148,11 +147,12 @@ func initLocal() { } func loadLocation(name string) (*Location, error) { - if z, err := loadZoneFile(runtime.GOROOT()+"/lib/time/zoneinfo.zip", name); err == nil { - z.name = name - return z, nil + z, err := loadZoneFile(runtime.GOROOT()+"/lib/time/zoneinfo.zip", name) + if err != nil { + return nil, err } - return nil, errors.New("unknown time zone " + name) + z.name = name + return z, nil } func forceZipFileForTesting(zipOnly bool) { diff --git a/libgo/go/time/zoneinfo_unix.go b/libgo/go/time/zoneinfo_unix.go index 3fe8e55795c..5fc669e478d 100644 --- a/libgo/go/time/zoneinfo_unix.go +++ b/libgo/go/time/zoneinfo_unix.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris +// +build darwin,386 darwin,amd64 dragonfly freebsd linux nacl netbsd openbsd solaris // Parse "zoneinfo" time zone file. // This is a fairly standard file format used on OS X, Linux, BSD, Sun, and others. @@ -70,11 +70,17 @@ func initLocal() { } func loadLocation(name string) (*Location, error) { + var firstErr error for _, zoneDir := range zoneDirs { if z, err := loadZoneFile(zoneDir, name); err == nil { z.name = name return z, nil + } else if firstErr == nil && !isNotExist(err) { + firstErr = err } } + if firstErr != nil { + return nil, firstErr + } return nil, errors.New("unknown time zone " + name) } diff --git a/libgo/go/time/zoneinfo_windows.go b/libgo/go/time/zoneinfo_windows.go index 02d8e0edcc8..d04ebec614e 100644 --- a/libgo/go/time/zoneinfo_windows.go +++ b/libgo/go/time/zoneinfo_windows.go @@ -6,9 +6,9 @@ package time import ( "errors" + "internal/syscall/windows/registry" "runtime" "syscall" - "unsafe" ) //go:generate go run genzabbrs.go -output zoneinfo_abbrs_windows.go @@ -20,39 +20,23 @@ import ( // The implementation assumes that this year's rules for daylight savings // time apply to all previous and future years as well. -// getKeyValue retrieves the string value kname associated with the open registry key kh. -func getKeyValue(kh syscall.Handle, kname string) (string, error) { - var buf [50]uint16 // buf needs to be large enough to fit zone descriptions - var typ uint32 - n := uint32(len(buf) * 2) // RegQueryValueEx's signature expects array of bytes, not uint16 - p, _ := syscall.UTF16PtrFromString(kname) - if err := syscall.RegQueryValueEx(kh, p, nil, &typ, (*byte)(unsafe.Pointer(&buf[0])), &n); err != nil { - return "", err - } - if typ != syscall.REG_SZ { // null terminated strings only - return "", errors.New("Key is not string") - } - return syscall.UTF16ToString(buf[:]), nil -} - // matchZoneKey checks if stdname and dstname match the corresponding "Std" // and "Dlt" key values in the kname key stored under the open registry key zones. -func matchZoneKey(zones syscall.Handle, kname string, stdname, dstname string) (matched bool, err2 error) { - var h syscall.Handle - p, _ := syscall.UTF16PtrFromString(kname) - if err := syscall.RegOpenKeyEx(zones, p, 0, syscall.KEY_READ, &h); err != nil { +func matchZoneKey(zones registry.Key, kname string, stdname, dstname string) (matched bool, err2 error) { + k, err := registry.OpenKey(zones, kname, registry.READ) + if err != nil { return false, err } - defer syscall.RegCloseKey(h) + defer k.Close() - s, err := getKeyValue(h, "Std") + s, _, err := k.GetStringValue("Std") if err != nil { return false, err } if s != stdname { return false, nil } - s, err = getKeyValue(h, "Dlt") + s, _, err = k.GetStringValue("Dlt") if err != nil { return false, err } @@ -65,28 +49,20 @@ func matchZoneKey(zones syscall.Handle, kname string, stdname, dstname string) ( // toEnglishName searches the registry for an English name of a time zone // whose zone names are stdname and dstname and returns the English name. func toEnglishName(stdname, dstname string) (string, error) { - var zones syscall.Handle - p, _ := syscall.UTF16PtrFromString(`SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones`) - if err := syscall.RegOpenKeyEx(syscall.HKEY_LOCAL_MACHINE, p, 0, syscall.KEY_READ, &zones); err != nil { + k, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones`, registry.ENUMERATE_SUB_KEYS|registry.QUERY_VALUE) + if err != nil { return "", err } - defer syscall.RegCloseKey(zones) + defer k.Close() - var count uint32 - if err := syscall.RegQueryInfoKey(zones, nil, nil, nil, &count, nil, nil, nil, nil, nil, nil, nil); err != nil { + names, err := k.ReadSubKeyNames(-1) + if err != nil { return "", err } - - var buf [50]uint16 // buf needs to be large enough to fit zone descriptions - for i := uint32(0); i < count; i++ { - n := uint32(len(buf)) - if syscall.RegEnumKeyEx(zones, i, &buf[0], &n, nil, nil, nil, nil) != nil { - continue - } - kname := syscall.UTF16ToString(buf[:]) - matched, err := matchZoneKey(zones, kname, stdname, dstname) + for _, name := range names { + matched, err := matchZoneKey(k, name, stdname, dstname) if err == nil && matched { - return kname, nil + return name, nil } } return "", errors.New(`English name for time zone "` + stdname + `" not found in registry`) @@ -260,11 +236,12 @@ func initLocal() { } func loadLocation(name string) (*Location, error) { - if z, err := loadZoneFile(runtime.GOROOT()+`\lib\time\zoneinfo.zip`, name); err == nil { - z.name = name - return z, nil + z, err := loadZoneFile(runtime.GOROOT()+`\lib\time\zoneinfo.zip`, name) + if err != nil { + return nil, err } - return nil, errors.New("unknown time zone " + name) + z.name = name + return z, nil } func forceZipFileForTesting(zipOnly bool) { diff --git a/libgo/go/unicode/graphic.go b/libgo/go/unicode/graphic.go index ba90b4e5189..81eae3e7623 100644 --- a/libgo/go/unicode/graphic.go +++ b/libgo/go/unicode/graphic.go @@ -82,7 +82,7 @@ func IsControl(r rune) bool { if uint32(r) <= MaxLatin1 { return properties[uint8(r)]&pC != 0 } - // All control characters are < Latin1Max. + // All control characters are < MaxLatin1. return false } diff --git a/libgo/go/unicode/letter_test.go b/libgo/go/unicode/letter_test.go index 4ee11fb364f..a40b412f66d 100644 --- a/libgo/go/unicode/letter_test.go +++ b/libgo/go/unicode/letter_test.go @@ -24,6 +24,7 @@ var upperTest = []rune{ 0x181, 0x376, 0x3cf, + 0x13bd, 0x1f2a, 0x2102, 0x2c00, @@ -46,6 +47,7 @@ var notupperTest = []rune{ 0x377, 0x387, 0x2150, + 0xab7d, 0xffff, 0x10000, } @@ -194,6 +196,15 @@ var caseTest = []caseT{ {LowerCase, 0x0148, 0x0148}, {TitleCase, 0x0148, 0x0147}, + // Lowercase lower than uppercase. + // AB78;CHEROKEE SMALL LETTER GE;Ll;0;L;;;;;N;;;13A8;;13A8 + {UpperCase, 0xab78, 0x13a8}, + {LowerCase, 0xab78, 0xab78}, + {TitleCase, 0xab78, 0x13a8}, + {UpperCase, 0x13a8, 0x13a8}, + {LowerCase, 0x13a8, 0xab78}, + {TitleCase, 0x13a8, 0x13a8}, + // Last block in the 5.1.0 table // 10400;DESERET CAPITAL LETTER LONG I;Lu;0;L;;;;;N;;;;10428; {UpperCase, 0x10400, 0x10400}, @@ -405,6 +416,9 @@ var simpleFoldTests = []string{ // Extra special cases: has lower/upper but no case fold. "İ", "ı", + + // Upper comes before lower (Cherokee). + "\u13b0\uab80", } func TestSimpleFold(t *testing.T) { diff --git a/libgo/go/unicode/script_test.go b/libgo/go/unicode/script_test.go index 795cb4e171b..935c225c376 100644 --- a/libgo/go/unicode/script_test.go +++ b/libgo/go/unicode/script_test.go @@ -14,9 +14,11 @@ type T struct { script string } -// Hand-chosen tests from Unicode 5.1.0, 6.0.0, 6.2.0, 6.3.0 and 7.0.0 mostly to -// discover when new scripts and categories arise. +// Hand-chosen tests from Unicode 5.1.0, 6.0.0, 6.2.0, 6.3.0, 7.0.0 and 8.0.0 +// mostly to discover when new scripts and categories arise. var inTest = []T{ + {0x11711, "Ahom"}, + {0x14646, "Anatolian_Hieroglyphs"}, {0x06e2, "Arabic"}, {0x0567, "Armenian"}, {0x10b20, "Avestan"}, @@ -58,6 +60,7 @@ var inTest = []T{ {0x3028, "Han"}, {0x11b8, "Hangul"}, {0x1727, "Hanunoo"}, + {0x108FF, "Hatran"}, {0x05a0, "Hebrew"}, {0x3058, "Hiragana"}, {0x10841, "Imperial_Aramaic"}, @@ -94,12 +97,14 @@ var inTest = []T{ {0x11611, "Modi"}, {0x1822, "Mongolian"}, {0x16a60, "Mro"}, + {0x11293, "Multani"}, {0x104c, "Myanmar"}, {0x10880, "Nabataean"}, {0x19c3, "New_Tai_Lue"}, {0x07f8, "Nko"}, {0x169b, "Ogham"}, {0x1c6a, "Ol_Chiki"}, + {0x10C80, "Old_Hungarian"}, {0x10310, "Old_Italic"}, {0x10a80, "Old_North_Arabian"}, {0x10350, "Old_Permic"}, @@ -121,6 +126,7 @@ var inTest = []T{ {0x111a0, "Sharada"}, {0x10463, "Shavian"}, {0x115c1, "Siddham"}, + {0x1D920, "SignWriting"}, {0x0dbd, "Sinhala"}, {0x110d0, "Sora_Sompeng"}, {0x1ba3, "Sundanese"}, diff --git a/libgo/go/unicode/tables.go b/libgo/go/unicode/tables.go index 8b77dd6036b..370a9d1174d 100644 --- a/libgo/go/unicode/tables.go +++ b/libgo/go/unicode/tables.go @@ -3,13 +3,13 @@ // license that can be found in the LICENSE file. // Generated by running -// maketables --tables=all --data=http://www.unicode.org/Public/7.0.0/ucd/UnicodeData.txt --casefolding=http://www.unicode.org/Public/7.0.0/ucd/CaseFolding.txt +// maketables --tables=all --data=http://www.unicode.org/Public/8.0.0/ucd/UnicodeData.txt --casefolding=http://www.unicode.org/Public/8.0.0/ucd/CaseFolding.txt // DO NOT EDIT package unicode // Version is the Unicode edition from which the tables are derived. -const Version = "7.0.0" +const Version = "8.0.0" // Categories is the set of Unicode category tables. var Categories = map[string]*RangeTable{ @@ -170,7 +170,7 @@ var _L = &RangeTable{ {0x081a, 0x0824, 10}, {0x0828, 0x0840, 24}, {0x0841, 0x0858, 1}, - {0x08a0, 0x08b2, 1}, + {0x08a0, 0x08b4, 1}, {0x0904, 0x0939, 1}, {0x093d, 0x0950, 19}, {0x0958, 0x0961, 1}, @@ -203,7 +203,8 @@ var _L = &RangeTable{ {0x0ab5, 0x0ab9, 1}, {0x0abd, 0x0ad0, 19}, {0x0ae0, 0x0ae1, 1}, - {0x0b05, 0x0b0c, 1}, + {0x0af9, 0x0b05, 12}, + {0x0b06, 0x0b0c, 1}, {0x0b0f, 0x0b10, 1}, {0x0b13, 0x0b28, 1}, {0x0b2a, 0x0b30, 1}, @@ -228,9 +229,9 @@ var _L = &RangeTable{ {0x0c12, 0x0c28, 1}, {0x0c2a, 0x0c39, 1}, {0x0c3d, 0x0c58, 27}, - {0x0c59, 0x0c60, 7}, - {0x0c61, 0x0c85, 36}, - {0x0c86, 0x0c8c, 1}, + {0x0c59, 0x0c5a, 1}, + {0x0c60, 0x0c61, 1}, + {0x0c85, 0x0c8c, 1}, {0x0c8e, 0x0c90, 1}, {0x0c92, 0x0ca8, 1}, {0x0caa, 0x0cb3, 1}, @@ -241,7 +242,7 @@ var _L = &RangeTable{ {0x0d05, 0x0d0c, 1}, {0x0d0e, 0x0d10, 1}, {0x0d12, 0x0d3a, 1}, - {0x0d3d, 0x0d4e, 17}, + {0x0d3d, 0x0d5f, 17}, {0x0d60, 0x0d61, 1}, {0x0d7a, 0x0d7f, 1}, {0x0d85, 0x0d96, 1}, @@ -300,7 +301,8 @@ var _L = &RangeTable{ {0x1312, 0x1315, 1}, {0x1318, 0x135a, 1}, {0x1380, 0x138f, 1}, - {0x13a0, 0x13f4, 1}, + {0x13a0, 0x13f5, 1}, + {0x13f8, 0x13fd, 1}, {0x1401, 0x166c, 1}, {0x166f, 0x167f, 1}, {0x1681, 0x169a, 1}, @@ -322,7 +324,7 @@ var _L = &RangeTable{ {0x1950, 0x196d, 1}, {0x1970, 0x1974, 1}, {0x1980, 0x19ab, 1}, - {0x19c1, 0x19c7, 1}, + {0x19b0, 0x19c9, 1}, {0x1a00, 0x1a16, 1}, {0x1a20, 0x1a54, 1}, {0x1aa7, 0x1b05, 94}, @@ -399,7 +401,7 @@ var _L = &RangeTable{ {0x31a0, 0x31ba, 1}, {0x31f0, 0x31ff, 1}, {0x3400, 0x4db5, 1}, - {0x4e00, 0x9fcc, 1}, + {0x4e00, 0x9fd5, 1}, {0xa000, 0xa48c, 1}, {0xa4d0, 0xa4fd, 1}, {0xa500, 0xa60c, 1}, @@ -410,9 +412,8 @@ var _L = &RangeTable{ {0xa6a0, 0xa6e5, 1}, {0xa717, 0xa71f, 1}, {0xa722, 0xa788, 1}, - {0xa78b, 0xa78e, 1}, - {0xa790, 0xa7ad, 1}, - {0xa7b0, 0xa7b1, 1}, + {0xa78b, 0xa7ad, 1}, + {0xa7b0, 0xa7b7, 1}, {0xa7f7, 0xa801, 1}, {0xa803, 0xa805, 1}, {0xa807, 0xa80a, 1}, @@ -420,8 +421,8 @@ var _L = &RangeTable{ {0xa840, 0xa873, 1}, {0xa882, 0xa8b3, 1}, {0xa8f2, 0xa8f7, 1}, - {0xa8fb, 0xa90a, 15}, - {0xa90b, 0xa925, 1}, + {0xa8fb, 0xa8fd, 2}, + {0xa90a, 0xa925, 1}, {0xa930, 0xa946, 1}, {0xa960, 0xa97c, 1}, {0xa984, 0xa9b2, 1}, @@ -448,9 +449,8 @@ var _L = &RangeTable{ {0xab20, 0xab26, 1}, {0xab28, 0xab2e, 1}, {0xab30, 0xab5a, 1}, - {0xab5c, 0xab5f, 1}, - {0xab64, 0xab65, 1}, - {0xabc0, 0xabe2, 1}, + {0xab5c, 0xab65, 1}, + {0xab70, 0xabe2, 1}, {0xac00, 0xd7a3, 1}, {0xd7b0, 0xd7c6, 1}, {0xd7cb, 0xd7fb, 1}, @@ -511,6 +511,8 @@ var _L = &RangeTable{ {0x10840, 0x10855, 1}, {0x10860, 0x10876, 1}, {0x10880, 0x1089e, 1}, + {0x108e0, 0x108f2, 1}, + {0x108f4, 0x108f5, 1}, {0x10900, 0x10915, 1}, {0x10920, 0x10939, 1}, {0x10980, 0x109b7, 1}, @@ -528,6 +530,8 @@ var _L = &RangeTable{ {0x10b60, 0x10b72, 1}, {0x10b80, 0x10b91, 1}, {0x10c00, 0x10c48, 1}, + {0x10c80, 0x10cb2, 1}, + {0x10cc0, 0x10cf2, 1}, {0x11003, 0x11037, 1}, {0x11083, 0x110af, 1}, {0x110d0, 0x110e8, 1}, @@ -536,9 +540,14 @@ var _L = &RangeTable{ {0x11176, 0x11183, 13}, {0x11184, 0x111b2, 1}, {0x111c1, 0x111c4, 1}, - {0x111da, 0x11200, 38}, - {0x11201, 0x11211, 1}, + {0x111da, 0x111dc, 2}, + {0x11200, 0x11211, 1}, {0x11213, 0x1122b, 1}, + {0x11280, 0x11286, 1}, + {0x11288, 0x1128a, 2}, + {0x1128b, 0x1128d, 1}, + {0x1128f, 0x1129d, 1}, + {0x1129f, 0x112a8, 1}, {0x112b0, 0x112de, 1}, {0x11305, 0x1130c, 1}, {0x1130f, 0x11310, 1}, @@ -546,20 +555,24 @@ var _L = &RangeTable{ {0x1132a, 0x11330, 1}, {0x11332, 0x11333, 1}, {0x11335, 0x11339, 1}, - {0x1133d, 0x1135d, 32}, - {0x1135e, 0x11361, 1}, + {0x1133d, 0x11350, 19}, + {0x1135d, 0x11361, 1}, {0x11480, 0x114af, 1}, {0x114c4, 0x114c5, 1}, {0x114c7, 0x11580, 185}, {0x11581, 0x115ae, 1}, + {0x115d8, 0x115db, 1}, {0x11600, 0x1162f, 1}, {0x11644, 0x11680, 60}, {0x11681, 0x116aa, 1}, + {0x11700, 0x11719, 1}, {0x118a0, 0x118df, 1}, {0x118ff, 0x11ac0, 449}, {0x11ac1, 0x11af8, 1}, - {0x12000, 0x12398, 1}, + {0x12000, 0x12399, 1}, + {0x12480, 0x12543, 1}, {0x13000, 0x1342e, 1}, + {0x14400, 0x14646, 1}, {0x16800, 0x16a38, 1}, {0x16a40, 0x16a5e, 1}, {0x16ad0, 0x16aed, 1}, @@ -633,6 +646,7 @@ var _L = &RangeTable{ {0x20000, 0x2a6d6, 1}, {0x2a700, 0x2b734, 1}, {0x2b740, 0x2b81d, 1}, + {0x2b820, 0x2cea1, 1}, {0x2f800, 0x2fa1d, 1}, }, LatinOffset: 6, @@ -691,6 +705,7 @@ var _Ll = &RangeTable{ {0x04c2, 0x04ce, 2}, {0x04cf, 0x052f, 2}, {0x0561, 0x0587, 1}, + {0x13f8, 0x13fd, 1}, {0x1d00, 0x1d2b, 1}, {0x1d6b, 0x1d77, 1}, {0x1d79, 0x1d9a, 1}, @@ -747,15 +762,18 @@ var _Ll = &RangeTable{ {0xa791, 0xa793, 2}, {0xa794, 0xa795, 1}, {0xa797, 0xa7a9, 2}, + {0xa7b5, 0xa7b7, 2}, {0xa7fa, 0xab30, 822}, {0xab31, 0xab5a, 1}, - {0xab64, 0xab65, 1}, + {0xab60, 0xab65, 1}, + {0xab70, 0xabbf, 1}, {0xfb00, 0xfb06, 1}, {0xfb13, 0xfb17, 1}, {0xff41, 0xff5a, 1}, }, R32: []Range32{ {0x10428, 0x1044f, 1}, + {0x10cc0, 0x10cf2, 1}, {0x118c0, 0x118df, 1}, {0x1d41a, 0x1d433, 1}, {0x1d44e, 0x1d454, 1}, @@ -861,7 +879,7 @@ var _Lo = &RangeTable{ {0x07cb, 0x07ea, 1}, {0x0800, 0x0815, 1}, {0x0840, 0x0858, 1}, - {0x08a0, 0x08b2, 1}, + {0x08a0, 0x08b4, 1}, {0x0904, 0x0939, 1}, {0x093d, 0x0950, 19}, {0x0958, 0x0961, 1}, @@ -894,7 +912,8 @@ var _Lo = &RangeTable{ {0x0ab5, 0x0ab9, 1}, {0x0abd, 0x0ad0, 19}, {0x0ae0, 0x0ae1, 1}, - {0x0b05, 0x0b0c, 1}, + {0x0af9, 0x0b05, 12}, + {0x0b06, 0x0b0c, 1}, {0x0b0f, 0x0b10, 1}, {0x0b13, 0x0b28, 1}, {0x0b2a, 0x0b30, 1}, @@ -919,9 +938,9 @@ var _Lo = &RangeTable{ {0x0c12, 0x0c28, 1}, {0x0c2a, 0x0c39, 1}, {0x0c3d, 0x0c58, 27}, - {0x0c59, 0x0c60, 7}, - {0x0c61, 0x0c85, 36}, - {0x0c86, 0x0c8c, 1}, + {0x0c59, 0x0c5a, 1}, + {0x0c60, 0x0c61, 1}, + {0x0c85, 0x0c8c, 1}, {0x0c8e, 0x0c90, 1}, {0x0c92, 0x0ca8, 1}, {0x0caa, 0x0cb3, 1}, @@ -932,7 +951,7 @@ var _Lo = &RangeTable{ {0x0d05, 0x0d0c, 1}, {0x0d0e, 0x0d10, 1}, {0x0d12, 0x0d3a, 1}, - {0x0d3d, 0x0d4e, 17}, + {0x0d3d, 0x0d5f, 17}, {0x0d60, 0x0d61, 1}, {0x0d7a, 0x0d7f, 1}, {0x0d85, 0x0d96, 1}, @@ -988,7 +1007,6 @@ var _Lo = &RangeTable{ {0x1312, 0x1315, 1}, {0x1318, 0x135a, 1}, {0x1380, 0x138f, 1}, - {0x13a0, 0x13f4, 1}, {0x1401, 0x166c, 1}, {0x166f, 0x167f, 1}, {0x1681, 0x169a, 1}, @@ -1011,7 +1029,7 @@ var _Lo = &RangeTable{ {0x1950, 0x196d, 1}, {0x1970, 0x1974, 1}, {0x1980, 0x19ab, 1}, - {0x19c1, 0x19c7, 1}, + {0x19b0, 0x19c9, 1}, {0x1a00, 0x1a16, 1}, {0x1a20, 0x1a54, 1}, {0x1b05, 0x1b33, 1}, @@ -1046,7 +1064,7 @@ var _Lo = &RangeTable{ {0x31a0, 0x31ba, 1}, {0x31f0, 0x31ff, 1}, {0x3400, 0x4db5, 1}, - {0x4e00, 0x9fcc, 1}, + {0x4e00, 0x9fd5, 1}, {0xa000, 0xa014, 1}, {0xa016, 0xa48c, 1}, {0xa4d0, 0xa4f7, 1}, @@ -1055,16 +1073,16 @@ var _Lo = &RangeTable{ {0xa62a, 0xa62b, 1}, {0xa66e, 0xa6a0, 50}, {0xa6a1, 0xa6e5, 1}, - {0xa7f7, 0xa7fb, 4}, - {0xa7fc, 0xa801, 1}, + {0xa78f, 0xa7f7, 104}, + {0xa7fb, 0xa801, 1}, {0xa803, 0xa805, 1}, {0xa807, 0xa80a, 1}, {0xa80c, 0xa822, 1}, {0xa840, 0xa873, 1}, {0xa882, 0xa8b3, 1}, {0xa8f2, 0xa8f7, 1}, - {0xa8fb, 0xa90a, 15}, - {0xa90b, 0xa925, 1}, + {0xa8fb, 0xa8fd, 2}, + {0xa90a, 0xa925, 1}, {0xa930, 0xa946, 1}, {0xa960, 0xa97c, 1}, {0xa984, 0xa9b2, 1}, @@ -1149,6 +1167,8 @@ var _Lo = &RangeTable{ {0x10840, 0x10855, 1}, {0x10860, 0x10876, 1}, {0x10880, 0x1089e, 1}, + {0x108e0, 0x108f2, 1}, + {0x108f4, 0x108f5, 1}, {0x10900, 0x10915, 1}, {0x10920, 0x10939, 1}, {0x10980, 0x109b7, 1}, @@ -1174,9 +1194,14 @@ var _Lo = &RangeTable{ {0x11176, 0x11183, 13}, {0x11184, 0x111b2, 1}, {0x111c1, 0x111c4, 1}, - {0x111da, 0x11200, 38}, - {0x11201, 0x11211, 1}, + {0x111da, 0x111dc, 2}, + {0x11200, 0x11211, 1}, {0x11213, 0x1122b, 1}, + {0x11280, 0x11286, 1}, + {0x11288, 0x1128a, 2}, + {0x1128b, 0x1128d, 1}, + {0x1128f, 0x1129d, 1}, + {0x1129f, 0x112a8, 1}, {0x112b0, 0x112de, 1}, {0x11305, 0x1130c, 1}, {0x1130f, 0x11310, 1}, @@ -1184,19 +1209,23 @@ var _Lo = &RangeTable{ {0x1132a, 0x11330, 1}, {0x11332, 0x11333, 1}, {0x11335, 0x11339, 1}, - {0x1133d, 0x1135d, 32}, - {0x1135e, 0x11361, 1}, + {0x1133d, 0x11350, 19}, + {0x1135d, 0x11361, 1}, {0x11480, 0x114af, 1}, {0x114c4, 0x114c5, 1}, {0x114c7, 0x11580, 185}, {0x11581, 0x115ae, 1}, + {0x115d8, 0x115db, 1}, {0x11600, 0x1162f, 1}, {0x11644, 0x11680, 60}, {0x11681, 0x116aa, 1}, + {0x11700, 0x11719, 1}, {0x118ff, 0x11ac0, 449}, {0x11ac1, 0x11af8, 1}, - {0x12000, 0x12398, 1}, + {0x12000, 0x12399, 1}, + {0x12480, 0x12543, 1}, {0x13000, 0x1342e, 1}, + {0x14400, 0x14646, 1}, {0x16800, 0x16a38, 1}, {0x16a40, 0x16a5e, 1}, {0x16ad0, 0x16aed, 1}, @@ -1238,6 +1267,7 @@ var _Lo = &RangeTable{ {0x20000, 0x2a6d6, 1}, {0x2a700, 0x2b734, 1}, {0x2b740, 0x2b81d, 1}, + {0x2b820, 0x2cea1, 1}, {0x2f800, 0x2fa1d, 1}, }, LatinOffset: 1, @@ -1312,6 +1342,7 @@ var _Lu = &RangeTable{ {0x0531, 0x0556, 1}, {0x10a0, 0x10c5, 1}, {0x10c7, 0x10cd, 6}, + {0x13a0, 0x13f5, 1}, {0x1e00, 0x1e94, 2}, {0x1e9e, 0x1efe, 2}, {0x1f08, 0x1f0f, 1}, @@ -1356,11 +1387,13 @@ var _Lu = &RangeTable{ {0xa790, 0xa792, 2}, {0xa796, 0xa7aa, 2}, {0xa7ab, 0xa7ad, 1}, - {0xa7b0, 0xa7b1, 1}, - {0xff21, 0xff3a, 1}, + {0xa7b0, 0xa7b4, 1}, + {0xa7b6, 0xff21, 22379}, + {0xff22, 0xff3a, 1}, }, R32: []Range32{ {0x10400, 0x10427, 1}, + {0x10c80, 0x10cb2, 1}, {0x118a0, 0x118bf, 1}, {0x1d400, 0x1d419, 1}, {0x1d434, 0x1d44d, 1}, @@ -1420,7 +1453,7 @@ var _M = &RangeTable{ {0x0825, 0x0827, 1}, {0x0829, 0x082d, 1}, {0x0859, 0x085b, 1}, - {0x08e4, 0x0903, 1}, + {0x08e3, 0x0903, 1}, {0x093a, 0x093c, 1}, {0x093e, 0x094f, 1}, {0x0951, 0x0957, 1}, @@ -1516,8 +1549,6 @@ var _M = &RangeTable{ {0x18a9, 0x1920, 119}, {0x1921, 0x192b, 1}, {0x1930, 0x193b, 1}, - {0x19b0, 0x19c0, 1}, - {0x19c8, 0x19c9, 1}, {0x1a17, 0x1a1b, 1}, {0x1a55, 0x1a5e, 1}, {0x1a60, 0x1a7c, 1}, @@ -1545,10 +1576,11 @@ var _M = &RangeTable{ {0x3099, 0x309a, 1}, {0xa66f, 0xa672, 1}, {0xa674, 0xa67d, 1}, - {0xa69f, 0xa6f0, 81}, - {0xa6f1, 0xa802, 273}, - {0xa806, 0xa80b, 5}, - {0xa823, 0xa827, 1}, + {0xa69e, 0xa69f, 1}, + {0xa6f0, 0xa6f1, 1}, + {0xa802, 0xa806, 4}, + {0xa80b, 0xa823, 24}, + {0xa824, 0xa827, 1}, {0xa880, 0xa881, 1}, {0xa8b4, 0xa8c4, 1}, {0xa8e0, 0xa8f1, 1}, @@ -1572,7 +1604,7 @@ var _M = &RangeTable{ {0xabec, 0xabed, 1}, {0xfb1e, 0xfe00, 738}, {0xfe01, 0xfe0f, 1}, - {0xfe20, 0xfe2d, 1}, + {0xfe20, 0xfe2f, 1}, }, R32: []Range32{ {0x101fd, 0x102e0, 227}, @@ -1592,9 +1624,10 @@ var _M = &RangeTable{ {0x11173, 0x11180, 13}, {0x11181, 0x11182, 1}, {0x111b3, 0x111c0, 1}, + {0x111ca, 0x111cc, 1}, {0x1122c, 0x11237, 1}, {0x112df, 0x112ea, 1}, - {0x11301, 0x11303, 1}, + {0x11300, 0x11303, 1}, {0x1133c, 0x1133e, 2}, {0x1133f, 0x11344, 1}, {0x11347, 0x11348, 1}, @@ -1606,8 +1639,10 @@ var _M = &RangeTable{ {0x114b0, 0x114c3, 1}, {0x115af, 0x115b5, 1}, {0x115b8, 0x115c0, 1}, + {0x115dc, 0x115dd, 1}, {0x11630, 0x11640, 1}, {0x116ab, 0x116b7, 1}, + {0x1171d, 0x1172b, 1}, {0x16af0, 0x16af4, 1}, {0x16b30, 0x16b36, 1}, {0x16f51, 0x16f7e, 1}, @@ -1619,6 +1654,11 @@ var _M = &RangeTable{ {0x1d185, 0x1d18b, 1}, {0x1d1aa, 0x1d1ad, 1}, {0x1d242, 0x1d244, 1}, + {0x1da00, 0x1da36, 1}, + {0x1da3b, 0x1da6c, 1}, + {0x1da75, 0x1da84, 15}, + {0x1da9b, 0x1da9f, 1}, + {0x1daa1, 0x1daaf, 1}, {0x1e8d0, 0x1e8d6, 1}, {0xe0100, 0xe01ef, 1}, }, @@ -1685,8 +1725,6 @@ var _Mc = &RangeTable{ {0x1929, 0x192b, 1}, {0x1930, 0x1931, 1}, {0x1933, 0x1938, 1}, - {0x19b0, 0x19c0, 1}, - {0x19c8, 0x19c9, 1}, {0x1a19, 0x1a1a, 1}, {0x1a55, 0x1a57, 2}, {0x1a61, 0x1a63, 2}, @@ -1755,8 +1793,9 @@ var _Mc = &RangeTable{ {0x1163b, 0x1163c, 1}, {0x1163e, 0x116ac, 110}, {0x116ae, 0x116af, 1}, - {0x116b6, 0x16f51, 22683}, - {0x16f52, 0x16f7e, 1}, + {0x116b6, 0x11720, 106}, + {0x11721, 0x11726, 5}, + {0x16f51, 0x16f7e, 1}, {0x1d165, 0x1d166, 1}, {0x1d16d, 0x1d172, 1}, }, @@ -1796,7 +1835,7 @@ var _Mn = &RangeTable{ {0x0825, 0x0827, 1}, {0x0829, 0x082d, 1}, {0x0859, 0x085b, 1}, - {0x08e4, 0x0902, 1}, + {0x08e3, 0x0902, 1}, {0x093a, 0x093c, 2}, {0x0941, 0x0948, 1}, {0x094d, 0x0951, 4}, @@ -1918,12 +1957,12 @@ var _Mn = &RangeTable{ {0x3099, 0x309a, 1}, {0xa66f, 0xa674, 5}, {0xa675, 0xa67d, 1}, - {0xa69f, 0xa6f0, 81}, - {0xa6f1, 0xa802, 273}, - {0xa806, 0xa80b, 5}, - {0xa825, 0xa826, 1}, - {0xa8c4, 0xa8e0, 28}, - {0xa8e1, 0xa8f1, 1}, + {0xa69e, 0xa69f, 1}, + {0xa6f0, 0xa6f1, 1}, + {0xa802, 0xa806, 4}, + {0xa80b, 0xa825, 26}, + {0xa826, 0xa8c4, 158}, + {0xa8e0, 0xa8f1, 1}, {0xa926, 0xa92d, 1}, {0xa947, 0xa951, 1}, {0xa980, 0xa982, 1}, @@ -1943,7 +1982,7 @@ var _Mn = &RangeTable{ {0xabe5, 0xabe8, 3}, {0xabed, 0xfb1e, 20273}, {0xfe00, 0xfe0f, 1}, - {0xfe20, 0xfe2d, 1}, + {0xfe20, 0xfe2f, 1}, }, R32: []Range32{ {0x101fd, 0x102e0, 227}, @@ -1964,13 +2003,14 @@ var _Mn = &RangeTable{ {0x11173, 0x11180, 13}, {0x11181, 0x111b6, 53}, {0x111b7, 0x111be, 1}, + {0x111ca, 0x111cc, 1}, {0x1122f, 0x11231, 1}, {0x11234, 0x11236, 2}, {0x11237, 0x112df, 168}, {0x112e3, 0x112ea, 1}, - {0x11301, 0x1133c, 59}, - {0x11340, 0x11366, 38}, - {0x11367, 0x1136c, 1}, + {0x11300, 0x11301, 1}, + {0x1133c, 0x11340, 4}, + {0x11366, 0x1136c, 1}, {0x11370, 0x11374, 1}, {0x114b3, 0x114b8, 1}, {0x114ba, 0x114bf, 5}, @@ -1979,13 +2019,17 @@ var _Mn = &RangeTable{ {0x115b3, 0x115b5, 1}, {0x115bc, 0x115bd, 1}, {0x115bf, 0x115c0, 1}, + {0x115dc, 0x115dd, 1}, {0x11633, 0x1163a, 1}, {0x1163d, 0x1163f, 2}, {0x11640, 0x116ab, 107}, {0x116ad, 0x116b0, 3}, {0x116b1, 0x116b5, 1}, - {0x116b7, 0x16af0, 21561}, - {0x16af1, 0x16af4, 1}, + {0x116b7, 0x1171d, 102}, + {0x1171e, 0x1171f, 1}, + {0x11722, 0x11725, 1}, + {0x11727, 0x1172b, 1}, + {0x16af0, 0x16af4, 1}, {0x16b30, 0x16b36, 1}, {0x16f8f, 0x16f92, 1}, {0x1bc9d, 0x1bc9e, 1}, @@ -1994,6 +2038,11 @@ var _Mn = &RangeTable{ {0x1d185, 0x1d18b, 1}, {0x1d1aa, 0x1d1ad, 1}, {0x1d242, 0x1d244, 1}, + {0x1da00, 0x1da36, 1}, + {0x1da3b, 0x1da6c, 1}, + {0x1da75, 0x1da84, 15}, + {0x1da9b, 0x1da9f, 1}, + {0x1daa1, 0x1daaf, 1}, {0x1e8d0, 0x1e8d6, 1}, {0xe0100, 0xe01ef, 1}, }, @@ -2079,7 +2128,11 @@ var _N = &RangeTable{ {0x10858, 0x1085f, 1}, {0x10879, 0x1087f, 1}, {0x108a7, 0x108af, 1}, + {0x108fb, 0x108ff, 1}, {0x10916, 0x1091b, 1}, + {0x109bc, 0x109bd, 1}, + {0x109c0, 0x109cf, 1}, + {0x109d2, 0x109ff, 1}, {0x10a40, 0x10a47, 1}, {0x10a7d, 0x10a7e, 1}, {0x10a9d, 0x10a9f, 1}, @@ -2087,6 +2140,7 @@ var _N = &RangeTable{ {0x10b58, 0x10b5f, 1}, {0x10b78, 0x10b7f, 1}, {0x10ba9, 0x10baf, 1}, + {0x10cfa, 0x10cff, 1}, {0x10e60, 0x10e7e, 1}, {0x11052, 0x1106f, 1}, {0x110f0, 0x110f9, 1}, @@ -2097,6 +2151,7 @@ var _N = &RangeTable{ {0x114d0, 0x114d9, 1}, {0x11650, 0x11659, 1}, {0x116c0, 0x116c9, 1}, + {0x11730, 0x1173b, 1}, {0x118e0, 0x118f2, 1}, {0x12400, 0x1246e, 1}, {0x16a60, 0x16a69, 1}, @@ -2160,6 +2215,7 @@ var _Nd = &RangeTable{ {0x114d0, 0x114d9, 1}, {0x11650, 0x11659, 1}, {0x116c0, 0x116c9, 1}, + {0x11730, 0x11739, 1}, {0x118e0, 0x118e9, 1}, {0x16a60, 0x16a69, 1}, {0x16b50, 0x16b59, 1}, @@ -2225,7 +2281,11 @@ var _No = &RangeTable{ {0x10858, 0x1085f, 1}, {0x10879, 0x1087f, 1}, {0x108a7, 0x108af, 1}, + {0x108fb, 0x108ff, 1}, {0x10916, 0x1091b, 1}, + {0x109bc, 0x109bd, 1}, + {0x109c0, 0x109cf, 1}, + {0x109d2, 0x109ff, 1}, {0x10a40, 0x10a47, 1}, {0x10a7d, 0x10a7e, 1}, {0x10a9d, 0x10a9f, 1}, @@ -2233,9 +2293,11 @@ var _No = &RangeTable{ {0x10b58, 0x10b5f, 1}, {0x10b78, 0x10b7f, 1}, {0x10ba9, 0x10baf, 1}, + {0x10cfa, 0x10cff, 1}, {0x10e60, 0x10e7e, 1}, {0x11052, 0x11065, 1}, {0x111e1, 0x111f4, 1}, + {0x1173a, 0x1173b, 1}, {0x118ea, 0x118f2, 1}, {0x16b5b, 0x16b61, 1}, {0x1d360, 0x1d371, 1}, @@ -2336,9 +2398,9 @@ var _P = &RangeTable{ {0xa874, 0xa877, 1}, {0xa8ce, 0xa8cf, 1}, {0xa8f8, 0xa8fa, 1}, - {0xa92e, 0xa92f, 1}, - {0xa95f, 0xa9c1, 98}, - {0xa9c2, 0xa9cd, 1}, + {0xa8fc, 0xa92e, 50}, + {0xa92f, 0xa95f, 48}, + {0xa9c1, 0xa9cd, 1}, {0xa9de, 0xa9df, 1}, {0xaa5c, 0xaa5f, 1}, {0xaade, 0xaadf, 1}, @@ -2375,17 +2437,20 @@ var _P = &RangeTable{ {0x110be, 0x110c1, 1}, {0x11140, 0x11143, 1}, {0x11174, 0x11175, 1}, - {0x111c5, 0x111c8, 1}, - {0x111cd, 0x11238, 107}, - {0x11239, 0x1123d, 1}, - {0x114c6, 0x115c1, 251}, - {0x115c2, 0x115c9, 1}, + {0x111c5, 0x111c9, 1}, + {0x111cd, 0x111db, 14}, + {0x111dd, 0x111df, 1}, + {0x11238, 0x1123d, 1}, + {0x112a9, 0x114c6, 541}, + {0x115c1, 0x115d7, 1}, {0x11641, 0x11643, 1}, + {0x1173c, 0x1173e, 1}, {0x12470, 0x12474, 1}, {0x16a6e, 0x16a6f, 1}, {0x16af5, 0x16b37, 66}, {0x16b38, 0x16b3b, 1}, {0x16b44, 0x1bc9f, 20827}, + {0x1da87, 0x1da8b, 1}, }, LatinOffset: 11, } @@ -2550,9 +2615,9 @@ var _Po = &RangeTable{ {0xa874, 0xa877, 1}, {0xa8ce, 0xa8cf, 1}, {0xa8f8, 0xa8fa, 1}, - {0xa92e, 0xa92f, 1}, - {0xa95f, 0xa9c1, 98}, - {0xa9c2, 0xa9cd, 1}, + {0xa8fc, 0xa92e, 50}, + {0xa92f, 0xa95f, 48}, + {0xa9c1, 0xa9cd, 1}, {0xa9de, 0xa9df, 1}, {0xaa5c, 0xaa5f, 1}, {0xaade, 0xaadf, 1}, @@ -2592,17 +2657,20 @@ var _Po = &RangeTable{ {0x110be, 0x110c1, 1}, {0x11140, 0x11143, 1}, {0x11174, 0x11175, 1}, - {0x111c5, 0x111c8, 1}, - {0x111cd, 0x11238, 107}, - {0x11239, 0x1123d, 1}, - {0x114c6, 0x115c1, 251}, - {0x115c2, 0x115c9, 1}, + {0x111c5, 0x111c9, 1}, + {0x111cd, 0x111db, 14}, + {0x111dd, 0x111df, 1}, + {0x11238, 0x1123d, 1}, + {0x112a9, 0x114c6, 541}, + {0x115c1, 0x115d7, 1}, {0x11641, 0x11643, 1}, + {0x1173c, 0x1173e, 1}, {0x12470, 0x12474, 1}, {0x16a6e, 0x16a6f, 1}, {0x16af5, 0x16b37, 66}, {0x16b38, 0x16b3b, 1}, {0x16b44, 0x1bc9f, 20827}, + {0x1da87, 0x1da8b, 1}, }, LatinOffset: 8, } @@ -2694,7 +2762,7 @@ var _S = &RangeTable{ {0x2044, 0x2052, 14}, {0x207a, 0x207c, 1}, {0x208a, 0x208c, 1}, - {0x20a0, 0x20bd, 1}, + {0x20a0, 0x20be, 1}, {0x2100, 0x2101, 1}, {0x2103, 0x2106, 1}, {0x2108, 0x2109, 1}, @@ -2706,7 +2774,8 @@ var _S = &RangeTable{ {0x213b, 0x2140, 5}, {0x2141, 0x2144, 1}, {0x214a, 0x214d, 1}, - {0x214f, 0x2190, 65}, + {0x214f, 0x218a, 59}, + {0x218b, 0x2190, 5}, {0x2191, 0x2307, 1}, {0x230c, 0x2328, 1}, {0x232b, 0x23fa, 1}, @@ -2724,6 +2793,7 @@ var _S = &RangeTable{ {0x2b98, 0x2bb9, 1}, {0x2bbd, 0x2bc8, 1}, {0x2bca, 0x2bd1, 1}, + {0x2bec, 0x2bef, 1}, {0x2ce5, 0x2cea, 1}, {0x2e80, 0x2e99, 1}, {0x2e9b, 0x2ef3, 1}, @@ -2774,8 +2844,8 @@ var _S = &RangeTable{ {0x101a0, 0x101d0, 48}, {0x101d1, 0x101fc, 1}, {0x10877, 0x10878, 1}, - {0x10ac8, 0x16b3c, 24692}, - {0x16b3d, 0x16b3f, 1}, + {0x10ac8, 0x1173f, 3191}, + {0x16b3c, 0x16b3f, 1}, {0x16b45, 0x1bc9c, 20823}, {0x1d000, 0x1d0f5, 1}, {0x1d100, 0x1d126, 1}, @@ -2783,7 +2853,7 @@ var _S = &RangeTable{ {0x1d16a, 0x1d16c, 1}, {0x1d183, 0x1d184, 1}, {0x1d18c, 0x1d1a9, 1}, - {0x1d1ae, 0x1d1dd, 1}, + {0x1d1ae, 0x1d1e8, 1}, {0x1d200, 0x1d241, 1}, {0x1d245, 0x1d300, 187}, {0x1d301, 0x1d356, 1}, @@ -2792,6 +2862,11 @@ var _S = &RangeTable{ {0x1d735, 0x1d74f, 26}, {0x1d76f, 0x1d789, 26}, {0x1d7a9, 0x1d7c3, 26}, + {0x1d800, 0x1d9ff, 1}, + {0x1da37, 0x1da3a, 1}, + {0x1da6d, 0x1da74, 1}, + {0x1da76, 0x1da83, 1}, + {0x1da85, 0x1da86, 1}, {0x1eef0, 0x1eef1, 1}, {0x1f000, 0x1f02b, 1}, {0x1f030, 0x1f093, 1}, @@ -2806,16 +2881,9 @@ var _S = &RangeTable{ {0x1f210, 0x1f23a, 1}, {0x1f240, 0x1f248, 1}, {0x1f250, 0x1f251, 1}, - {0x1f300, 0x1f32c, 1}, - {0x1f330, 0x1f37d, 1}, - {0x1f380, 0x1f3ce, 1}, - {0x1f3d4, 0x1f3f7, 1}, - {0x1f400, 0x1f4fe, 1}, - {0x1f500, 0x1f54a, 1}, - {0x1f550, 0x1f579, 1}, + {0x1f300, 0x1f579, 1}, {0x1f57b, 0x1f5a3, 1}, - {0x1f5a5, 0x1f642, 1}, - {0x1f645, 0x1f6cf, 1}, + {0x1f5a5, 0x1f6d0, 1}, {0x1f6e0, 0x1f6ec, 1}, {0x1f6f0, 0x1f6f3, 1}, {0x1f700, 0x1f773, 1}, @@ -2825,6 +2893,9 @@ var _S = &RangeTable{ {0x1f850, 0x1f859, 1}, {0x1f860, 0x1f887, 1}, {0x1f890, 0x1f8ad, 1}, + {0x1f910, 0x1f918, 1}, + {0x1f980, 0x1f984, 1}, + {0x1f9c0, 0x1f9c0, 1}, }, LatinOffset: 10, } @@ -2838,7 +2909,7 @@ var _Sc = &RangeTable{ {0x09fb, 0x0af1, 246}, {0x0bf9, 0x0e3f, 582}, {0x17db, 0x20a0, 2245}, - {0x20a1, 0x20bd, 1}, + {0x20a1, 0x20be, 1}, {0xa838, 0xfdfc, 21956}, {0xfe69, 0xff04, 155}, {0xffe0, 0xffe1, 1}, @@ -2873,6 +2944,10 @@ var _Sk = &RangeTable{ {0xff3e, 0xff40, 2}, {0xffe3, 0xffe3, 1}, }, + R32: []Range32{ + {0x1f3fb, 0x1f3fb, 1}, + {0x1f3fc, 0x1f3ff, 1}, + }, LatinOffset: 3, } @@ -2971,7 +3046,8 @@ var _So = &RangeTable{ {0x212e, 0x213a, 12}, {0x213b, 0x214a, 15}, {0x214c, 0x214d, 1}, - {0x214f, 0x2195, 70}, + {0x214f, 0x218a, 59}, + {0x218b, 0x2195, 10}, {0x2196, 0x2199, 1}, {0x219c, 0x219f, 1}, {0x21a1, 0x21a2, 1}, @@ -3005,6 +3081,7 @@ var _So = &RangeTable{ {0x2b98, 0x2bb9, 1}, {0x2bbd, 0x2bc8, 1}, {0x2bca, 0x2bd1, 1}, + {0x2bec, 0x2bef, 1}, {0x2ce5, 0x2cea, 1}, {0x2e80, 0x2e99, 1}, {0x2e9b, 0x2ef3, 1}, @@ -3044,8 +3121,8 @@ var _So = &RangeTable{ {0x101a0, 0x101d0, 48}, {0x101d1, 0x101fc, 1}, {0x10877, 0x10878, 1}, - {0x10ac8, 0x16b3c, 24692}, - {0x16b3d, 0x16b3f, 1}, + {0x10ac8, 0x1173f, 3191}, + {0x16b3c, 0x16b3f, 1}, {0x16b45, 0x1bc9c, 20823}, {0x1d000, 0x1d0f5, 1}, {0x1d100, 0x1d126, 1}, @@ -3053,10 +3130,15 @@ var _So = &RangeTable{ {0x1d16a, 0x1d16c, 1}, {0x1d183, 0x1d184, 1}, {0x1d18c, 0x1d1a9, 1}, - {0x1d1ae, 0x1d1dd, 1}, + {0x1d1ae, 0x1d1e8, 1}, {0x1d200, 0x1d241, 1}, {0x1d245, 0x1d300, 187}, {0x1d301, 0x1d356, 1}, + {0x1d800, 0x1d9ff, 1}, + {0x1da37, 0x1da3a, 1}, + {0x1da6d, 0x1da74, 1}, + {0x1da76, 0x1da83, 1}, + {0x1da85, 0x1da86, 1}, {0x1f000, 0x1f02b, 1}, {0x1f030, 0x1f093, 1}, {0x1f0a0, 0x1f0ae, 1}, @@ -3070,16 +3152,10 @@ var _So = &RangeTable{ {0x1f210, 0x1f23a, 1}, {0x1f240, 0x1f248, 1}, {0x1f250, 0x1f251, 1}, - {0x1f300, 0x1f32c, 1}, - {0x1f330, 0x1f37d, 1}, - {0x1f380, 0x1f3ce, 1}, - {0x1f3d4, 0x1f3f7, 1}, - {0x1f400, 0x1f4fe, 1}, - {0x1f500, 0x1f54a, 1}, - {0x1f550, 0x1f579, 1}, + {0x1f300, 0x1f3fa, 1}, + {0x1f400, 0x1f579, 1}, {0x1f57b, 0x1f5a3, 1}, - {0x1f5a5, 0x1f642, 1}, - {0x1f645, 0x1f6cf, 1}, + {0x1f5a5, 0x1f6d0, 1}, {0x1f6e0, 0x1f6ec, 1}, {0x1f6f0, 0x1f6f3, 1}, {0x1f700, 0x1f773, 1}, @@ -3089,6 +3165,9 @@ var _So = &RangeTable{ {0x1f850, 0x1f859, 1}, {0x1f860, 0x1f887, 1}, {0x1f890, 0x1f8ad, 1}, + {0x1f910, 0x1f918, 1}, + {0x1f980, 0x1f984, 1}, + {0x1f9c0, 0x1f9c0, 1}, }, LatinOffset: 2, } @@ -3180,11 +3259,13 @@ var ( ) // Generated by running -// maketables --scripts=all --url=http://www.unicode.org/Public/7.0.0/ucd/ +// maketables --scripts=all --url=http://www.unicode.org/Public/8.0.0/ucd/ // DO NOT EDIT // Scripts is the set of Unicode script tables. var Scripts = map[string]*RangeTable{ + "Ahom": Ahom, + "Anatolian_Hieroglyphs": Anatolian_Hieroglyphs, "Arabic": Arabic, "Armenian": Armenian, "Avestan": Avestan, @@ -3225,6 +3306,7 @@ var Scripts = map[string]*RangeTable{ "Han": Han, "Hangul": Hangul, "Hanunoo": Hanunoo, + "Hatran": Hatran, "Hebrew": Hebrew, "Hiragana": Hiragana, "Imperial_Aramaic": Imperial_Aramaic, @@ -3261,12 +3343,14 @@ var Scripts = map[string]*RangeTable{ "Modi": Modi, "Mongolian": Mongolian, "Mro": Mro, + "Multani": Multani, "Myanmar": Myanmar, "Nabataean": Nabataean, "New_Tai_Lue": New_Tai_Lue, "Nko": Nko, "Ogham": Ogham, "Ol_Chiki": Ol_Chiki, + "Old_Hungarian": Old_Hungarian, "Old_Italic": Old_Italic, "Old_North_Arabian": Old_North_Arabian, "Old_Permic": Old_Permic, @@ -3288,6 +3372,7 @@ var Scripts = map[string]*RangeTable{ "Sharada": Sharada, "Shavian": Shavian, "Siddham": Siddham, + "SignWriting": SignWriting, "Sinhala": Sinhala, "Sora_Sompeng": Sora_Sompeng, "Sundanese": Sundanese, @@ -3312,6 +3397,22 @@ var Scripts = map[string]*RangeTable{ "Yi": Yi, } +var _Ahom = &RangeTable{ + R16: []Range16{}, + R32: []Range32{ + {0x11700, 0x11719, 1}, + {0x1171d, 0x1172b, 1}, + {0x11730, 0x1173f, 1}, + }, +} + +var _Anatolian_Hieroglyphs = &RangeTable{ + R16: []Range16{}, + R32: []Range32{ + {0x14400, 0x14646, 1}, + }, +} + var _Arabic = &RangeTable{ R16: []Range16{ {0x0600, 0x0604, 1}, @@ -3320,13 +3421,12 @@ var _Arabic = &RangeTable{ {0x061e, 0x061e, 1}, {0x0620, 0x063f, 1}, {0x0641, 0x064a, 1}, - {0x0656, 0x065f, 1}, - {0x066a, 0x066f, 1}, + {0x0656, 0x066f, 1}, {0x0671, 0x06dc, 1}, {0x06de, 0x06ff, 1}, {0x0750, 0x077f, 1}, - {0x08a0, 0x08b2, 1}, - {0x08e4, 0x08ff, 1}, + {0x08a0, 0x08b4, 1}, + {0x08e3, 0x08ff, 1}, {0xfb50, 0xfbc1, 1}, {0xfbd3, 0xfd3d, 1}, {0xfd50, 0xfd8f, 1}, @@ -3520,7 +3620,9 @@ var _Cham = &RangeTable{ var _Cherokee = &RangeTable{ R16: []Range16{ - {0x13a0, 0x13f4, 1}, + {0x13a0, 0x13f5, 1}, + {0x13f8, 0x13fd, 1}, + {0xab70, 0xabbf, 1}, }, } @@ -3546,7 +3648,6 @@ var _Common = &RangeTable{ {0x061b, 0x061c, 1}, {0x061f, 0x061f, 1}, {0x0640, 0x0640, 1}, - {0x0660, 0x0669, 1}, {0x06dd, 0x06dd, 1}, {0x0964, 0x0965, 1}, {0x0e3f, 0x0e3f, 1}, @@ -3566,13 +3667,13 @@ var _Common = &RangeTable{ {0x2066, 0x2070, 1}, {0x2074, 0x207e, 1}, {0x2080, 0x208e, 1}, - {0x20a0, 0x20bd, 1}, + {0x20a0, 0x20be, 1}, {0x2100, 0x2125, 1}, {0x2127, 0x2129, 1}, {0x212c, 0x2131, 1}, {0x2133, 0x214d, 1}, {0x214f, 0x215f, 1}, - {0x2189, 0x2189, 1}, + {0x2189, 0x218b, 1}, {0x2190, 0x23fa, 1}, {0x2400, 0x2426, 1}, {0x2440, 0x244a, 1}, @@ -3582,6 +3683,7 @@ var _Common = &RangeTable{ {0x2b98, 0x2bb9, 1}, {0x2bbd, 0x2bc8, 1}, {0x2bca, 0x2bd1, 1}, + {0x2bec, 0x2bef, 1}, {0x2e00, 0x2e42, 1}, {0x2ff0, 0x2ffb, 1}, {0x3000, 0x3004, 1}, @@ -3633,7 +3735,7 @@ var _Common = &RangeTable{ {0x1d16a, 0x1d17a, 1}, {0x1d183, 0x1d184, 1}, {0x1d18c, 0x1d1a9, 1}, - {0x1d1ae, 0x1d1dd, 1}, + {0x1d1ae, 0x1d1e8, 1}, {0x1d300, 0x1d356, 1}, {0x1d360, 0x1d371, 1}, {0x1d400, 0x1d454, 1}, @@ -3672,16 +3774,9 @@ var _Common = &RangeTable{ {0x1f210, 0x1f23a, 1}, {0x1f240, 0x1f248, 1}, {0x1f250, 0x1f251, 1}, - {0x1f300, 0x1f32c, 1}, - {0x1f330, 0x1f37d, 1}, - {0x1f380, 0x1f3ce, 1}, - {0x1f3d4, 0x1f3f7, 1}, - {0x1f400, 0x1f4fe, 1}, - {0x1f500, 0x1f54a, 1}, - {0x1f550, 0x1f579, 1}, + {0x1f300, 0x1f579, 1}, {0x1f57b, 0x1f5a3, 1}, - {0x1f5a5, 0x1f642, 1}, - {0x1f645, 0x1f6cf, 1}, + {0x1f5a5, 0x1f6d0, 1}, {0x1f6e0, 0x1f6ec, 1}, {0x1f6f0, 0x1f6f3, 1}, {0x1f700, 0x1f773, 1}, @@ -3691,6 +3786,9 @@ var _Common = &RangeTable{ {0x1f850, 0x1f859, 1}, {0x1f860, 0x1f887, 1}, {0x1f890, 0x1f8ad, 1}, + {0x1f910, 0x1f918, 1}, + {0x1f980, 0x1f984, 1}, + {0x1f9c0, 0x1f9c0, 1}, {0xe0001, 0xe0001, 1}, {0xe0020, 0xe007f, 1}, }, @@ -3708,9 +3806,10 @@ var _Coptic = &RangeTable{ var _Cuneiform = &RangeTable{ R16: []Range16{}, R32: []Range32{ - {0x12000, 0x12398, 1}, + {0x12000, 0x12399, 1}, {0x12400, 0x1246e, 1}, {0x12470, 0x12474, 1}, + {0x12480, 0x12543, 1}, }, } @@ -3733,8 +3832,8 @@ var _Cyrillic = &RangeTable{ {0x1d2b, 0x1d2b, 1}, {0x1d78, 0x1d78, 1}, {0x2de0, 0x2dff, 1}, - {0xa640, 0xa69d, 1}, - {0xa69f, 0xa69f, 1}, + {0xa640, 0xa69f, 1}, + {0xfe2e, 0xfe2f, 1}, }, } @@ -3750,7 +3849,7 @@ var _Devanagari = &RangeTable{ {0x0900, 0x0950, 1}, {0x0953, 0x0963, 1}, {0x0966, 0x097f, 1}, - {0xa8e0, 0xa8fb, 1}, + {0xa8e0, 0xa8fd, 1}, }, } @@ -3846,7 +3945,7 @@ var _Gothic = &RangeTable{ var _Grantha = &RangeTable{ R16: []Range16{}, R32: []Range32{ - {0x11301, 0x11303, 1}, + {0x11300, 0x11303, 1}, {0x11305, 0x1130c, 1}, {0x1130f, 0x11310, 1}, {0x11313, 0x11328, 1}, @@ -3856,6 +3955,7 @@ var _Grantha = &RangeTable{ {0x1133c, 0x11344, 1}, {0x11347, 0x11348, 1}, {0x1134b, 0x1134d, 1}, + {0x11350, 0x11350, 1}, {0x11357, 0x11357, 1}, {0x1135d, 0x11363, 1}, {0x11366, 0x1136c, 1}, @@ -3921,6 +4021,7 @@ var _Gujarati = &RangeTable{ {0x0ad0, 0x0ad0, 1}, {0x0ae0, 0x0ae3, 1}, {0x0ae6, 0x0af1, 1}, + {0x0af9, 0x0af9, 1}, }, } @@ -3955,7 +4056,7 @@ var _Han = &RangeTable{ {0x3021, 0x3029, 1}, {0x3038, 0x303b, 1}, {0x3400, 0x4db5, 1}, - {0x4e00, 0x9fcc, 1}, + {0x4e00, 0x9fd5, 1}, {0xf900, 0xfa6d, 1}, {0xfa70, 0xfad9, 1}, }, @@ -3963,6 +4064,7 @@ var _Han = &RangeTable{ {0x20000, 0x2a6d6, 1}, {0x2a700, 0x2b734, 1}, {0x2b740, 0x2b81d, 1}, + {0x2b820, 0x2cea1, 1}, {0x2f800, 0x2fa1d, 1}, }, } @@ -3992,6 +4094,15 @@ var _Hanunoo = &RangeTable{ }, } +var _Hatran = &RangeTable{ + R16: []Range16{}, + R32: []Range32{ + {0x108e0, 0x108f2, 1}, + {0x108f4, 0x108f5, 1}, + {0x108fb, 0x108ff, 1}, + }, +} + var _Hebrew = &RangeTable{ R16: []Range16{ {0x0591, 0x05c7, 1}, @@ -4218,13 +4329,11 @@ var _Latin = &RangeTable{ {0x2160, 0x2188, 1}, {0x2c60, 0x2c7f, 1}, {0xa722, 0xa787, 1}, - {0xa78b, 0xa78e, 1}, - {0xa790, 0xa7ad, 1}, - {0xa7b0, 0xa7b1, 1}, + {0xa78b, 0xa7ad, 1}, + {0xa7b0, 0xa7b7, 1}, {0xa7f7, 0xa7ff, 1}, {0xab30, 0xab5a, 1}, - {0xab5c, 0xab5f, 1}, - {0xab64, 0xab64, 1}, + {0xab5c, 0xab64, 1}, {0xfb00, 0xfb06, 1}, {0xff21, 0xff3a, 1}, {0xff41, 0xff5a, 1}, @@ -4310,7 +4419,7 @@ var _Malayalam = &RangeTable{ {0x0d46, 0x0d48, 1}, {0x0d4a, 0x0d4e, 1}, {0x0d57, 0x0d57, 1}, - {0x0d60, 0x0d63, 1}, + {0x0d5f, 0x0d63, 1}, {0x0d66, 0x0d75, 1}, {0x0d79, 0x0d7f, 1}, }, @@ -4351,7 +4460,8 @@ var _Meroitic_Cursive = &RangeTable{ R16: []Range16{}, R32: []Range32{ {0x109a0, 0x109b7, 1}, - {0x109be, 0x109bf, 1}, + {0x109bc, 0x109cf, 1}, + {0x109d2, 0x109ff, 1}, }, } @@ -4399,6 +4509,17 @@ var _Mro = &RangeTable{ }, } +var _Multani = &RangeTable{ + R16: []Range16{}, + R32: []Range32{ + {0x11280, 0x11286, 1}, + {0x11288, 0x11288, 1}, + {0x1128a, 0x1128d, 1}, + {0x1128f, 0x1129d, 1}, + {0x1129f, 0x112a9, 1}, + }, +} + var _Myanmar = &RangeTable{ R16: []Range16{ {0x1000, 0x109f, 1}, @@ -4442,6 +4563,15 @@ var _Ol_Chiki = &RangeTable{ }, } +var _Old_Hungarian = &RangeTable{ + R16: []Range16{}, + R32: []Range32{ + {0x10c80, 0x10cb2, 1}, + {0x10cc0, 0x10cf2, 1}, + {0x10cfa, 0x10cff, 1}, + }, +} + var _Old_Italic = &RangeTable{ R16: []Range16{}, R32: []Range32{ @@ -4591,9 +4721,8 @@ var _Saurashtra = &RangeTable{ var _Sharada = &RangeTable{ R16: []Range16{}, R32: []Range32{ - {0x11180, 0x111c8, 1}, - {0x111cd, 0x111cd, 1}, - {0x111d0, 0x111da, 1}, + {0x11180, 0x111cd, 1}, + {0x111d0, 0x111df, 1}, }, } @@ -4608,7 +4737,16 @@ var _Siddham = &RangeTable{ R16: []Range16{}, R32: []Range32{ {0x11580, 0x115b5, 1}, - {0x115b8, 0x115c9, 1}, + {0x115b8, 0x115dd, 1}, + }, +} + +var _SignWriting = &RangeTable{ + R16: []Range16{}, + R32: []Range32{ + {0x1d800, 0x1da8b, 1}, + {0x1da9b, 0x1da9f, 1}, + {0x1daa1, 0x1daaf, 1}, }, } @@ -4740,7 +4878,7 @@ var _Telugu = &RangeTable{ {0x0c46, 0x0c48, 1}, {0x0c4a, 0x0c4d, 1}, {0x0c55, 0x0c56, 1}, - {0x0c58, 0x0c59, 1}, + {0x0c58, 0x0c5a, 1}, {0x0c60, 0x0c63, 1}, {0x0c66, 0x0c6f, 1}, {0x0c78, 0x0c7f, 1}, @@ -4819,6 +4957,8 @@ var _Yi = &RangeTable{ // These variables have type *RangeTable. var ( + Ahom = _Ahom // Ahom is the set of Unicode characters in script Ahom. + Anatolian_Hieroglyphs = _Anatolian_Hieroglyphs // Anatolian_Hieroglyphs is the set of Unicode characters in script Anatolian_Hieroglyphs. Arabic = _Arabic // Arabic is the set of Unicode characters in script Arabic. Armenian = _Armenian // Armenian is the set of Unicode characters in script Armenian. Avestan = _Avestan // Avestan is the set of Unicode characters in script Avestan. @@ -4859,6 +4999,7 @@ var ( Han = _Han // Han is the set of Unicode characters in script Han. Hangul = _Hangul // Hangul is the set of Unicode characters in script Hangul. Hanunoo = _Hanunoo // Hanunoo is the set of Unicode characters in script Hanunoo. + Hatran = _Hatran // Hatran is the set of Unicode characters in script Hatran. Hebrew = _Hebrew // Hebrew is the set of Unicode characters in script Hebrew. Hiragana = _Hiragana // Hiragana is the set of Unicode characters in script Hiragana. Imperial_Aramaic = _Imperial_Aramaic // Imperial_Aramaic is the set of Unicode characters in script Imperial_Aramaic. @@ -4895,12 +5036,14 @@ var ( Modi = _Modi // Modi is the set of Unicode characters in script Modi. Mongolian = _Mongolian // Mongolian is the set of Unicode characters in script Mongolian. Mro = _Mro // Mro is the set of Unicode characters in script Mro. + Multani = _Multani // Multani is the set of Unicode characters in script Multani. Myanmar = _Myanmar // Myanmar is the set of Unicode characters in script Myanmar. Nabataean = _Nabataean // Nabataean is the set of Unicode characters in script Nabataean. New_Tai_Lue = _New_Tai_Lue // New_Tai_Lue is the set of Unicode characters in script New_Tai_Lue. Nko = _Nko // Nko is the set of Unicode characters in script Nko. Ogham = _Ogham // Ogham is the set of Unicode characters in script Ogham. Ol_Chiki = _Ol_Chiki // Ol_Chiki is the set of Unicode characters in script Ol_Chiki. + Old_Hungarian = _Old_Hungarian // Old_Hungarian is the set of Unicode characters in script Old_Hungarian. Old_Italic = _Old_Italic // Old_Italic is the set of Unicode characters in script Old_Italic. Old_North_Arabian = _Old_North_Arabian // Old_North_Arabian is the set of Unicode characters in script Old_North_Arabian. Old_Permic = _Old_Permic // Old_Permic is the set of Unicode characters in script Old_Permic. @@ -4922,6 +5065,7 @@ var ( Sharada = _Sharada // Sharada is the set of Unicode characters in script Sharada. Shavian = _Shavian // Shavian is the set of Unicode characters in script Shavian. Siddham = _Siddham // Siddham is the set of Unicode characters in script Siddham. + SignWriting = _SignWriting // SignWriting is the set of Unicode characters in script SignWriting. Sinhala = _Sinhala // Sinhala is the set of Unicode characters in script Sinhala. Sora_Sompeng = _Sora_Sompeng // Sora_Sompeng is the set of Unicode characters in script Sora_Sompeng. Sundanese = _Sundanese // Sundanese is the set of Unicode characters in script Sundanese. @@ -4947,7 +5091,7 @@ var ( ) // Generated by running -// maketables --props=all --url=http://www.unicode.org/Public/7.0.0/ucd/ +// maketables --props=all --url=http://www.unicode.org/Public/8.0.0/ucd/ // DO NOT EDIT // Properties is the set of Unicode property tables. @@ -5043,7 +5187,7 @@ var _Deprecated = &RangeTable{ }, R32: []Range32{ {0xe0001, 0xe0001, 1}, - {0xe0020, 0xe007f, 1}, + {0xe007f, 0xe007f, 1}, }, } @@ -5077,7 +5221,7 @@ var _Diacritic = &RangeTable{ {0x07a6, 0x07b0, 1}, {0x07eb, 0x07f5, 1}, {0x0818, 0x0819, 1}, - {0x08e4, 0x08fe, 1}, + {0x08e3, 0x08fe, 1}, {0x093c, 0x093c, 1}, {0x094d, 0x094d, 1}, {0x0951, 0x0954, 1}, @@ -5164,7 +5308,7 @@ var _Diacritic = &RangeTable{ {0xab5b, 0xab5f, 1}, {0xabec, 0xabed, 1}, {0xfb1e, 0xfb1e, 1}, - {0xfe20, 0xfe2d, 1}, + {0xfe20, 0xfe2f, 1}, {0xff3e, 0xff3e, 1}, {0xff40, 0xff40, 1}, {0xff70, 0xff70, 1}, @@ -5178,6 +5322,7 @@ var _Diacritic = &RangeTable{ {0x11133, 0x11134, 1}, {0x11173, 0x11173, 1}, {0x111c0, 0x111c0, 1}, + {0x111ca, 0x111cc, 1}, {0x11235, 0x11236, 1}, {0x112e9, 0x112ea, 1}, {0x1133c, 0x1133c, 1}, @@ -5188,6 +5333,7 @@ var _Diacritic = &RangeTable{ {0x115bf, 0x115c0, 1}, {0x1163f, 0x1163f, 1}, {0x116b6, 0x116b7, 1}, + {0x1172b, 0x1172b, 1}, {0x16af0, 0x16af4, 1}, {0x16f8f, 0x16f9f, 1}, {0x1d167, 0x1d169, 1}, @@ -5281,7 +5427,7 @@ var _Ideographic = &RangeTable{ {0x3021, 0x3029, 1}, {0x3038, 0x303a, 1}, {0x3400, 0x4db5, 1}, - {0x4e00, 0x9fcc, 1}, + {0x4e00, 0x9fd5, 1}, {0xf900, 0xfa6d, 1}, {0xfa70, 0xfad9, 1}, }, @@ -5289,6 +5435,7 @@ var _Ideographic = &RangeTable{ {0x20000, 0x2a6d6, 1}, {0x2a700, 0x2b734, 1}, {0x2b740, 0x2b81d, 1}, + {0x2b820, 0x2cea1, 1}, {0x2f800, 0x2fa1d, 1}, }, } @@ -5303,6 +5450,8 @@ var _Logical_Order_Exception = &RangeTable{ R16: []Range16{ {0x0e40, 0x0e44, 1}, {0x0ec0, 0x0ec4, 1}, + {0x19b5, 0x19b7, 1}, + {0x19ba, 0x19ba, 1}, {0xaab5, 0xaab6, 1}, {0xaab9, 0xaab9, 1}, {0xaabb, 0xaabc, 1}, @@ -5357,7 +5506,7 @@ var _Other_Alphabetic = &RangeTable{ {0x081b, 0x0823, 1}, {0x0825, 0x0827, 1}, {0x0829, 0x082c, 1}, - {0x08e4, 0x08e9, 1}, + {0x08e3, 0x08e9, 1}, {0x08f0, 0x0903, 1}, {0x093a, 0x093b, 1}, {0x093e, 0x094c, 1}, @@ -5445,8 +5594,6 @@ var _Other_Alphabetic = &RangeTable{ {0x18a9, 0x18a9, 1}, {0x1920, 0x192b, 1}, {0x1930, 0x1938, 1}, - {0x19b0, 0x19c0, 1}, - {0x19c8, 0x19c9, 1}, {0x1a17, 0x1a1b, 1}, {0x1a55, 0x1a5e, 1}, {0x1a61, 0x1a74, 1}, @@ -5462,7 +5609,7 @@ var _Other_Alphabetic = &RangeTable{ {0x24b6, 0x24e9, 1}, {0x2de0, 0x2dff, 1}, {0xa674, 0xa67b, 1}, - {0xa69f, 0xa69f, 1}, + {0xa69e, 0xa69f, 1}, {0xa823, 0xa827, 1}, {0xa880, 0xa881, 1}, {0xa8b4, 0xa8c3, 1}, @@ -5498,7 +5645,7 @@ var _Other_Alphabetic = &RangeTable{ {0x1122c, 0x11234, 1}, {0x11237, 0x11237, 1}, {0x112df, 0x112e8, 1}, - {0x11301, 0x11303, 1}, + {0x11300, 0x11303, 1}, {0x1133e, 0x11344, 1}, {0x11347, 0x11348, 1}, {0x1134b, 0x1134c, 1}, @@ -5507,9 +5654,11 @@ var _Other_Alphabetic = &RangeTable{ {0x114b0, 0x114c1, 1}, {0x115af, 0x115b5, 1}, {0x115b8, 0x115be, 1}, + {0x115dc, 0x115dd, 1}, {0x11630, 0x1163e, 1}, {0x11640, 0x11640, 1}, {0x116ab, 0x116b5, 1}, + {0x1171d, 0x1172a, 1}, {0x16b30, 0x16b36, 1}, {0x16f51, 0x16f7e, 1}, {0x1bc9e, 0x1bc9e, 1}, @@ -5890,16 +6039,20 @@ var _STerm = &RangeTable{ {0x11141, 0x11143, 1}, {0x111c5, 0x111c6, 1}, {0x111cd, 0x111cd, 1}, + {0x111de, 0x111df, 1}, {0x11238, 0x11239, 1}, {0x1123b, 0x1123c, 1}, + {0x112a9, 0x112a9, 1}, {0x115c2, 0x115c3, 1}, - {0x115c9, 0x115c9, 1}, + {0x115c9, 0x115d7, 1}, {0x11641, 0x11642, 1}, + {0x1173c, 0x1173e, 1}, {0x16a6e, 0x16a6f, 1}, {0x16af5, 0x16af5, 1}, {0x16b37, 0x16b38, 1}, {0x16b44, 0x16b44, 1}, {0x1bc9f, 0x1bc9f, 1}, + {0x1da88, 0x1da88, 1}, }, LatinOffset: 3, } @@ -6023,16 +6176,20 @@ var _Terminal_Punctuation = &RangeTable{ {0x11141, 0x11143, 1}, {0x111c5, 0x111c6, 1}, {0x111cd, 0x111cd, 1}, + {0x111de, 0x111df, 1}, {0x11238, 0x1123c, 1}, + {0x112a9, 0x112a9, 1}, {0x115c2, 0x115c5, 1}, - {0x115c9, 0x115c9, 1}, + {0x115c9, 0x115d7, 1}, {0x11641, 0x11642, 1}, + {0x1173c, 0x1173e, 1}, {0x12470, 0x12474, 1}, {0x16a6e, 0x16a6f, 1}, {0x16af5, 0x16af5, 1}, {0x16b37, 0x16b39, 1}, {0x16b44, 0x16b44, 1}, {0x1bc9f, 0x1bc9f, 1}, + {0x1da87, 0x1da8a, 1}, }, LatinOffset: 5, } @@ -6040,7 +6197,7 @@ var _Terminal_Punctuation = &RangeTable{ var _Unified_Ideograph = &RangeTable{ R16: []Range16{ {0x3400, 0x4db5, 1}, - {0x4e00, 0x9fcc, 1}, + {0x4e00, 0x9fd5, 1}, {0xfa0e, 0xfa0f, 1}, {0xfa11, 0xfa11, 1}, {0xfa13, 0xfa14, 1}, @@ -6053,6 +6210,7 @@ var _Unified_Ideograph = &RangeTable{ {0x20000, 0x2a6d6, 1}, {0x2a700, 0x2b734, 1}, {0x2b740, 0x2b81d, 1}, + {0x2b820, 0x2cea1, 1}, }, } @@ -6119,7 +6277,7 @@ var ( ) // Generated by running -// maketables --data=http://www.unicode.org/Public/7.0.0/ucd/UnicodeData.txt --casefolding=http://www.unicode.org/Public/7.0.0/ucd/CaseFolding.txt +// maketables --data=http://www.unicode.org/Public/8.0.0/ucd/UnicodeData.txt --casefolding=http://www.unicode.org/Public/8.0.0/ucd/CaseFolding.txt // DO NOT EDIT // CaseRanges is the table describing case mappings for all letters with @@ -6240,6 +6398,7 @@ var _CaseRanges = []CaseRange{ {0x028A, 0x028B, d{-217, 0, -217}}, {0x028C, 0x028C, d{-71, 0, -71}}, {0x0292, 0x0292, d{-219, 0, -219}}, + {0x029D, 0x029D, d{42261, 0, 42261}}, {0x029E, 0x029E, d{42258, 0, 42258}}, {0x0345, 0x0345, d{84, 0, 84}}, {0x0370, 0x0373, d{UpperLower, UpperLower, UpperLower}}, @@ -6291,6 +6450,9 @@ var _CaseRanges = []CaseRange{ {0x10A0, 0x10C5, d{0, 7264, 0}}, {0x10C7, 0x10C7, d{0, 7264, 0}}, {0x10CD, 0x10CD, d{0, 7264, 0}}, + {0x13A0, 0x13EF, d{0, 38864, 0}}, + {0x13F0, 0x13F5, d{0, 8, 0}}, + {0x13F8, 0x13FD, d{-8, 0, -8}}, {0x1D79, 0x1D79, d{35332, 0, 35332}}, {0x1D7D, 0x1D7D, d{3814, 0, 3814}}, {0x1E00, 0x1E95, d{UpperLower, UpperLower, UpperLower}}, @@ -6399,10 +6561,17 @@ var _CaseRanges = []CaseRange{ {0xA7AD, 0xA7AD, d{0, -42305, 0}}, {0xA7B0, 0xA7B0, d{0, -42258, 0}}, {0xA7B1, 0xA7B1, d{0, -42282, 0}}, + {0xA7B2, 0xA7B2, d{0, -42261, 0}}, + {0xA7B3, 0xA7B3, d{0, 928, 0}}, + {0xA7B4, 0xA7B7, d{UpperLower, UpperLower, UpperLower}}, + {0xAB53, 0xAB53, d{-928, 0, -928}}, + {0xAB70, 0xABBF, d{-38864, 0, -38864}}, {0xFF21, 0xFF3A, d{0, 32, 0}}, {0xFF41, 0xFF5A, d{-32, 0, -32}}, {0x10400, 0x10427, d{0, 40, 0}}, {0x10428, 0x1044F, d{-40, 0, -40}}, + {0x10C80, 0x10CB2, d{0, 64, 0}}, + {0x10CC0, 0x10CF2, d{-64, 0, -64}}, {0x118A0, 0x118BF, d{0, 32, 0}}, {0x118C0, 0x118DF, d{-32, 0, -32}}, } @@ -6832,6 +7001,7 @@ var foldLl = &RangeTable{ {0x0531, 0x0556, 1}, {0x10a0, 0x10c5, 1}, {0x10c7, 0x10cd, 6}, + {0x13a0, 0x13f5, 1}, {0x1e00, 0x1e94, 2}, {0x1e9e, 0x1efe, 2}, {0x1f08, 0x1f0f, 1}, @@ -6872,11 +7042,13 @@ var foldLl = &RangeTable{ {0xa790, 0xa792, 2}, {0xa796, 0xa7aa, 2}, {0xa7ab, 0xa7ad, 1}, - {0xa7b0, 0xa7b1, 1}, - {0xff21, 0xff3a, 1}, + {0xa7b0, 0xa7b4, 1}, + {0xa7b6, 0xff21, 22379}, + {0xff22, 0xff3a, 1}, }, R32: []Range32{ {0x10400, 0x10427, 1}, + {0x10c80, 0x10cb2, 1}, {0x118a0, 0x118bf, 1}, }, LatinOffset: 3, @@ -6942,9 +7114,10 @@ var foldLu = &RangeTable{ {0x0275, 0x027d, 8}, {0x0280, 0x0283, 3}, {0x0287, 0x028c, 1}, - {0x0292, 0x029e, 12}, - {0x0345, 0x0371, 44}, - {0x0373, 0x037b, 4}, + {0x0292, 0x029d, 11}, + {0x029e, 0x0345, 167}, + {0x0371, 0x0373, 2}, + {0x0377, 0x037b, 4}, {0x037c, 0x037d, 1}, {0x03ac, 0x03af, 1}, {0x03b1, 0x03ce, 1}, @@ -6959,6 +7132,7 @@ var foldLu = &RangeTable{ {0x04c2, 0x04ce, 2}, {0x04cf, 0x052f, 2}, {0x0561, 0x0586, 1}, + {0x13f8, 0x13fd, 1}, {0x1d79, 0x1d7d, 4}, {0x1e01, 0x1e95, 2}, {0x1e9b, 0x1ea1, 6}, @@ -6994,10 +7168,14 @@ var foldLu = &RangeTable{ {0xa78c, 0xa791, 5}, {0xa793, 0xa797, 4}, {0xa799, 0xa7a9, 2}, + {0xa7b5, 0xa7b7, 2}, + {0xab53, 0xab70, 29}, + {0xab71, 0xabbf, 1}, {0xff41, 0xff5a, 1}, }, R32: []Range32{ {0x10428, 0x1044f, 1}, + {0x10cc0, 0x10cf2, 1}, {0x118c0, 0x118df, 1}, }, LatinOffset: 4, @@ -7023,7 +7201,7 @@ var foldMn = &RangeTable{ // If there is no entry for a script name, there are no such points. var FoldScript = map[string]*RangeTable{} -// Range entries: 3532 16-bit, 1204 32-bit, 4736 total. -// Range bytes: 21192 16-bit, 14448 32-bit, 35640 total. +// Range entries: 3546 16-bit, 1306 32-bit, 4852 total. +// Range bytes: 21276 16-bit, 15672 32-bit, 36948 total. // Fold orbit bytes: 63 pairs, 252 bytes diff --git a/libgo/go/unicode/utf16/utf16.go b/libgo/go/unicode/utf16/utf16.go index c0e47c535ab..b497500778e 100644 --- a/libgo/go/unicode/utf16/utf16.go +++ b/libgo/go/unicode/utf16/utf16.go @@ -25,7 +25,7 @@ const ( surrSelf = 0x10000 ) -// IsSurrogate returns true if the specified Unicode code point +// IsSurrogate reports whether the specified Unicode code point // can appear in a surrogate pair. func IsSurrogate(r rune) bool { return surr1 <= r && r < surr3 diff --git a/libgo/merge.sh b/libgo/merge.sh index c79f7596dca..24f63d9df6b 100755 --- a/libgo/merge.sh +++ b/libgo/merge.sh @@ -8,7 +8,7 @@ # into the libgo library. This does the easy stuff; the hard stuff is # left to the user. -# The file MERGE should hold the Mercurial revision number of the last +# The file MERGE should hold the Git revision number of the last # revision which was merged into these sources. Given that, and given # the current sources, we can run the usual diff3 algorithm to merge # all changes into our sources. @@ -30,7 +30,7 @@ case $# in 1) ;; 2) rev=$2 ;; *) - echo 1>&2 "merge.sh: Usage: merge.sh mercurial-repository [revision]" + echo 1>&2 "merge.sh: Usage: merge.sh git-repository [revision]" exit 1 ;; esac @@ -66,7 +66,7 @@ merge() { else echo "merge.sh: ${name}: REMOVED" rm -f ${libgo} - hg rm ${libgo} + git rm ${libgo} fi elif test -f ${old}; then # The file exists in the old version. @@ -97,7 +97,6 @@ merge() { 1) echo "merge.sh: $name: CONFLICTS" mv ${libgo}.tmp ${libgo} - hg resolve -u ${libgo} ;; *) echo 1>&2 "merge.sh: $name: diff3 failure" @@ -118,7 +117,7 @@ merge() { mkdir -p ${dir} fi cp ${new} ${libgo} - hg add ${libgo} + git add ${libgo} fi fi } @@ -174,35 +173,6 @@ done done done -cmdlist="cgo go gofmt" -for c in $cmdlist; do - (cd ${NEWDIR}/src/cmd/$c && find . -name '*.go' -print) | while read f; do - oldfile=${OLDDIR}/src/cmd/$c/$f - newfile=${NEWDIR}/src/cmd/$c/$f - libgofile=go/cmd/$c/$f - merge $f ${oldfile} ${newfile} ${libgofile} - done - - (cd ${NEWDIR}/src/cmd/$c && find . -name testdata -print) | while read d; do - oldtd=${OLDDIR}/src/cmd/$c/$d - newtd=${NEWDIR}/src/cmd/$c/$d - libgotd=go/cmd/$c/$d - if ! test -d ${oldtd}; then - continue - fi - (cd ${oldtd} && git ls-files .) | while read f; do - if test "`basename $f`" = ".gitignore"; then - continue - fi - name=$d/$f - oldfile=${oldtd}/$f - newfile=${newtd}/$f - libgofile=${libgotd}/$f - merge ${name} ${oldfile} ${newfile} ${libgofile} - done - done -done - runtime="chan.goc chan.h cpuprof.goc env_posix.c heapdump.c lock_futex.c lfstack.goc lock_sema.c mcache.c mcentral.c mfixalloc.c mgc0.c mgc0.h mheap.c msize.c netpoll.goc netpoll_epoll.c netpoll_kqueue.c netpoll_stub.c panic.c print.c proc.c race.h rdebug.goc runtime.c runtime.h signal_unix.c signal_unix.h malloc.h malloc.goc mprof.goc parfor.c runtime1.goc sema.goc sigqueue.goc string.goc time.goc" for f in $runtime; do # merge_c $f $f @@ -224,7 +194,7 @@ done fi echo "merge.sh: ${libgofile}: REMOVED" rm -f ${libgofile} - hg rm ${libgofile} + git rm ${libgofile} done (echo ${new_rev}; sed -ne '2,$p' MERGE) > MERGE.tmp diff --git a/libgo/mksysinfo.sh b/libgo/mksysinfo.sh index 3d37d21cbd6..407c12c43bc 100755 --- a/libgo/mksysinfo.sh +++ b/libgo/mksysinfo.sh @@ -875,11 +875,13 @@ grep '^type _addrinfo ' gen-sysinfo.go | \ -e 's/ ai_/ Ai_/g' \ >> ${OUT} -# The addrinfo flags and errors. +# The addrinfo and nameinfo flags and errors. grep '^const _AI_' gen-sysinfo.go | \ sed -e 's/^\(const \)_\(AI_[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT} grep '^const _EAI_' gen-sysinfo.go | \ sed -e 's/^\(const \)_\(EAI_[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT} +grep '^const _NI_' gen-sysinfo.go | \ + sed -e 's/^\(const \)_\(NI_[^= ]*\)\(.*\)$/\1\2 = _\2/' >> ${OUT} # The passwd struct. grep '^type _passwd ' gen-sysinfo.go | \ diff --git a/libgo/runtime/env_posix.c b/libgo/runtime/env_posix.c index ee3e4514554..b93edd65a6b 100644 --- a/libgo/runtime/env_posix.c +++ b/libgo/runtime/env_posix.c @@ -11,7 +11,7 @@ extern Slice envs; -const byte* +String runtime_getenv(const char *s) { int32 i, j; @@ -19,6 +19,7 @@ runtime_getenv(const char *s) const byte *v, *bs; String* envv; int32 envc; + String ret; bs = (const byte*)s; len = runtime_findnull(bs); @@ -33,8 +34,12 @@ runtime_getenv(const char *s) goto nomatch; if(v[len] != '=') goto nomatch; - return v+len+1; + ret.str = v+len+1; + ret.len = envv[i].len-len-1; + return ret; nomatch:; } - return nil; + ret.str = nil; + ret.len = 0; + return ret; } diff --git a/libgo/runtime/go-varargs.c b/libgo/runtime/go-varargs.c index 7a2006fbab2..534c0db94fa 100644 --- a/libgo/runtime/go-varargs.c +++ b/libgo/runtime/go-varargs.c @@ -10,6 +10,7 @@ #include #include #include +#include /* The syscall package calls C functions. The Go compiler can not represent a C varargs functions. On some systems it's important @@ -56,6 +57,18 @@ __go_fcntl_uintptr (uintptr_t fd, uintptr_t cmd, uintptr_t arg) return ret; } +int +__go_ioctl (int d, int request, int arg) +{ + return ioctl (d, request, arg); +} + +int +__go_ioctl_ptr (int d, int request, void *arg) +{ + return ioctl (d, request, arg); +} + #ifdef HAVE_OPEN64 int diff --git a/libgo/runtime/malloc.h b/libgo/runtime/malloc.h index 86b9fccf904..065f74a9b58 100644 --- a/libgo/runtime/malloc.h +++ b/libgo/runtime/malloc.h @@ -263,7 +263,9 @@ struct MStats uint64 last_gc; // last GC (in absolute time) uint64 pause_total_ns; uint64 pause_ns[256]; + uint64 pause_end[256]; uint32 numgc; + float64 gc_cpu_fraction; bool enablegc; bool debuggc; diff --git a/libgo/runtime/mgc0.c b/libgo/runtime/mgc0.c index 9d8c025e7c2..d7d0b27ba9c 100644 --- a/libgo/runtime/mgc0.c +++ b/libgo/runtime/mgc0.c @@ -1368,6 +1368,8 @@ markroot(ParFor *desc, uint32 i) scanblock(wbuf, false); } +static const FuncVal markroot_funcval = { (void *) markroot }; + // Get an empty work buffer off the work.empty list, // allocating new buffers as needed. static Workbuf* @@ -2102,14 +2104,16 @@ static void mgc(G *gp); static int32 readgogc(void) { + String s; const byte *p; - p = runtime_getenv("GOGC"); - if(p == nil || p[0] == '\0') + s = runtime_getenv("GOGC"); + if(s.len == 0) return 100; - if(runtime_strcmp((const char *)p, "off") == 0) + p = s.str; + if(s.len == 3 && runtime_strcmp((const char *)p, "off") == 0) return -1; - return runtime_atoi(p); + return runtime_atoi(p, s.len); } // force = 1 - do GC regardless of current heap usage @@ -2252,7 +2256,7 @@ gc(struct gc_args *args) work.nwait = 0; work.ndone = 0; work.nproc = runtime_gcprocs(); - runtime_parforsetup(work.markfor, work.nproc, RootCount + runtime_allglen, nil, false, markroot); + runtime_parforsetup(work.markfor, work.nproc, RootCount + runtime_allglen, false, &markroot_funcval); if(work.nproc > 1) { runtime_noteclear(&work.alldone); runtime_helpgc(work.nproc); @@ -2285,6 +2289,7 @@ gc(struct gc_args *args) t4 = runtime_nanotime(); mstats.last_gc = runtime_unixnanotime(); // must be Unix time to make sense to user mstats.pause_ns[mstats.numgc%nelem(mstats.pause_ns)] = t4 - t0; + mstats.pause_end[mstats.numgc%nelem(mstats.pause_end)] = mstats.last_gc; mstats.pause_total_ns += t4 - t0; mstats.numgc++; if(mstats.debuggc) @@ -2749,3 +2754,38 @@ runtime_MHeap_MapBits(MHeap *h) runtime_SysMap(h->arena_start - n, n - h->bitmap_mapped, h->arena_reserved, &mstats.gc_sys); h->bitmap_mapped = n; } + +// typedmemmove copies a value of type t to dst from src. + +extern void typedmemmove(const Type* td, void *dst, const void *src) + __asm__ (GOSYM_PREFIX "reflect.typedmemmove"); + +void +typedmemmove(const Type* td, void *dst, const void *src) +{ + runtime_memmove(dst, src, td->__size); +} + +// typedslicecopy copies a slice of elemType values from src to dst, +// returning the number of elements copied. + +extern intgo typedslicecopy(const Type* elem, Slice dst, Slice src) + __asm__ (GOSYM_PREFIX "reflect.typedslicecopy"); + +intgo +typedslicecopy(const Type* elem, Slice dst, Slice src) +{ + intgo n; + void *dstp; + void *srcp; + + n = dst.__count; + if (n > src.__count) + n = src.__count; + if (n == 0) + return 0; + dstp = dst.__values; + srcp = src.__values; + memmove(dstp, srcp, (uintptr_t)n * elem->__size); + return n; +} diff --git a/libgo/runtime/parfor.c b/libgo/runtime/parfor.c index 386faea512c..ede921b9aaa 100644 --- a/libgo/runtime/parfor.c +++ b/libgo/runtime/parfor.c @@ -34,7 +34,7 @@ runtime_parforalloc(uint32 nthrmax) } void -runtime_parforsetup(ParFor *desc, uint32 nthr, uint32 n, void *ctx, bool wait, void (*body)(ParFor*, uint32)) +runtime_parforsetup(ParFor *desc, uint32 nthr, uint32 n, bool wait, const FuncVal *body) { uint32 i, begin, end; uint64 *pos; @@ -49,7 +49,6 @@ runtime_parforsetup(ParFor *desc, uint32 nthr, uint32 n, void *ctx, bool wait, v desc->nthr = nthr; desc->thrseq = 0; desc->cnt = n; - desc->ctx = ctx; desc->wait = wait; desc->nsteal = 0; desc->nstealcnt = 0; @@ -72,7 +71,8 @@ runtime_parfordo(ParFor *desc) ParForThread *me; uint32 tid, begin, end, begin2, try, victim, i; uint64 *mypos, *victimpos, pos, newpos; - void (*body)(ParFor*, uint32); + const FuncVal *body; + void (*bodyfn)(ParFor*, uint32); bool idle; // Obtain 0-based thread index. @@ -82,14 +82,16 @@ runtime_parfordo(ParFor *desc) runtime_throw("parfor: invalid tid"); } + body = desc->body; + bodyfn = (void (*)(ParFor*, uint32))(void*)body->fn; + // If single-threaded, just execute the for serially. if(desc->nthr==1) { for(i=0; icnt; i++) - desc->body(desc, i); + __builtin_call_with_static_chain (bodyfn(desc, i), body); return; } - body = desc->body; me = &desc->thr[tid]; mypos = &me->pos; for(;;) { @@ -100,7 +102,7 @@ runtime_parfordo(ParFor *desc) begin = (uint32)pos-1; end = (uint32)(pos>>32); if(begin < end) { - body(desc, begin); + __builtin_call_with_static_chain(bodyfn(desc, begin), body); continue; } break; diff --git a/libgo/runtime/proc.c b/libgo/runtime/proc.c index 8f82f5b9cc4..b5741c54cc9 100644 --- a/libgo/runtime/proc.c +++ b/libgo/runtime/proc.c @@ -443,6 +443,7 @@ void runtime_schedinit(void) { int32 n, procs; + String s; const byte *p; Eface i; @@ -477,8 +478,9 @@ runtime_schedinit(void) runtime_sched.lastpoll = runtime_nanotime(); procs = 1; - p = runtime_getenv("GOMAXPROCS"); - if(p != nil && (n = runtime_atoi(p)) > 0) { + s = runtime_getenv("GOMAXPROCS"); + p = s.str; + if(p != nil && (n = runtime_atoi(p, s.len)) > 0) { if(n > MaxGomaxprocs) n = MaxGomaxprocs; procs = n; @@ -2268,19 +2270,19 @@ runtime_malg(int32 stacksize, byte** ret_stack, size_t* ret_stacksize) // are available sequentially after &fn; they would not be // copied if a stack split occurred. It's OK for this to call // functions that split the stack. -void runtime_testing_entersyscall(void) +void runtime_testing_entersyscall(int32) __asm__ (GOSYM_PREFIX "runtime.entersyscall"); void -runtime_testing_entersyscall() +runtime_testing_entersyscall(int32 dummy __attribute__ ((unused))) { runtime_entersyscall(); } -void runtime_testing_exitsyscall(void) +void runtime_testing_exitsyscall(int32) __asm__ (GOSYM_PREFIX "runtime.exitsyscall"); void -runtime_testing_exitsyscall() +runtime_testing_exitsyscall(int32 dummy __attribute__ ((unused))) { runtime_exitsyscall(); } @@ -3429,3 +3431,54 @@ runtime_gcwaiting(void) { return runtime_sched.gcwaiting; } + +// os_beforeExit is called from os.Exit(0). +//go:linkname os_beforeExit os.runtime_beforeExit + +extern void os_beforeExit() __asm__ (GOSYM_PREFIX "os.runtime_beforeExit"); + +void +os_beforeExit() +{ +} + +// Active spinning for sync.Mutex. +//go:linkname sync_runtime_canSpin sync.runtime_canSpin + +enum +{ + ACTIVE_SPIN = 4, + ACTIVE_SPIN_CNT = 30, +}; + +extern _Bool sync_runtime_canSpin(intgo i) + __asm__ (GOSYM_PREFIX "sync.runtime_canSpin"); + +_Bool +sync_runtime_canSpin(intgo i) +{ + P *p; + + // sync.Mutex is cooperative, so we are conservative with spinning. + // Spin only few times and only if running on a multicore machine and + // GOMAXPROCS>1 and there is at least one other running P and local runq is empty. + // As opposed to runtime mutex we don't do passive spinning here, + // because there can be work on global runq on on other Ps. + if (i >= ACTIVE_SPIN || runtime_ncpu <= 1 || runtime_gomaxprocs <= (int32)(runtime_sched.npidle+runtime_sched.nmspinning)+1) { + return false; + } + p = m->p; + return p != nil && p->runqhead == p->runqtail; +} + +//go:linkname sync_runtime_doSpin sync.runtime_doSpin +//go:nosplit + +extern void sync_runtime_doSpin(void) + __asm__ (GOSYM_PREFIX "sync.runtime_doSpin"); + +void +sync_runtime_doSpin() +{ + runtime_procyield(ACTIVE_SPIN_CNT); +} diff --git a/libgo/runtime/runtime.c b/libgo/runtime/runtime.c index e3320356c47..be7ccbd6135 100644 --- a/libgo/runtime/runtime.c +++ b/libgo/runtime/runtime.c @@ -35,6 +35,7 @@ extern volatile intgo runtime_MemProfileRate int32 runtime_gotraceback(bool *crash) { + String s; const byte *p; uint32 x; @@ -44,15 +45,14 @@ runtime_gotraceback(bool *crash) return runtime_m()->traceback; x = runtime_atomicload(&traceback_cache); if(x == ~(uint32)0) { - p = runtime_getenv("GOTRACEBACK"); - if(p == nil) - p = (const byte*)""; - if(p[0] == '\0') + s = runtime_getenv("GOTRACEBACK"); + p = s.str; + if(s.len == 0) x = 1<<1; - else if(runtime_strcmp((const char *)p, "crash") == 0) + else if(s.len == 5 && runtime_strcmp((const char *)p, "crash") == 0) x = (2<<1) | 1; else - x = runtime_atoi(p)<<1; + x = runtime_atoi(p, s.len)<<1; runtime_atomicstore(&traceback_cache, x); } if(crash != nil) @@ -136,13 +136,15 @@ os_runtime_args() } int32 -runtime_atoi(const byte *p) +runtime_atoi(const byte *p, intgo len) { int32 n; n = 0; - while('0' <= *p && *p <= '9') + while(len > 0 && '0' <= *p && *p <= '9') { n = n*10 + *p++ - '0'; + len--; + } return n; } @@ -339,7 +341,9 @@ static struct { void runtime_parsedebugvars(void) { - const byte *p; + String s; + const byte *p, *pn; + intgo len; intgo i, n; bool tmp; @@ -352,24 +356,27 @@ runtime_parsedebugvars(void) traceback_cache = ~(uint32)0; runtime_gotraceback(&tmp); - p = runtime_getenv("GODEBUG"); - if(p == nil) + s = runtime_getenv("GODEBUG"); + if(s.len == 0) return; + p = s.str; + len = s.len; for(;;) { for(i=0; i<(intgo)nelem(dbgvar); i++) { n = runtime_findnull((const byte*)dbgvar[i].name); - if(runtime_mcmp(p, "memprofilerate", n) == 0 && p[n] == '=') + if(len > n && runtime_mcmp(p, "memprofilerate", n) == 0 && p[n] == '=') // Set the MemProfileRate directly since it // is an int, not int32, and should only lbe // set here if specified by GODEBUG - runtime_MemProfileRate = runtime_atoi(p+n+1); - else if(runtime_mcmp(p, dbgvar[i].name, n) == 0 && p[n] == '=') - *dbgvar[i].value = runtime_atoi(p+n+1); + runtime_MemProfileRate = runtime_atoi(p+n+1, len-(n+1)); + else if(len > n && runtime_mcmp(p, dbgvar[i].name, n) == 0 && p[n] == '=') + *dbgvar[i].value = runtime_atoi(p+n+1, len-(n+1)); } - p = (const byte *)runtime_strstr((const char *)p, ","); - if(p == nil) + pn = (const byte *)runtime_strstr((const char *)p, ","); + if(pn == nil || pn - p >= len) break; - p++; + len -= (pn - p) - 1; + p = pn + 1; } } diff --git a/libgo/runtime/runtime.h b/libgo/runtime/runtime.h index b9264236227..cbf1fe160b9 100644 --- a/libgo/runtime/runtime.h +++ b/libgo/runtime/runtime.h @@ -421,17 +421,15 @@ struct LFNode // Parallel for descriptor. struct ParFor { - void (*body)(ParFor*, uint32); // executed for each element + const FuncVal *body; // executed for each element uint32 done; // number of idle threads uint32 nthr; // total number of threads uint32 nthrmax; // maximum number of threads uint32 thrseq; // thread id sequencer uint32 cnt; // iteration space [0, cnt) - void *ctx; // arbitrary user context bool wait; // if true, wait while all threads finish processing, // otherwise parfor may return while other threads are still working ParForThread *thr; // array of thread descriptors - uint32 pad; // to align ParForThread.pos for 64-bit atomic operations // stats uint64 nsteal; uint64 nstealcnt; @@ -544,6 +542,7 @@ void runtime_schedinit(void); void runtime_initsig(void); void runtime_sigenable(uint32 sig); void runtime_sigdisable(uint32 sig); +void runtime_sigignore(uint32 sig); int32 runtime_gotraceback(bool *crash); void runtime_goroutineheader(G*); void runtime_printtrace(Location*, int32, bool); @@ -552,8 +551,8 @@ void runtime_printtrace(Location*, int32, bool); #define runtime_write(d, v, n) write((d), (v), (n)) #define runtime_close(d) close(d) void runtime_ready(G*); -const byte* runtime_getenv(const char*); -int32 runtime_atoi(const byte*); +String runtime_getenv(const char*); +int32 runtime_atoi(const byte*, intgo); void* runtime_mstart(void*); G* runtime_malg(int32, byte**, size_t*); void runtime_mpreinit(M*); @@ -713,12 +712,11 @@ LFNode* runtime_lfstackpop(uint64 *head); * Parallel for over [0, n). * body() is executed for each iteration. * nthr - total number of worker threads. - * ctx - arbitrary user context. * if wait=true, threads return from parfor() when all work is done; * otherwise, threads can return while other threads are still finishing processing. */ ParFor* runtime_parforalloc(uint32 nthrmax); -void runtime_parforsetup(ParFor *desc, uint32 nthr, uint32 n, void *ctx, bool wait, void (*body)(ParFor*, uint32)); +void runtime_parforsetup(ParFor *desc, uint32 nthr, uint32 n, bool wait, const FuncVal *body); void runtime_parfordo(ParFor *desc); void runtime_parforiters(ParFor*, uintptr, uintptr*, uintptr*); diff --git a/libgo/runtime/runtime1.goc b/libgo/runtime/runtime1.goc index 6d8f09a6c5f..cd9d3017b51 100644 --- a/libgo/runtime/runtime1.goc +++ b/libgo/runtime/runtime1.goc @@ -27,8 +27,8 @@ func newParFor(nthrmax uint32) (desc *ParFor) { desc = runtime_parforalloc(nthrmax); } -func parForSetup(desc *ParFor, nthr uint32, n uint32, ctx *byte, wait bool, body *byte) { - runtime_parforsetup(desc, nthr, n, ctx, wait, *(void(**)(ParFor*, uint32))body); +func parForSetup(desc *ParFor, nthr uint32, n uint32, wait bool, body *byte) { + runtime_parforsetup(desc, nthr, n, wait, (const FuncVal*) body); } func parForDo(desc *ParFor) { @@ -52,10 +52,7 @@ func NumGoroutine() (ret int) { } func getgoroot() (out String) { - const byte *p; - - p = runtime_getenv("GOROOT"); - out = runtime_gostringnocopy(p); + out = runtime_getenv("GOROOT"); } func runtime_pprof.runtime_cyclesPerSecond() (res int64) { @@ -87,3 +84,13 @@ func sync_atomic.runtime_procPin() (p int) { func sync_atomic.runtime_procUnpin() { runtime_m()->locks--; } + +extern Slice envs; + +func envs() (s Slice) { + s = envs; +} + +func setenvs(e Slice) { + envs = e; +} diff --git a/libgo/runtime/signal_unix.c b/libgo/runtime/signal_unix.c index 66638dec56b..43be0d85771 100644 --- a/libgo/runtime/signal_unix.c +++ b/libgo/runtime/signal_unix.c @@ -92,6 +92,29 @@ runtime_sigdisable(uint32 sig) } } +void +runtime_sigignore(uint32 sig) +{ + int32 i; + SigTab *t; + + t = nil; + for(i = 0; runtime_sigtab[i].sig != -1; i++) { + if(runtime_sigtab[i].sig == (int32)sig) { + t = &runtime_sigtab[i]; + break; + } + } + + if(t == nil) + return; + + if((t->flags & SigNotify) != 0) { + t->flags &= ~SigHandling; + runtime_setsig(i, GO_SIG_IGN, true); + } +} + void runtime_resetcpuprofiler(int32 hz) { diff --git a/libgo/runtime/sigqueue.goc b/libgo/runtime/sigqueue.goc index 6769b239dc3..fba1c71e2cd 100644 --- a/libgo/runtime/sigqueue.goc +++ b/libgo/runtime/sigqueue.goc @@ -156,6 +156,14 @@ func signal_disable(s uint32) { runtime_sigdisable(s); } +// Must only be called from a single goroutine at a time. +func signal_ignore(s uint32) { + if (s >= nelem(sig.wanted)*32) + return; + sig.wanted[s/32] &= ~(1U<<(s&31)); + runtime_sigignore(s); +} + // This runs on a foreign stack, without an m or a g. No stack split. void runtime_badsignal(int sig) diff --git a/libgo/testsuite/gotest b/libgo/testsuite/gotest index 79097b86bc6..14841613afe 100755 --- a/libgo/testsuite/gotest +++ b/libgo/testsuite/gotest @@ -26,7 +26,9 @@ NM=${NM:-nm} # gofiles are the test files. pkgfiles are the source files. srcdir=. basedir=. +goarch="" gofiles="" +goos="" pkgfiles="" loop=true keep=false @@ -58,6 +60,24 @@ while $loop; do basedir=`echo $1 | sed -e 's/^--basedir=//'` shift ;; + x--goarch) + goarch=$2 + shift + shift + ;; + x--goarch=*) + goarch=`echo $1 | sed -e 's/^--goarch=//'` + shift + ;; + x--goos) + goos=$2 + shift + shift + ;; + x--goos=*) + goos=`echo $1 | sed -e 's/^--goos=//'` + shift + ;; x--pkgpath) pkgpath=$2 shift @@ -268,7 +288,96 @@ mkdir _test case "x$gofiles" in x) - gofiles=`ls *_test.go 2>/dev/null` + for f in `ls *_test.go`; do + tag1=`echo $f | sed -e 's/^.*_\([^_]*\)_test.go$/\1/'` + tag2=`echo $f | sed -e 's/^.*_\([^_]*\)_[^_]*_test.go$/\1/'` + if test x$tag1 = x$f; then + tag1= + fi + if test x$tag2 = x$f; then + tag2= + fi + + case "$tag1" in + "") ;; + $goarch) ;; + $goos) ;; + android | darwin | dragonfly | freebsd | linux | nacl | netbsd | openbsd | plan9 | solaris | windows) + tag1=nonmatchingtag + ;; + 386 | amd64 | amd64p32 | arm | armbe | arm64 | arm64be | alpha | m68k | ppc64 | ppc64le | mips | mipsle | mips64 | mips64le | mips64p32 | mips64p32le | mipso32 | mipsn32 | mipsn64 | mipso64 | ppc | s390 | s390x | sparc | sparc64) + tag1=nonmatchingtag + ;; + esac + + case "$tag2" in + "") ;; + $goarch) ;; + $goos) ;; + android | darwin | dragonfly | freebsd | linux | nacl | netbsd | openbsd | plan9 | solaris | windows) + tag2=nonmatchingtag + ;; + 386 | amd64 | amd64p32 | arm | armbe | arm64 | arm64be | alpha | m68k | ppc64 | ppc64le | mips | mipsle | mips64 | mips64le | mips64p32 | mips64p32le | mipso32 | mipsn32 | mipsn64 | mipso64 | ppc | s390 | s390x | sparc | sparc64) + tag2=nonmatchingtag + ;; + esac + + if test x$tag1 != xnonmatchingtag -a x$tag2 != xnonmatchingtag; then + taglines=`sed '/^package /q' < $f | fgrep '// +build '` + if test "$taglines" = ""; then + omatch=true + else + omatch=false + fi + for tags in $taglines; do + match=false + for tag in $tags; do + reverse=false + case $tag in + "!"*) + reverse=true + tag=`echo $tag | sed -e 's/^!//'` + ;; + esac + + case $tag in + "//" | "+build") + ;; + $goos | $goarch | cgo) + match=true + ;; + *,*) + match=true + for ctag in `echo $tag | sed -e 's/,/ /g'`; do + case $ctag in + $goos | $goarch | cgo) + ;; + *) + match=false + ;; + esac + done + ;; + esac + + if test "$reverse" = true; then + if test "$match" = true; then + match=false + else + match=true + fi + fi + done + if test "$match" = "true"; then + omatch=true + fi + done + + if test "$omatch" = "true"; then + gofiles="$gofiles $f" + fi + fi + done ;; *) xgofiles=$gofiles